s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / vfs_glusterfs.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Wrap GlusterFS GFAPI calls in vfs functions.
5
6    Copyright (c) 2013 Anand Avati <avati@redhat.com>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /**
23  * @file   vfs_glusterfs.c
24  * @author Anand Avati <avati@redhat.com>
25  * @date   May 2013
26  * @brief  Samba VFS module for glusterfs
27  *
28  * @todo
29  *   - sendfile/recvfile support
30  *
31  * A Samba VFS module for GlusterFS, based on Gluster's libgfapi.
32  * This is a "bottom" vfs module (not something to be stacked on top of
33  * another module), and translates (most) calls to the closest actions
34  * available in libgfapi.
35  *
36  */
37
38 #include "includes.h"
39 #include "smbd/smbd.h"
40 #include <stdio.h>
41 #include <glusterfs/api/glfs.h>
42 #include "lib/util/dlinklist.h"
43 #include "lib/util/tevent_unix.h"
44 #include "lib/util/util_file.h"
45 #include "smbd/globals.h"
46 #include "lib/util/sys_rw.h"
47 #include "smbprofile.h"
48 #include "modules/posixacl_xattr.h"
49 #include "lib/pthreadpool/pthreadpool_tevent.h"
50
51 #define DEFAULT_VOLFILE_SERVER "localhost"
52 #define GLUSTER_NAME_MAX 255
53
54 /**
55  * Helper to convert struct stat to struct stat_ex.
56  */
57 static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
58 {
59         ZERO_STRUCTP(dst);
60
61         dst->st_ex_dev = src->st_dev;
62         dst->st_ex_ino = src->st_ino;
63         dst->st_ex_mode = src->st_mode;
64         dst->st_ex_nlink = src->st_nlink;
65         dst->st_ex_uid = src->st_uid;
66         dst->st_ex_gid = src->st_gid;
67         dst->st_ex_rdev = src->st_rdev;
68         dst->st_ex_size = src->st_size;
69         dst->st_ex_atime.tv_sec = src->st_atime;
70         dst->st_ex_mtime.tv_sec = src->st_mtime;
71         dst->st_ex_ctime.tv_sec = src->st_ctime;
72         dst->st_ex_btime.tv_sec = src->st_mtime;
73         dst->st_ex_blksize = src->st_blksize;
74         dst->st_ex_blocks = src->st_blocks;
75 #ifdef STAT_HAVE_NSEC
76         dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
77         dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
78         dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
79         dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
80 #endif
81 }
82
83 /* pre-opened glfs_t */
84
85 static struct glfs_preopened {
86         char *volume;
87         char *connectpath;
88         glfs_t *fs;
89         int ref;
90         struct glfs_preopened *next, *prev;
91 } *glfs_preopened;
92
93
94 static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
95 {
96         struct glfs_preopened *entry = NULL;
97
98         entry = talloc_zero(NULL, struct glfs_preopened);
99         if (!entry) {
100                 errno = ENOMEM;
101                 return -1;
102         }
103
104         entry->volume = talloc_strdup(entry, volume);
105         if (!entry->volume) {
106                 talloc_free(entry);
107                 errno = ENOMEM;
108                 return -1;
109         }
110
111         entry->connectpath = talloc_strdup(entry, connectpath);
112         if (entry->connectpath == NULL) {
113                 talloc_free(entry);
114                 errno = ENOMEM;
115                 return -1;
116         }
117
118         entry->fs = fs;
119         entry->ref = 1;
120
121         DLIST_ADD(glfs_preopened, entry);
122
123         return 0;
124 }
125
126 static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
127 {
128         struct glfs_preopened *entry = NULL;
129
130         for (entry = glfs_preopened; entry; entry = entry->next) {
131                 if (strcmp(entry->volume, volume) == 0 &&
132                     strcmp(entry->connectpath, connectpath) == 0)
133                 {
134                         entry->ref++;
135                         return entry->fs;
136                 }
137         }
138
139         return NULL;
140 }
141
142 static void glfs_clear_preopened(glfs_t *fs)
143 {
144         struct glfs_preopened *entry = NULL;
145
146         for (entry = glfs_preopened; entry; entry = entry->next) {
147                 if (entry->fs == fs) {
148                         if (--entry->ref)
149                                 return;
150
151                         DLIST_REMOVE(glfs_preopened, entry);
152
153                         glfs_fini(entry->fs);
154                         talloc_free(entry);
155                         break;
156                 }
157         }
158 }
159
160 static int vfs_gluster_set_volfile_servers(glfs_t *fs,
161                                            const char *volfile_servers)
162 {
163         char *server = NULL;
164         size_t server_count = 0;
165         size_t server_success = 0;
166         int   ret = -1;
167         TALLOC_CTX *frame = talloc_stackframe();
168
169         DBG_INFO("servers list %s\n", volfile_servers);
170
171         while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
172                 char *transport = NULL;
173                 char *host = NULL;
174                 int   port = 0;
175
176                 server_count++;
177                 DBG_INFO("server %zu %s\n", server_count, server);
178
179                 /* Determine the transport type */
180                 if (strncmp(server, "unix+", 5) == 0) {
181                         port = 0;
182                         transport = talloc_strdup(frame, "unix");
183                         if (!transport) {
184                                 errno = ENOMEM;
185                                 goto out;
186                         }
187                         host = talloc_strdup(frame, server + 5);
188                         if (!host) {
189                                 errno = ENOMEM;
190                                 goto out;
191                         }
192                 } else {
193                         char *p = NULL;
194                         char *port_index = NULL;
195
196                         if (strncmp(server, "tcp+", 4) == 0) {
197                                 server += 4;
198                         }
199
200                         /* IPv6 is enclosed in []
201                          * ':' before ']' is part of IPv6
202                          * ':' after  ']' indicates port
203                          */
204                         p = server;
205                         if (server[0] == '[') {
206                                 server++;
207                                 p = index(server, ']');
208                                 if (p == NULL) {
209                                         /* Malformed IPv6 */
210                                         continue;
211                                 }
212                                 p[0] = '\0';
213                                 p++;
214                         }
215
216                         port_index = index(p, ':');
217
218                         if (port_index == NULL) {
219                                 port = 0;
220                         } else {
221                                 port = atoi(port_index + 1);
222                                 port_index[0] = '\0';
223                         }
224                         transport = talloc_strdup(frame, "tcp");
225                         if (!transport) {
226                                 errno = ENOMEM;
227                                 goto out;
228                         }
229                         host = talloc_strdup(frame, server);
230                         if (!host) {
231                                 errno = ENOMEM;
232                                 goto out;
233                         }
234                 }
235
236                 DBG_INFO("Calling set volfile server with params "
237                          "transport=%s, host=%s, port=%d\n", transport,
238                           host, port);
239
240                 ret = glfs_set_volfile_server(fs, transport, host, port);
241                 if (ret < 0) {
242                         DBG_WARNING("Failed to set volfile_server "
243                                     "transport=%s, host=%s, port=%d (%s)\n",
244                                     transport, host, port, strerror(errno));
245                 } else {
246                         server_success++;
247                 }
248         }
249
250 out:
251         if (server_count == 0) {
252                 ret = -1;
253         } else if (server_success < server_count) {
254                 DBG_WARNING("Failed to set %zu out of %zu servers parsed\n",
255                             server_count - server_success, server_count);
256                 ret = 0;
257         }
258
259         TALLOC_FREE(frame);
260         return ret;
261 }
262
263 /* Disk Operations */
264
265 static int check_for_write_behind_translator(TALLOC_CTX *mem_ctx,
266                                              glfs_t *fs,
267                                              const char *volume)
268 {
269         char *buf = NULL;
270         char **lines = NULL;
271         int numlines = 0;
272         int i;
273         char *option;
274         bool write_behind_present = false;
275         size_t newlen;
276         int ret;
277
278         ret = glfs_get_volfile(fs, NULL, 0);
279         if (ret == 0) {
280                 DBG_ERR("%s: Failed to get volfile for "
281                         "volume (%s): No volfile\n",
282                         volume,
283                         strerror(errno));
284                 return -1;
285         }
286         if (ret > 0) {
287                 DBG_ERR("%s: Invalid return %d for glfs_get_volfile for "
288                         "volume (%s): No volfile\n",
289                         volume,
290                         ret,
291                         strerror(errno));
292                 return -1;
293         }
294
295         newlen = 0 - ret;
296
297         buf = talloc_zero_array(mem_ctx, char, newlen);
298         if (buf == NULL) {
299                 return -1;
300         }
301
302         ret = glfs_get_volfile(fs, buf, newlen);
303         if (ret != newlen) {
304                 TALLOC_FREE(buf);
305                 DBG_ERR("%s: Failed to get volfile for volume (%s)\n",
306                         volume, strerror(errno));
307                 return -1;
308         }
309
310         option = talloc_asprintf(mem_ctx, "volume %s-write-behind", volume);
311         if (option == NULL) {
312                 TALLOC_FREE(buf);
313                 return -1;
314         }
315
316         /*
317          * file_lines_parse() plays horrible tricks with
318          * the passed-in talloc pointers and the hierarchy
319          * which makes freeing hard to get right.
320          *
321          * As we know mem_ctx is freed by the caller, after
322          * this point don't free on exit and let the caller
323          * handle it. This violates good Samba coding practice
324          * but we know we're not leaking here.
325          */
326
327         lines = file_lines_parse(buf,
328                                 newlen,
329                                 &numlines,
330                                 mem_ctx);
331         if (lines == NULL || numlines <= 0) {
332                 return -1;
333         }
334         /* On success, buf is now a talloc child of lines !! */
335
336         for (i=0; i < numlines; i++) {
337                 if (strequal(lines[i], option)) {
338                         write_behind_present = true;
339                         break;
340                 }
341         }
342
343         if (write_behind_present) {
344                 DBG_ERR("Write behind translator is enabled for "
345                         "volume (%s), refusing to connect! "
346                         "Please turn off the write behind translator by calling "
347                         "'gluster volume set %s performance.write-behind off' "
348                         "on the commandline. "
349                         "Check the vfs_glusterfs(8) manpage for "
350                         "further details.\n",
351                         volume, volume);
352                 return -1;
353         }
354
355         return 0;
356 }
357
358 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
359                                const char *service,
360                                const char *user)
361 {
362         const struct loadparm_substitution *lp_sub =
363                 loadparm_s3_global_substitution();
364         const char *volfile_servers;
365         const char *volume;
366         char *logfile;
367         int loglevel;
368         glfs_t *fs = NULL;
369         TALLOC_CTX *tmp_ctx;
370         int ret = 0;
371         bool write_behind_pass_through_set = false;
372
373         tmp_ctx = talloc_new(NULL);
374         if (tmp_ctx == NULL) {
375                 ret = -1;
376                 goto done;
377         }
378         logfile = lp_parm_substituted_string(tmp_ctx,
379                                              lp_sub,
380                                              SNUM(handle->conn),
381                                              "glusterfs",
382                                              "logfile",
383                                              NULL);
384
385         loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
386
387         volfile_servers = lp_parm_substituted_string(tmp_ctx,
388                                                      lp_sub,
389                                                      SNUM(handle->conn),
390                                                      "glusterfs",
391                                                      "volfile_server",
392                                                      NULL);
393         if (volfile_servers == NULL) {
394                 volfile_servers = DEFAULT_VOLFILE_SERVER;
395         }
396
397         volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
398                                       NULL);
399         if (volume == NULL) {
400                 volume = service;
401         }
402
403         fs = glfs_find_preopened(volume, handle->conn->connectpath);
404         if (fs) {
405                 goto done;
406         }
407
408         fs = glfs_new(volume);
409         if (fs == NULL) {
410                 ret = -1;
411                 goto done;
412         }
413
414         ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
415         if (ret < 0) {
416                 DBG_ERR("Failed to set volfile_servers from list %s\n",
417                         volfile_servers);
418                 goto done;
419         }
420
421         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
422                                      "true");
423         if (ret < 0) {
424                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
425                 goto done;
426         }
427
428         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-selinux",
429                                      "true");
430         if (ret < 0) {
431                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
432                 goto done;
433         }
434
435         ret = glfs_set_xlator_option(fs, "*-snapview-client",
436                                      "snapdir-entry-path",
437                                      handle->conn->connectpath);
438         if (ret < 0) {
439                 DEBUG(0, ("%s: Failed to set xlator option:"
440                           " snapdir-entry-path\n", volume));
441                 goto done;
442         }
443
444 #ifdef HAVE_GFAPI_VER_7_9
445         ret = glfs_set_xlator_option(fs, "*-write-behind", "pass-through",
446                                      "true");
447         if (ret < 0) {
448                 DBG_ERR("%s: Failed to set xlator option: pass-through\n",
449                         volume);
450                 goto done;
451         }
452         write_behind_pass_through_set = true;
453 #endif
454
455         ret = glfs_set_logging(fs, logfile, loglevel);
456         if (ret < 0) {
457                 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
458                           volume, logfile, loglevel));
459                 goto done;
460         }
461
462         ret = glfs_init(fs);
463         if (ret < 0) {
464                 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
465                           volume, strerror(errno)));
466                 goto done;
467         }
468
469         if (!write_behind_pass_through_set) {
470                 ret = check_for_write_behind_translator(tmp_ctx, fs, volume);
471                 if (ret < 0) {
472                         goto done;
473                 }
474         }
475
476         ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
477         if (ret < 0) {
478                 DEBUG(0, ("%s: Failed to register volume (%s)\n",
479                           volume, strerror(errno)));
480                 goto done;
481         }
482
483         /*
484          * The shadow_copy2 module will fail to export subdirectories
485          * of a gluster volume unless we specify the mount point,
486          * because the detection fails if the file system is not
487          * locally mounted:
488          * https://bugzilla.samba.org/show_bug.cgi?id=13091
489          */
490         lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
491
492         /*
493          * Unless we have an async implementation of getxattrat turn this off.
494          */
495         lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
496
497 done:
498         if (ret < 0) {
499                 if (fs)
500                         glfs_fini(fs);
501         } else {
502                 DBG_ERR("%s: Initialized volume from servers %s\n",
503                         volume, volfile_servers);
504                 handle->data = fs;
505         }
506         talloc_free(tmp_ctx);
507         return ret;
508 }
509
510 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
511 {
512         glfs_t *fs = NULL;
513
514         fs = handle->data;
515
516         glfs_clear_preopened(fs);
517 }
518
519 static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
520                                 const struct smb_filename *smb_fname,
521                                 uint64_t *bsize_p,
522                                 uint64_t *dfree_p,
523                                 uint64_t *dsize_p)
524 {
525         struct statvfs statvfs = { 0, };
526         int ret;
527
528         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
529         if (ret < 0) {
530                 return -1;
531         }
532
533         if (bsize_p != NULL) {
534                 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
535         }
536         if (dfree_p != NULL) {
537                 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
538         }
539         if (dsize_p != NULL) {
540                 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
541         }
542
543         return (uint64_t)statvfs.f_bavail;
544 }
545
546 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
547                                 const struct smb_filename *smb_fname,
548                                 enum SMB_QUOTA_TYPE qtype,
549                                 unid_t id,
550                                 SMB_DISK_QUOTA *qt)
551 {
552         errno = ENOSYS;
553         return -1;
554 }
555
556 static int
557 vfs_gluster_set_quota(struct vfs_handle_struct *handle,
558                       enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
559 {
560         errno = ENOSYS;
561         return -1;
562 }
563
564 static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
565                                 const struct smb_filename *smb_fname,
566                                 struct vfs_statvfs_struct *vfs_statvfs)
567 {
568         struct statvfs statvfs = { 0, };
569         int ret;
570
571         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
572         if (ret < 0) {
573                 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
574                           smb_fname->base_name, strerror(errno)));
575                 return -1;
576         }
577
578         ZERO_STRUCTP(vfs_statvfs);
579
580         vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
581         vfs_statvfs->BlockSize = statvfs.f_bsize;
582         vfs_statvfs->TotalBlocks = statvfs.f_blocks;
583         vfs_statvfs->BlocksAvail = statvfs.f_bfree;
584         vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
585         vfs_statvfs->TotalFileNodes = statvfs.f_files;
586         vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
587         vfs_statvfs->FsIdentifier = statvfs.f_fsid;
588         vfs_statvfs->FsCapabilities =
589             FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
590
591         return ret;
592 }
593
594 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
595                                             enum timestamp_set_resolution *p_ts_res)
596 {
597         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
598
599 #ifdef HAVE_GFAPI_VER_6
600         caps |= FILE_SUPPORTS_SPARSE_FILES;
601 #endif
602
603 #ifdef STAT_HAVE_NSEC
604         *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
605 #endif
606
607         return caps;
608 }
609
610 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
611                                          const files_struct *fsp)
612 {
613         glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
614         if (glfd == NULL) {
615                 DBG_INFO("Failed to fetch fsp extension\n");
616                 return NULL;
617         }
618         if (*glfd == NULL) {
619                 DBG_INFO("Empty glfs_fd_t pointer\n");
620                 return NULL;
621         }
622
623         return *glfd;
624 }
625
626 static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
627                                   files_struct *fsp, const char *mask,
628                                   uint32_t attributes)
629 {
630         glfs_fd_t *glfd = NULL;
631
632         glfd = glfs_opendir(handle->data, fsp->fsp_name->base_name);
633         if (glfd == NULL) {
634                 return NULL;
635         }
636
637         return (DIR *)glfd;
638 }
639
640 static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
641 {
642         int ret;
643
644         START_PROFILE(syscall_closedir);
645         ret = glfs_closedir((void *)dirp);
646         END_PROFILE(syscall_closedir);
647
648         return ret;
649 }
650
651 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
652                                           struct files_struct *dirfsp,
653                                           DIR *dirp)
654 {
655         static char direntbuf[512];
656         int ret;
657         struct dirent *dirent = 0;
658
659         START_PROFILE(syscall_readdir);
660
661         ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
662
663         if ((ret < 0) || (dirent == NULL)) {
664                 END_PROFILE(syscall_readdir);
665                 return NULL;
666         }
667
668         END_PROFILE(syscall_readdir);
669         return dirent;
670 }
671
672 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
673 {
674         START_PROFILE(syscall_rewinddir);
675         glfs_seekdir((void *)dirp, 0);
676         END_PROFILE(syscall_rewinddir);
677 }
678
679 static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
680                         struct files_struct *dirfsp,
681                         const struct smb_filename *smb_fname,
682                         mode_t mode)
683 {
684         int ret;
685
686 #ifdef HAVE_GFAPI_VER_7_11
687         glfs_fd_t *pglfd = NULL;
688
689         START_PROFILE(syscall_mkdirat);
690
691         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
692         if (pglfd == NULL) {
693                 END_PROFILE(syscall_mkdirat);
694                 DBG_ERR("Failed to fetch gluster fd\n");
695                 return -1;
696         }
697
698         ret = glfs_mkdirat(pglfd, smb_fname->base_name, mode);
699 #else
700         struct smb_filename *full_fname = NULL;
701
702         START_PROFILE(syscall_mkdirat);
703
704         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
705                                                   dirfsp,
706                                                   smb_fname);
707         if (full_fname == NULL) {
708                 END_PROFILE(syscall_mkdirat);
709                 return -1;
710         }
711
712         ret = glfs_mkdir(handle->data, full_fname->base_name, mode);
713
714         TALLOC_FREE(full_fname);
715 #endif
716
717         END_PROFILE(syscall_mkdirat);
718
719         return ret;
720 }
721
722 static int vfs_gluster_openat(struct vfs_handle_struct *handle,
723                               const struct files_struct *dirfsp,
724                               const struct smb_filename *smb_fname,
725                               files_struct *fsp,
726                               const struct vfs_open_how *how)
727 {
728         int flags = how->flags;
729         struct smb_filename *full_fname = NULL;
730         bool have_opath = false;
731         bool became_root = false;
732         glfs_fd_t *glfd = NULL;
733         glfs_fd_t *pglfd = NULL;
734         glfs_fd_t **p_tmp;
735
736         START_PROFILE(syscall_openat);
737
738         if (how->resolve != 0) {
739                 END_PROFILE(syscall_openat);
740                 errno = ENOSYS;
741                 return -1;
742         }
743
744         p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
745         if (p_tmp == NULL) {
746                 END_PROFILE(syscall_openat);
747                 errno = ENOMEM;
748                 return -1;
749         }
750
751 #ifdef O_PATH
752         have_opath = true;
753         if (fsp->fsp_flags.is_pathref) {
754                 flags |= O_PATH;
755         }
756 #endif
757
758         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
759                                                   dirfsp,
760                                                   smb_fname);
761         if (full_fname == NULL) {
762                 END_PROFILE(syscall_openat);
763                 return -1;
764         }
765
766         if (fsp->fsp_flags.is_pathref && !have_opath) {
767                 become_root();
768                 became_root = true;
769         }
770
771         if (fsp_get_pathref_fd(dirfsp) != AT_FDCWD) {
772 #ifdef HAVE_GFAPI_VER_7_11
773                 /*
774                  * Fetch Gluster fd for parent directory using dirfsp
775                  * before calling glfs_openat();
776                  */
777                 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
778                 if (pglfd == NULL) {
779                         END_PROFILE(syscall_openat);
780                         DBG_ERR("Failed to fetch gluster fd\n");
781                         return -1;
782                 }
783
784                 glfd = glfs_openat(pglfd,
785                                    smb_fname->base_name,
786                                    flags,
787                                    how->mode);
788 #else
789                 /*
790                  * Replace smb_fname with full_path constructed above.
791                  */
792                 smb_fname = full_fname;
793 #endif
794         }
795
796         if (pglfd == NULL) {
797                 /*
798                  * smb_fname can either be a full_path or the same one
799                  * as received from the caller. In the latter case we
800                  * are operating at current working directory.
801                  */
802                 if (flags & O_CREAT) {
803                         glfd = glfs_creat(handle->data,
804                                           smb_fname->base_name,
805                                           flags,
806                                           how->mode);
807                 } else {
808                         glfd = glfs_open(handle->data,
809                                          smb_fname->base_name,
810                                          flags);
811                 }
812         }
813
814         if (became_root) {
815                 unbecome_root();
816         }
817
818         TALLOC_FREE(full_fname);
819
820         fsp->fsp_flags.have_proc_fds = false;
821
822         if (glfd == NULL) {
823                 END_PROFILE(syscall_openat);
824                 /* no extension destroy_fn, so no need to save errno */
825                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
826                 return -1;
827         }
828
829         *p_tmp = glfd;
830
831         END_PROFILE(syscall_openat);
832         /* An arbitrary value for error reporting, so you know its us. */
833         return 13371337;
834 }
835
836 static int vfs_gluster_close(struct vfs_handle_struct *handle,
837                              files_struct *fsp)
838 {
839         int ret;
840         glfs_fd_t *glfd = NULL;
841
842         START_PROFILE(syscall_close);
843
844         glfd = vfs_gluster_fetch_glfd(handle, fsp);
845         if (glfd == NULL) {
846                 END_PROFILE(syscall_close);
847                 DBG_ERR("Failed to fetch gluster fd\n");
848                 return -1;
849         }
850
851         VFS_REMOVE_FSP_EXTENSION(handle, fsp);
852
853         ret = glfs_close(glfd);
854         END_PROFILE(syscall_close);
855
856         return ret;
857 }
858
859 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
860                                  files_struct *fsp, void *data, size_t n,
861                                  off_t offset)
862 {
863         ssize_t ret;
864         glfs_fd_t *glfd = NULL;
865
866         START_PROFILE_BYTES(syscall_pread, n);
867
868         glfd = vfs_gluster_fetch_glfd(handle, fsp);
869         if (glfd == NULL) {
870                 END_PROFILE_BYTES(syscall_pread);
871                 DBG_ERR("Failed to fetch gluster fd\n");
872                 return -1;
873         }
874
875 #ifdef HAVE_GFAPI_VER_7_6
876         ret = glfs_pread(glfd, data, n, offset, 0, NULL);
877 #else
878         ret = glfs_pread(glfd, data, n, offset, 0);
879 #endif
880         END_PROFILE_BYTES(syscall_pread);
881
882         return ret;
883 }
884
885 struct vfs_gluster_pread_state {
886         ssize_t ret;
887         glfs_fd_t *fd;
888         void *buf;
889         size_t count;
890         off_t offset;
891
892         struct vfs_aio_state vfs_aio_state;
893         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
894 };
895
896 static void vfs_gluster_pread_do(void *private_data);
897 static void vfs_gluster_pread_done(struct tevent_req *subreq);
898 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
899
900 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
901                                                   *handle, TALLOC_CTX *mem_ctx,
902                                                   struct tevent_context *ev,
903                                                   files_struct *fsp,
904                                                   void *data, size_t n,
905                                                   off_t offset)
906 {
907         struct vfs_gluster_pread_state *state;
908         struct tevent_req *req, *subreq;
909
910         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
911         if (glfd == NULL) {
912                 DBG_ERR("Failed to fetch gluster fd\n");
913                 return NULL;
914         }
915
916         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
917         if (req == NULL) {
918                 return NULL;
919         }
920
921         state->ret = -1;
922         state->fd = glfd;
923         state->buf = data;
924         state->count = n;
925         state->offset = offset;
926
927         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
928                                      state->profile_bytes, n);
929         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
930
931         subreq = pthreadpool_tevent_job_send(
932                 state, ev, handle->conn->sconn->pool,
933                 vfs_gluster_pread_do, state);
934         if (tevent_req_nomem(subreq, req)) {
935                 return tevent_req_post(req, ev);
936         }
937         tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
938
939         talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
940
941         return req;
942 }
943
944 static void vfs_gluster_pread_do(void *private_data)
945 {
946         struct vfs_gluster_pread_state *state = talloc_get_type_abort(
947                 private_data, struct vfs_gluster_pread_state);
948         struct timespec start_time;
949         struct timespec end_time;
950
951         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
952
953         PROFILE_TIMESTAMP(&start_time);
954
955         do {
956 #ifdef HAVE_GFAPI_VER_7_6
957                 state->ret = glfs_pread(state->fd, state->buf, state->count,
958                                         state->offset, 0, NULL);
959 #else
960                 state->ret = glfs_pread(state->fd, state->buf, state->count,
961                                         state->offset, 0);
962 #endif
963         } while ((state->ret == -1) && (errno == EINTR));
964
965         if (state->ret == -1) {
966                 state->vfs_aio_state.error = errno;
967         }
968
969         PROFILE_TIMESTAMP(&end_time);
970
971         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
972
973         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
974 }
975
976 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
977 {
978         return -1;
979 }
980
981 static void vfs_gluster_pread_done(struct tevent_req *subreq)
982 {
983         struct tevent_req *req = tevent_req_callback_data(
984                 subreq, struct tevent_req);
985         struct vfs_gluster_pread_state *state = tevent_req_data(
986                 req, struct vfs_gluster_pread_state);
987         int ret;
988
989         ret = pthreadpool_tevent_job_recv(subreq);
990         TALLOC_FREE(subreq);
991         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
992         talloc_set_destructor(state, NULL);
993         if (ret != 0) {
994                 if (ret != EAGAIN) {
995                         tevent_req_error(req, ret);
996                         return;
997                 }
998                 /*
999                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1000                  * means the lower level pthreadpool failed to create a new
1001                  * thread. Fallback to sync processing in that case to allow
1002                  * some progress for the client.
1003                  */
1004                 vfs_gluster_pread_do(state);
1005         }
1006
1007         tevent_req_done(req);
1008 }
1009
1010 static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
1011                                       struct vfs_aio_state *vfs_aio_state)
1012 {
1013         struct vfs_gluster_pread_state *state = tevent_req_data(
1014                 req, struct vfs_gluster_pread_state);
1015
1016         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1017                 return -1;
1018         }
1019
1020         *vfs_aio_state = state->vfs_aio_state;
1021         return state->ret;
1022 }
1023
1024 struct vfs_gluster_pwrite_state {
1025         ssize_t ret;
1026         glfs_fd_t *fd;
1027         const void *buf;
1028         size_t count;
1029         off_t offset;
1030
1031         struct vfs_aio_state vfs_aio_state;
1032         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1033 };
1034
1035 static void vfs_gluster_pwrite_do(void *private_data);
1036 static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
1037 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
1038
1039 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
1040                                                   *handle, TALLOC_CTX *mem_ctx,
1041                                                   struct tevent_context *ev,
1042                                                   files_struct *fsp,
1043                                                   const void *data, size_t n,
1044                                                   off_t offset)
1045 {
1046         struct tevent_req *req, *subreq;
1047         struct vfs_gluster_pwrite_state *state;
1048
1049         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1050         if (glfd == NULL) {
1051                 DBG_ERR("Failed to fetch gluster fd\n");
1052                 return NULL;
1053         }
1054
1055         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
1056         if (req == NULL) {
1057                 return NULL;
1058         }
1059
1060         state->ret = -1;
1061         state->fd = glfd;
1062         state->buf = data;
1063         state->count = n;
1064         state->offset = offset;
1065
1066         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1067                                      state->profile_bytes, n);
1068         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1069
1070         subreq = pthreadpool_tevent_job_send(
1071                 state, ev, handle->conn->sconn->pool,
1072                 vfs_gluster_pwrite_do, state);
1073         if (tevent_req_nomem(subreq, req)) {
1074                 return tevent_req_post(req, ev);
1075         }
1076         tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
1077
1078         talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
1079
1080         return req;
1081 }
1082
1083 static void vfs_gluster_pwrite_do(void *private_data)
1084 {
1085         struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
1086                 private_data, struct vfs_gluster_pwrite_state);
1087         struct timespec start_time;
1088         struct timespec end_time;
1089
1090         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1091
1092         PROFILE_TIMESTAMP(&start_time);
1093
1094         do {
1095 #ifdef HAVE_GFAPI_VER_7_6
1096                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1097                                          state->offset, 0, NULL, NULL);
1098 #else
1099                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1100                                          state->offset, 0);
1101 #endif
1102         } while ((state->ret == -1) && (errno == EINTR));
1103
1104         if (state->ret == -1) {
1105                 state->vfs_aio_state.error = errno;
1106         }
1107
1108         PROFILE_TIMESTAMP(&end_time);
1109
1110         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1111
1112         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1113 }
1114
1115 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
1116 {
1117         return -1;
1118 }
1119
1120 static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
1121 {
1122         struct tevent_req *req = tevent_req_callback_data(
1123                 subreq, struct tevent_req);
1124         struct vfs_gluster_pwrite_state *state = tevent_req_data(
1125                 req, struct vfs_gluster_pwrite_state);
1126         int ret;
1127
1128         ret = pthreadpool_tevent_job_recv(subreq);
1129         TALLOC_FREE(subreq);
1130         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1131         talloc_set_destructor(state, NULL);
1132         if (ret != 0) {
1133                 if (ret != EAGAIN) {
1134                         tevent_req_error(req, ret);
1135                         return;
1136                 }
1137                 /*
1138                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1139                  * means the lower level pthreadpool failed to create a new
1140                  * thread. Fallback to sync processing in that case to allow
1141                  * some progress for the client.
1142                  */
1143                 vfs_gluster_pwrite_do(state);
1144         }
1145
1146         tevent_req_done(req);
1147 }
1148
1149 static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
1150                                        struct vfs_aio_state *vfs_aio_state)
1151 {
1152         struct vfs_gluster_pwrite_state *state = tevent_req_data(
1153                 req, struct vfs_gluster_pwrite_state);
1154
1155         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1156                 return -1;
1157         }
1158
1159         *vfs_aio_state = state->vfs_aio_state;
1160
1161         return state->ret;
1162 }
1163
1164 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
1165                                   files_struct *fsp, const void *data,
1166                                   size_t n, off_t offset)
1167 {
1168         ssize_t ret;
1169         glfs_fd_t *glfd = NULL;
1170
1171         START_PROFILE_BYTES(syscall_pwrite, n);
1172
1173         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1174         if (glfd == NULL) {
1175                 END_PROFILE_BYTES(syscall_pwrite);
1176                 DBG_ERR("Failed to fetch gluster fd\n");
1177                 return -1;
1178         }
1179
1180 #ifdef HAVE_GFAPI_VER_7_6
1181         ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1182 #else
1183         ret = glfs_pwrite(glfd, data, n, offset, 0);
1184 #endif
1185         END_PROFILE_BYTES(syscall_pwrite);
1186
1187         return ret;
1188 }
1189
1190 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1191                                files_struct *fsp, off_t offset, int whence)
1192 {
1193         off_t ret = 0;
1194         glfs_fd_t *glfd = NULL;
1195
1196         START_PROFILE(syscall_lseek);
1197
1198         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1199         if (glfd == NULL) {
1200                 END_PROFILE(syscall_lseek);
1201                 DBG_ERR("Failed to fetch gluster fd\n");
1202                 return -1;
1203         }
1204
1205         ret = glfs_lseek(glfd, offset, whence);
1206         END_PROFILE(syscall_lseek);
1207
1208         return ret;
1209 }
1210
1211 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1212                                     files_struct *fromfsp,
1213                                     const DATA_BLOB *hdr,
1214                                     off_t offset, size_t n)
1215 {
1216         errno = ENOTSUP;
1217         return -1;
1218 }
1219
1220 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1221                                     int fromfd, files_struct *tofsp,
1222                                     off_t offset, size_t n)
1223 {
1224         errno = ENOTSUP;
1225         return -1;
1226 }
1227
1228 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1229                         files_struct *srcfsp,
1230                         const struct smb_filename *smb_fname_src,
1231                         files_struct *dstfsp,
1232                         const struct smb_filename *smb_fname_dst)
1233 {
1234         int ret;
1235
1236 #ifdef HAVE_GFAPI_VER_7_11
1237         glfs_fd_t *src_pglfd = NULL;
1238         glfs_fd_t *dst_pglfd = NULL;
1239
1240         START_PROFILE(syscall_renameat);
1241
1242         src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
1243         if (src_pglfd == NULL) {
1244                 END_PROFILE(syscall_renameat);
1245                 DBG_ERR("Failed to fetch gluster fd\n");
1246                 return -1;
1247         }
1248
1249         dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
1250         if (dst_pglfd == NULL) {
1251                 END_PROFILE(syscall_renameat);
1252                 DBG_ERR("Failed to fetch gluster fd\n");
1253                 return -1;
1254         }
1255
1256         ret = glfs_renameat(src_pglfd, smb_fname_src->base_name,
1257                             dst_pglfd, smb_fname_dst->base_name);
1258 #else
1259         struct smb_filename *full_fname_src = NULL;
1260         struct smb_filename *full_fname_dst = NULL;
1261
1262         START_PROFILE(syscall_renameat);
1263
1264         full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
1265                                                       srcfsp,
1266                                                       smb_fname_src);
1267         if (full_fname_src == NULL) {
1268                 END_PROFILE(syscall_renameat);
1269                 errno = ENOMEM;
1270                 return -1;
1271         }
1272
1273         full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
1274                                                       dstfsp,
1275                                                       smb_fname_dst);
1276         if (full_fname_dst == NULL) {
1277                 END_PROFILE(syscall_renameat);
1278                 TALLOC_FREE(full_fname_src);
1279                 errno = ENOMEM;
1280                 return -1;
1281         }
1282         ret = glfs_rename(handle->data,
1283                           full_fname_src->base_name,
1284                           full_fname_dst->base_name);
1285
1286         TALLOC_FREE(full_fname_src);
1287         TALLOC_FREE(full_fname_dst);
1288 #endif
1289
1290         END_PROFILE(syscall_renameat);
1291
1292         return ret;
1293 }
1294
1295 struct vfs_gluster_fsync_state {
1296         ssize_t ret;
1297         glfs_fd_t *fd;
1298
1299         struct vfs_aio_state vfs_aio_state;
1300         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1301 };
1302
1303 static void vfs_gluster_fsync_do(void *private_data);
1304 static void vfs_gluster_fsync_done(struct tevent_req *subreq);
1305 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
1306
1307 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1308                                                  *handle, TALLOC_CTX *mem_ctx,
1309                                                  struct tevent_context *ev,
1310                                                  files_struct *fsp)
1311 {
1312         struct tevent_req *req, *subreq;
1313         struct vfs_gluster_fsync_state *state;
1314
1315         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1316         if (glfd == NULL) {
1317                 DBG_ERR("Failed to fetch gluster fd\n");
1318                 return NULL;
1319         }
1320
1321         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
1322         if (req == NULL) {
1323                 return NULL;
1324         }
1325
1326         state->ret = -1;
1327         state->fd = glfd;
1328
1329         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1330                                      state->profile_bytes, 0);
1331         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1332
1333         subreq = pthreadpool_tevent_job_send(
1334                 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
1335         if (tevent_req_nomem(subreq, req)) {
1336                 return tevent_req_post(req, ev);
1337         }
1338         tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
1339
1340         talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
1341
1342         return req;
1343 }
1344
1345 static void vfs_gluster_fsync_do(void *private_data)
1346 {
1347         struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
1348                 private_data, struct vfs_gluster_fsync_state);
1349         struct timespec start_time;
1350         struct timespec end_time;
1351
1352         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1353
1354         PROFILE_TIMESTAMP(&start_time);
1355
1356         do {
1357 #ifdef HAVE_GFAPI_VER_7_6
1358                 state->ret = glfs_fsync(state->fd, NULL, NULL);
1359 #else
1360                 state->ret = glfs_fsync(state->fd);
1361 #endif
1362         } while ((state->ret == -1) && (errno == EINTR));
1363
1364         if (state->ret == -1) {
1365                 state->vfs_aio_state.error = errno;
1366         }
1367
1368         PROFILE_TIMESTAMP(&end_time);
1369
1370         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1371
1372         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1373 }
1374
1375 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
1376 {
1377         return -1;
1378 }
1379
1380 static void vfs_gluster_fsync_done(struct tevent_req *subreq)
1381 {
1382         struct tevent_req *req = tevent_req_callback_data(
1383                 subreq, struct tevent_req);
1384         struct vfs_gluster_fsync_state *state = tevent_req_data(
1385                 req, struct vfs_gluster_fsync_state);
1386         int ret;
1387
1388         ret = pthreadpool_tevent_job_recv(subreq);
1389         TALLOC_FREE(subreq);
1390         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1391         talloc_set_destructor(state, NULL);
1392         if (ret != 0) {
1393                 if (ret != EAGAIN) {
1394                         tevent_req_error(req, ret);
1395                         return;
1396                 }
1397                 /*
1398                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1399                  * means the lower level pthreadpool failed to create a new
1400                  * thread. Fallback to sync processing in that case to allow
1401                  * some progress for the client.
1402                  */
1403                 vfs_gluster_fsync_do(state);
1404         }
1405
1406         tevent_req_done(req);
1407 }
1408
1409 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1410                                   struct vfs_aio_state *vfs_aio_state)
1411 {
1412         struct vfs_gluster_fsync_state *state = tevent_req_data(
1413                 req, struct vfs_gluster_fsync_state);
1414
1415         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1416                 return -1;
1417         }
1418
1419         *vfs_aio_state = state->vfs_aio_state;
1420         return state->ret;
1421 }
1422
1423 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1424                             struct smb_filename *smb_fname)
1425 {
1426         struct stat st;
1427         int ret;
1428
1429         START_PROFILE(syscall_stat);
1430         ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1431         if (ret == 0) {
1432                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1433         }
1434         if (ret < 0 && errno != ENOENT) {
1435                 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1436                           smb_fname->base_name, strerror(errno)));
1437         }
1438         END_PROFILE(syscall_stat);
1439
1440         return ret;
1441 }
1442
1443 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1444                              files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1445 {
1446         struct stat st;
1447         int ret;
1448         glfs_fd_t *glfd = NULL;
1449
1450         START_PROFILE(syscall_fstat);
1451
1452         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1453         if (glfd == NULL) {
1454                 END_PROFILE(syscall_fstat);
1455                 DBG_ERR("Failed to fetch gluster fd\n");
1456                 return -1;
1457         }
1458
1459         ret = glfs_fstat(glfd, &st);
1460         if (ret == 0) {
1461                 smb_stat_ex_from_stat(sbuf, &st);
1462         }
1463         if (ret < 0) {
1464                 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1465                           fsp_get_io_fd(fsp), strerror(errno)));
1466         }
1467         END_PROFILE(syscall_fstat);
1468
1469         return ret;
1470 }
1471
1472 static int vfs_gluster_fstatat(struct vfs_handle_struct *handle,
1473                                const struct files_struct *dirfsp,
1474                                const struct smb_filename *smb_fname,
1475                                SMB_STRUCT_STAT *sbuf,
1476                                int flags)
1477 {
1478         struct stat st;
1479         int ret;
1480
1481 #ifdef HAVE_GFAPI_VER_7_11
1482         glfs_fd_t *pglfd = NULL;
1483
1484         START_PROFILE(syscall_fstatat);
1485
1486         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
1487         if (pglfd == NULL) {
1488                 END_PROFILE(syscall_fstatat);
1489                 DBG_ERR("Failed to fetch gluster fd\n");
1490                 return -1;
1491         }
1492
1493         ret = glfs_fstatat(pglfd, smb_fname->base_name, &st, flags);
1494 #else
1495         struct smb_filename *full_fname = NULL;
1496
1497         START_PROFILE(syscall_fstatat);
1498
1499         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1500                                                   dirfsp,
1501                                                   smb_fname);
1502         if (full_fname == NULL) {
1503                 END_PROFILE(syscall_fstatat);
1504                 return -1;
1505         }
1506
1507         ret = glfs_stat(handle->data, full_fname->base_name, &st);
1508
1509         TALLOC_FREE(full_fname->base_name);
1510 #endif
1511
1512         if (ret == 0) {
1513                 smb_stat_ex_from_stat(sbuf, &st);
1514         }
1515
1516         END_PROFILE(syscall_fstatat);
1517
1518         return ret;
1519 }
1520
1521 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1522                              struct smb_filename *smb_fname)
1523 {
1524         struct stat st;
1525         int ret;
1526
1527         START_PROFILE(syscall_lstat);
1528         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1529         if (ret == 0) {
1530                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1531         }
1532         if (ret < 0 && errno != ENOENT) {
1533                 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1534                           smb_fname->base_name, strerror(errno)));
1535         }
1536         END_PROFILE(syscall_lstat);
1537
1538         return ret;
1539 }
1540
1541 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1542                                            files_struct *fsp,
1543                                            const SMB_STRUCT_STAT *sbuf)
1544 {
1545         uint64_t ret;
1546
1547         START_PROFILE(syscall_get_alloc_size);
1548         ret = sbuf->st_ex_blocks * 512;
1549         END_PROFILE(syscall_get_alloc_size);
1550
1551         return ret;
1552 }
1553
1554 static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
1555                         struct files_struct *dirfsp,
1556                         const struct smb_filename *smb_fname,
1557                         int flags)
1558 {
1559         int ret;
1560
1561 #ifdef HAVE_GFAPI_VER_7_11
1562         glfs_fd_t *pglfd = NULL;
1563
1564         START_PROFILE(syscall_unlinkat);
1565
1566         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
1567         if (pglfd == NULL) {
1568                 END_PROFILE(syscall_unlinkat);
1569                 DBG_ERR("Failed to fetch gluster fd\n");
1570                 return -1;
1571         }
1572
1573         ret = glfs_unlinkat(pglfd, smb_fname->base_name, flags);
1574 #else
1575         struct smb_filename *full_fname = NULL;
1576
1577         START_PROFILE(syscall_unlinkat);
1578
1579         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1580                                                   dirfsp,
1581                                                   smb_fname);
1582         if (full_fname == NULL) {
1583                 END_PROFILE(syscall_unlinkat);
1584                 return -1;
1585         }
1586
1587         if (flags & AT_REMOVEDIR) {
1588                 ret = glfs_rmdir(handle->data, full_fname->base_name);
1589         } else {
1590                 ret = glfs_unlink(handle->data, full_fname->base_name);
1591         }
1592
1593         TALLOC_FREE(full_fname);
1594 #endif
1595
1596         END_PROFILE(syscall_unlinkat);
1597
1598         return ret;
1599 }
1600
1601 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1602                               files_struct *fsp, mode_t mode)
1603 {
1604         int ret;
1605         glfs_fd_t *glfd = NULL;
1606
1607         START_PROFILE(syscall_fchmod);
1608
1609         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1610         if (glfd == NULL) {
1611                 END_PROFILE(syscall_fchmod);
1612                 DBG_ERR("Failed to fetch gluster fd\n");
1613                 return -1;
1614         }
1615
1616         if (!fsp->fsp_flags.is_pathref) {
1617                 /*
1618                  * We can use an io_fd to remove xattrs.
1619                  */
1620                 ret = glfs_fchmod(glfd, mode);
1621         } else {
1622                 /*
1623                  * This is no longer a handle based call.
1624                  */
1625                 ret = glfs_chmod(handle->data, fsp->fsp_name->base_name, mode);
1626         }
1627         END_PROFILE(syscall_fchmod);
1628
1629         return ret;
1630 }
1631
1632 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1633                               files_struct *fsp, uid_t uid, gid_t gid)
1634 {
1635         int ret;
1636         glfs_fd_t *glfd = NULL;
1637
1638         START_PROFILE(syscall_fchown);
1639
1640         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1641         if (glfd == NULL) {
1642                 END_PROFILE(syscall_fchown);
1643                 DBG_ERR("Failed to fetch gluster fd\n");
1644                 return -1;
1645         }
1646
1647         ret = glfs_fchown(glfd, uid, gid);
1648         END_PROFILE(syscall_fchown);
1649
1650         return ret;
1651 }
1652
1653 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1654                         const struct smb_filename *smb_fname,
1655                         uid_t uid,
1656                         gid_t gid)
1657 {
1658         int ret;
1659
1660         START_PROFILE(syscall_lchown);
1661         ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1662         END_PROFILE(syscall_lchown);
1663
1664         return ret;
1665 }
1666
1667 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1668                         const struct smb_filename *smb_fname)
1669 {
1670         int ret;
1671
1672         START_PROFILE(syscall_chdir);
1673         ret = glfs_chdir(handle->data, smb_fname->base_name);
1674         END_PROFILE(syscall_chdir);
1675
1676         return ret;
1677 }
1678
1679 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1680                                 TALLOC_CTX *ctx)
1681 {
1682         char cwd[PATH_MAX] = { '\0' };
1683         char *ret;
1684         struct smb_filename *smb_fname = NULL;
1685
1686         START_PROFILE(syscall_getwd);
1687
1688         ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1689         END_PROFILE(syscall_getwd);
1690
1691         if (ret == NULL) {
1692                 return NULL;
1693         }
1694         smb_fname = synthetic_smb_fname(ctx,
1695                                         ret,
1696                                         NULL,
1697                                         NULL,
1698                                         0,
1699                                         0);
1700         return smb_fname;
1701 }
1702
1703 static int vfs_gluster_fntimes(struct vfs_handle_struct *handle,
1704                                files_struct *fsp,
1705                                struct smb_file_time *ft)
1706 {
1707         int ret = -1;
1708         struct timespec times[2];
1709         glfs_fd_t *glfd = NULL;
1710
1711         START_PROFILE(syscall_fntimes);
1712
1713         if (is_omit_timespec(&ft->atime)) {
1714                 times[0].tv_sec = fsp->fsp_name->st.st_ex_atime.tv_sec;
1715                 times[0].tv_nsec = fsp->fsp_name->st.st_ex_atime.tv_nsec;
1716         } else {
1717                 times[0].tv_sec = ft->atime.tv_sec;
1718                 times[0].tv_nsec = ft->atime.tv_nsec;
1719         }
1720
1721         if (is_omit_timespec(&ft->mtime)) {
1722                 times[1].tv_sec = fsp->fsp_name->st.st_ex_mtime.tv_sec;
1723                 times[1].tv_nsec = fsp->fsp_name->st.st_ex_mtime.tv_nsec;
1724         } else {
1725                 times[1].tv_sec = ft->mtime.tv_sec;
1726                 times[1].tv_nsec = ft->mtime.tv_nsec;
1727         }
1728
1729         if ((timespec_compare(&times[0],
1730                               &fsp->fsp_name->st.st_ex_atime) == 0) &&
1731             (timespec_compare(&times[1],
1732                               &fsp->fsp_name->st.st_ex_mtime) == 0)) {
1733                 END_PROFILE(syscall_fntimes);
1734                 return 0;
1735         }
1736
1737         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1738         if (glfd == NULL) {
1739                 END_PROFILE(syscall_fntimes);
1740                 DBG_ERR("Failed to fetch gluster fd\n");
1741                 return -1;
1742         }
1743
1744         if (!fsp->fsp_flags.is_pathref) {
1745                 ret = glfs_futimens(glfd, times);
1746         } else {
1747                 ret = glfs_utimens(handle->data,
1748                                    fsp->fsp_name->base_name,
1749                                    times);
1750         }
1751         END_PROFILE(syscall_fntimes);
1752
1753         return ret;
1754 }
1755
1756 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1757                                  files_struct *fsp, off_t offset)
1758 {
1759         int ret;
1760         glfs_fd_t *glfd = NULL;
1761
1762         START_PROFILE(syscall_ftruncate);
1763
1764         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1765         if (glfd == NULL) {
1766                 END_PROFILE(syscall_ftruncate);
1767                 DBG_ERR("Failed to fetch gluster fd\n");
1768                 return -1;
1769         }
1770
1771 #ifdef HAVE_GFAPI_VER_7_6
1772         ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1773 #else
1774         ret = glfs_ftruncate(glfd, offset);
1775 #endif
1776         END_PROFILE(syscall_ftruncate);
1777
1778         return ret;
1779 }
1780
1781 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1782                                  struct files_struct *fsp,
1783                                  uint32_t mode,
1784                                  off_t offset, off_t len)
1785 {
1786         int ret;
1787 #ifdef HAVE_GFAPI_VER_6
1788         glfs_fd_t *glfd = NULL;
1789         int keep_size, punch_hole;
1790
1791         START_PROFILE(syscall_fallocate);
1792
1793         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1794         if (glfd == NULL) {
1795                 END_PROFILE(syscall_fallocate);
1796                 DBG_ERR("Failed to fetch gluster fd\n");
1797                 return -1;
1798         }
1799
1800         keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1801         punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1802
1803         mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1804         if (mode != 0) {
1805                 END_PROFILE(syscall_fallocate);
1806                 errno = ENOTSUP;
1807                 return -1;
1808         }
1809
1810         if (punch_hole) {
1811                 ret = glfs_discard(glfd, offset, len);
1812                 if (ret != 0) {
1813                         DBG_DEBUG("glfs_discard failed: %s\n",
1814                                   strerror(errno));
1815                 }
1816         }
1817
1818         ret = glfs_fallocate(glfd, keep_size, offset, len);
1819         END_PROFILE(syscall_fallocate);
1820 #else
1821         errno = ENOTSUP;
1822         ret = -1;
1823 #endif
1824         return ret;
1825 }
1826
1827 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1828                                 TALLOC_CTX *ctx,
1829                                 const struct smb_filename *smb_fname)
1830 {
1831         char *result = NULL;
1832         struct smb_filename *result_fname = NULL;
1833         char *resolved_path = NULL;
1834
1835         START_PROFILE(syscall_realpath);
1836
1837         resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1838         if (resolved_path == NULL) {
1839                 END_PROFILE(syscall_realpath);
1840                 errno = ENOMEM;
1841                 return NULL;
1842         }
1843
1844         result = glfs_realpath(handle->data,
1845                         smb_fname->base_name,
1846                         resolved_path);
1847         if (result != NULL) {
1848                 result_fname = synthetic_smb_fname(ctx,
1849                                                    result,
1850                                                    NULL,
1851                                                    NULL,
1852                                                    0,
1853                                                    0);
1854         }
1855
1856         SAFE_FREE(resolved_path);
1857         END_PROFILE(syscall_realpath);
1858
1859         return result_fname;
1860 }
1861
1862 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1863                              files_struct *fsp, int op, off_t offset,
1864                              off_t count, int type)
1865 {
1866         struct flock flock = { 0, };
1867         int ret;
1868         glfs_fd_t *glfd = NULL;
1869         bool ok = false;
1870
1871         START_PROFILE(syscall_fcntl_lock);
1872
1873         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1874         if (glfd == NULL) {
1875                 DBG_ERR("Failed to fetch gluster fd\n");
1876                 ok = false;
1877                 goto out;
1878         }
1879
1880         flock.l_type = type;
1881         flock.l_whence = SEEK_SET;
1882         flock.l_start = offset;
1883         flock.l_len = count;
1884         flock.l_pid = 0;
1885
1886         ret = glfs_posix_lock(glfd, op, &flock);
1887
1888         if (op == F_GETLK) {
1889                 /* lock query, true if someone else has locked */
1890                 if ((ret != -1) &&
1891                     (flock.l_type != F_UNLCK) &&
1892                     (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1893                         ok = true;
1894                         goto out;
1895                 }
1896                 /* not me */
1897                 ok = false;
1898                 goto out;
1899         }
1900
1901         if (ret == -1) {
1902                 ok = false;
1903                 goto out;
1904         }
1905
1906         ok = true;
1907 out:
1908         END_PROFILE(syscall_fcntl_lock);
1909
1910         return ok;
1911 }
1912
1913 static int vfs_gluster_filesystem_sharemode(struct vfs_handle_struct *handle,
1914                                             files_struct *fsp,
1915                                             uint32_t share_access,
1916                                             uint32_t access_mask)
1917 {
1918         errno = ENOSYS;
1919         return -1;
1920 }
1921
1922 static int vfs_gluster_fcntl(vfs_handle_struct *handle,
1923                              files_struct *fsp, int cmd, va_list cmd_arg)
1924 {
1925         /*
1926          * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
1927          * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
1928          */
1929         if (cmd == F_GETFL) {
1930                 return 0;
1931         } else if (cmd == F_SETFL) {
1932                 va_list dup_cmd_arg;
1933                 int opt;
1934
1935                 va_copy(dup_cmd_arg, cmd_arg);
1936                 opt = va_arg(dup_cmd_arg, int);
1937                 va_end(dup_cmd_arg);
1938                 if (opt == 0) {
1939                         return 0;
1940                 }
1941                 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
1942                 goto err_out;
1943         }
1944         DBG_ERR("unexpected fcntl: %d\n", cmd);
1945 err_out:
1946         errno = EINVAL;
1947         return -1;
1948 }
1949
1950 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1951                                       files_struct *fsp, int leasetype)
1952 {
1953         errno = ENOSYS;
1954         return -1;
1955 }
1956
1957 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1958                                 files_struct *fsp, off_t *poffset,
1959                                 off_t *pcount, int *ptype, pid_t *ppid)
1960 {
1961         struct flock flock = { 0, };
1962         int ret;
1963         glfs_fd_t *glfd = NULL;
1964
1965         START_PROFILE(syscall_fcntl_getlock);
1966
1967         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1968         if (glfd == NULL) {
1969                 END_PROFILE(syscall_fcntl_getlock);
1970                 DBG_ERR("Failed to fetch gluster fd\n");
1971                 return false;
1972         }
1973
1974         flock.l_type = *ptype;
1975         flock.l_whence = SEEK_SET;
1976         flock.l_start = *poffset;
1977         flock.l_len = *pcount;
1978         flock.l_pid = 0;
1979
1980         ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1981
1982         if (ret == -1) {
1983                 END_PROFILE(syscall_fcntl_getlock);
1984                 return false;
1985         }
1986
1987         *ptype = flock.l_type;
1988         *poffset = flock.l_start;
1989         *pcount = flock.l_len;
1990         *ppid = flock.l_pid;
1991         END_PROFILE(syscall_fcntl_getlock);
1992
1993         return true;
1994 }
1995
1996 static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
1997                                 const struct smb_filename *link_target,
1998                                 struct files_struct *dirfsp,
1999                                 const struct smb_filename *new_smb_fname)
2000 {
2001         int ret;
2002
2003 #ifdef HAVE_GFAPI_VER_7_11
2004         glfs_fd_t *pglfd = NULL;
2005
2006         START_PROFILE(syscall_symlinkat);
2007
2008         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2009         if (pglfd == NULL) {
2010                 END_PROFILE(syscall_symlinkat);
2011                 DBG_ERR("Failed to fetch gluster fd\n");
2012                 return -1;
2013         }
2014
2015         ret = glfs_symlinkat(link_target->base_name,
2016                              pglfd,
2017                              new_smb_fname->base_name);
2018 #else
2019         struct smb_filename *full_fname = NULL;
2020
2021         START_PROFILE(syscall_symlinkat);
2022
2023         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2024                                                   dirfsp,
2025                                                   new_smb_fname);
2026         if (full_fname == NULL) {
2027                 END_PROFILE(syscall_symlinkat);
2028                 return -1;
2029         }
2030
2031         ret = glfs_symlink(handle->data,
2032                            link_target->base_name,
2033                            full_fname->base_name);
2034
2035         TALLOC_FREE(full_fname);
2036 #endif
2037
2038         END_PROFILE(syscall_symlinkat);
2039
2040         return ret;
2041 }
2042
2043 static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
2044                                 const struct files_struct *dirfsp,
2045                                 const struct smb_filename *smb_fname,
2046                                 char *buf,
2047                                 size_t bufsiz)
2048 {
2049         int ret;
2050
2051 #ifdef HAVE_GFAPI_VER_7_11
2052         glfs_fd_t *pglfd = NULL;
2053
2054         START_PROFILE(syscall_readlinkat);
2055
2056         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2057         if (pglfd == NULL) {
2058                 END_PROFILE(syscall_readlinkat);
2059                 DBG_ERR("Failed to fetch gluster fd\n");
2060                 return -1;
2061         }
2062
2063         ret = glfs_readlinkat(pglfd, smb_fname->base_name, buf, bufsiz);
2064 #else
2065         struct smb_filename *full_fname = NULL;
2066
2067         START_PROFILE(syscall_readlinkat);
2068
2069         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2070                                                   dirfsp,
2071                                                   smb_fname);
2072         if (full_fname == NULL) {
2073                 END_PROFILE(syscall_readlinkat);
2074                 return -1;
2075         }
2076
2077         ret = glfs_readlink(handle->data, full_fname->base_name, buf, bufsiz);
2078
2079         TALLOC_FREE(full_fname);
2080 #endif
2081
2082         END_PROFILE(syscall_readlinkat);
2083
2084         return ret;
2085 }
2086
2087 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
2088                                 files_struct *srcfsp,
2089                                 const struct smb_filename *old_smb_fname,
2090                                 files_struct *dstfsp,
2091                                 const struct smb_filename *new_smb_fname,
2092                                 int flags)
2093 {
2094         int ret;
2095
2096 #ifdef HAVE_GFAPI_VER_7_11
2097         glfs_fd_t *src_pglfd = NULL;
2098         glfs_fd_t *dst_pglfd = NULL;
2099
2100         START_PROFILE(syscall_linkat);
2101
2102         src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
2103         if (src_pglfd == NULL) {
2104                 END_PROFILE(syscall_linkat);
2105                 DBG_ERR("Failed to fetch gluster fd\n");
2106                 return -1;
2107         }
2108
2109         dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
2110         if (dst_pglfd == NULL) {
2111                 END_PROFILE(syscall_linkat);
2112                 DBG_ERR("Failed to fetch gluster fd\n");
2113                 return -1;
2114         }
2115
2116         ret = glfs_linkat(src_pglfd,
2117                           old_smb_fname->base_name,
2118                           dst_pglfd,
2119                           new_smb_fname->base_name,
2120                           flags);
2121 #else
2122         struct smb_filename *full_fname_old = NULL;
2123         struct smb_filename *full_fname_new = NULL;
2124
2125         START_PROFILE(syscall_linkat);
2126
2127         full_fname_old = full_path_from_dirfsp_atname(talloc_tos(),
2128                                                       srcfsp,
2129                                                       old_smb_fname);
2130         if (full_fname_old == NULL) {
2131                 END_PROFILE(syscall_linkat);
2132                 return -1;
2133         }
2134
2135         full_fname_new = full_path_from_dirfsp_atname(talloc_tos(),
2136                                                       dstfsp,
2137                                                       new_smb_fname);
2138         if (full_fname_new == NULL) {
2139                 END_PROFILE(syscall_linkat);
2140                 TALLOC_FREE(full_fname_old);
2141                 return -1;
2142         }
2143
2144         ret = glfs_link(handle->data,
2145                         full_fname_old->base_name,
2146                         full_fname_new->base_name);
2147
2148         TALLOC_FREE(full_fname_old);
2149         TALLOC_FREE(full_fname_new);
2150 #endif
2151
2152         END_PROFILE(syscall_linkat);
2153
2154         return ret;
2155 }
2156
2157 static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
2158                                 files_struct *dirfsp,
2159                                 const struct smb_filename *smb_fname,
2160                                 mode_t mode,
2161                                 SMB_DEV_T dev)
2162 {
2163         int ret;
2164
2165 #ifdef HAVE_GFAPI_VER_7_11
2166         glfs_fd_t *pglfd = NULL;
2167
2168         START_PROFILE(syscall_mknodat);
2169
2170         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2171         if (pglfd == NULL) {
2172                 END_PROFILE(syscall_mknodat);
2173                 DBG_ERR("Failed to fetch gluster fd\n");
2174                 return -1;
2175         }
2176
2177         ret = glfs_mknodat(pglfd, smb_fname->base_name, mode, dev);
2178 #else
2179         struct smb_filename *full_fname = NULL;
2180
2181         START_PROFILE(syscall_mknodat);
2182
2183         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2184                                                   dirfsp,
2185                                                   smb_fname);
2186         if (full_fname == NULL) {
2187                 END_PROFILE(syscall_mknodat);
2188                 return -1;
2189         }
2190
2191         ret = glfs_mknod(handle->data, full_fname->base_name, mode, dev);
2192
2193         TALLOC_FREE(full_fname);
2194 #endif
2195
2196         END_PROFILE(syscall_mknodat);
2197
2198         return ret;
2199 }
2200
2201 static int vfs_gluster_fchflags(struct vfs_handle_struct *handle,
2202                                 struct files_struct *fsp,
2203                                 unsigned int flags)
2204 {
2205         errno = ENOSYS;
2206         return -1;
2207 }
2208
2209 static NTSTATUS vfs_gluster_get_real_filename_at(
2210         struct vfs_handle_struct *handle,
2211         struct files_struct *dirfsp,
2212         const char *name,
2213         TALLOC_CTX *mem_ctx,
2214         char **found_name)
2215 {
2216         int ret;
2217         char key_buf[GLUSTER_NAME_MAX + 64];
2218         char val_buf[GLUSTER_NAME_MAX + 1];
2219
2220         if (strlen(name) >= GLUSTER_NAME_MAX) {
2221                 return NT_STATUS_OBJECT_NAME_INVALID;
2222         }
2223
2224         snprintf(key_buf, GLUSTER_NAME_MAX + 64,
2225                  "glusterfs.get_real_filename:%s", name);
2226
2227         ret = glfs_getxattr(handle->data,
2228                             dirfsp->fsp_name->base_name,
2229                             key_buf,
2230                             val_buf,
2231                             GLUSTER_NAME_MAX + 1);
2232         if (ret == -1) {
2233                 if (errno == ENOATTR) {
2234                         errno = ENOENT;
2235                 }
2236                 return map_nt_error_from_unix(errno);
2237         }
2238
2239         *found_name = talloc_strdup(mem_ctx, val_buf);
2240         if (found_name[0] == NULL) {
2241                 return NT_STATUS_NO_MEMORY;
2242         }
2243
2244         return NT_STATUS_OK;
2245 }
2246
2247 static const char *vfs_gluster_connectpath(
2248         struct vfs_handle_struct *handle,
2249         const struct files_struct *dirfsp,
2250         const struct smb_filename *smb_fname)
2251 {
2252         return handle->conn->connectpath;
2253 }
2254
2255 /* EA Operations */
2256
2257 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
2258                                      files_struct *fsp, const char *name,
2259                                      void *value, size_t size)
2260 {
2261         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2262         if (glfd == NULL) {
2263                 DBG_ERR("Failed to fetch gluster fd\n");
2264                 return -1;
2265         }
2266
2267         if (!fsp->fsp_flags.is_pathref) {
2268                 /*
2269                  * We can use an io_fd to retrieve xattr value.
2270                  */
2271                 return glfs_fgetxattr(glfd, name, value, size);
2272         }
2273
2274         /*
2275          * This is no longer a handle based call.
2276          */
2277         return glfs_getxattr(handle->data,
2278                              fsp->fsp_name->base_name,
2279                              name,
2280                              value,
2281                              size);
2282 }
2283
2284 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
2285                                       files_struct *fsp, char *list,
2286                                       size_t size)
2287 {
2288         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2289         if (glfd == NULL) {
2290                 DBG_ERR("Failed to fetch gluster fd\n");
2291                 return -1;
2292         }
2293         if (!fsp->fsp_flags.is_pathref) {
2294                 /*
2295                  * We can use an io_fd to list xattrs.
2296                  */
2297                 return glfs_flistxattr(glfd, list, size);
2298         } else {
2299                 /*
2300                  * This is no longer a handle based call.
2301                  */
2302                 return glfs_listxattr(handle->data,
2303                                 fsp->fsp_name->base_name,
2304                                 list,
2305                                 size);
2306         }
2307 }
2308
2309 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
2310                                     files_struct *fsp, const char *name)
2311 {
2312         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2313         if (glfd == NULL) {
2314                 DBG_ERR("Failed to fetch gluster fd\n");
2315                 return -1;
2316         }
2317         if (!fsp->fsp_flags.is_pathref) {
2318                 /*
2319                  * We can use an io_fd to remove xattrs.
2320                  */
2321                 return glfs_fremovexattr(glfd, name);
2322         } else {
2323                 /*
2324                  * This is no longer a handle based call.
2325                  */
2326                 return glfs_removexattr(handle->data,
2327                                 fsp->fsp_name->base_name,
2328                                 name);
2329         }
2330 }
2331
2332 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
2333                                  files_struct *fsp, const char *name,
2334                                  const void *value, size_t size, int flags)
2335 {
2336         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2337         if (glfd == NULL) {
2338                 DBG_ERR("Failed to fetch gluster fd\n");
2339                 return -1;
2340         }
2341
2342         if (!fsp->fsp_flags.is_pathref) {
2343                 /*
2344                  * We can use an io_fd to set xattrs.
2345                  */
2346                 return glfs_fsetxattr(glfd, name, value, size, flags);
2347         } else {
2348                 /*
2349                  * This is no longer a handle based call.
2350                  */
2351                 return glfs_setxattr(handle->data,
2352                                 fsp->fsp_name->base_name,
2353                                 name,
2354                                 value,
2355                                 size,
2356                                 flags);
2357         }
2358 }
2359
2360 /* AIO Operations */
2361
2362 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
2363                                   files_struct *fsp)
2364 {
2365         return false;
2366 }
2367
2368 static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
2369                                 struct files_struct *dirfsp,
2370                                 const struct smb_filename *smb_fname,
2371                                 const struct referral *reflist,
2372                                 size_t referral_count)
2373 {
2374         TALLOC_CTX *frame = talloc_stackframe();
2375         NTSTATUS status = NT_STATUS_NO_MEMORY;
2376         int ret;
2377         char *msdfs_link = NULL;
2378 #ifdef HAVE_GFAPI_VER_7_11
2379         glfs_fd_t *pglfd = NULL;
2380 #else
2381         struct smb_filename *full_fname = NULL;
2382 #endif
2383
2384         /* Form the msdfs_link contents */
2385         msdfs_link = msdfs_link_string(frame,
2386                                         reflist,
2387                                         referral_count);
2388         if (msdfs_link == NULL) {
2389                 goto out;
2390         }
2391
2392 #ifdef HAVE_GFAPI_VER_7_11
2393         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2394         if (pglfd == NULL) {
2395                 DBG_ERR("Failed to fetch gluster fd\n");
2396                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2397                 goto out;
2398         }
2399
2400         ret = glfs_symlinkat(msdfs_link, pglfd, smb_fname->base_name);
2401 #else
2402         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2403                                                   dirfsp,
2404                                                   smb_fname);
2405         if (full_fname == NULL) {
2406                 goto out;
2407         }
2408
2409         ret = glfs_symlink(handle->data, msdfs_link, full_fname->base_name);
2410
2411         TALLOC_FREE(full_fname);
2412 #endif
2413         if (ret == 0) {
2414                 status = NT_STATUS_OK;
2415         } else {
2416                 status = map_nt_error_from_unix(errno);
2417         }
2418
2419   out:
2420
2421         TALLOC_FREE(frame);
2422         return status;
2423 }
2424
2425 /*
2426  * Read and return the contents of a DFS redirect given a
2427  * pathname. A caller can pass in NULL for ppreflist and
2428  * preferral_count but still determine if this was a
2429  * DFS redirect point by getting NT_STATUS_OK back
2430  * without incurring the overhead of reading and parsing
2431  * the referral contents.
2432  */
2433
2434 static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
2435                                 TALLOC_CTX *mem_ctx,
2436                                 struct files_struct *dirfsp,
2437                                 struct smb_filename *smb_fname,
2438                                 struct referral **ppreflist,
2439                                 size_t *preferral_count)
2440 {
2441         NTSTATUS status = NT_STATUS_NO_MEMORY;
2442         size_t bufsize;
2443         char *link_target = NULL;
2444         int referral_len;
2445         bool ok;
2446 #if defined(HAVE_BROKEN_READLINK)
2447         char link_target_buf[PATH_MAX];
2448 #else
2449         char link_target_buf[7];
2450 #endif
2451         struct stat st;
2452         struct smb_filename *full_fname = NULL;
2453         int ret;
2454 #ifdef HAVE_GFAPI_VER_7_11
2455         glfs_fd_t *pglfd = NULL;
2456 #endif
2457
2458         if (is_named_stream(smb_fname)) {
2459                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2460                 goto err;
2461         }
2462
2463         if (ppreflist == NULL && preferral_count == NULL) {
2464                 /*
2465                  * We're only checking if this is a DFS
2466                  * redirect. We don't need to return data.
2467                  */
2468                 bufsize = sizeof(link_target_buf);
2469                 link_target = link_target_buf;
2470         } else {
2471                 bufsize = PATH_MAX;
2472                 link_target = talloc_array(mem_ctx, char, bufsize);
2473                 if (!link_target) {
2474                         goto err;
2475                 }
2476         }
2477
2478         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2479                                                   dirfsp,
2480                                                   smb_fname);
2481         if (full_fname == NULL) {
2482                 status = NT_STATUS_NO_MEMORY;
2483                 goto err;
2484         }
2485
2486         ret = glfs_lstat(handle->data, full_fname->base_name, &st);
2487         if (ret < 0) {
2488                 status = map_nt_error_from_unix(errno);
2489                 goto err;
2490         }
2491
2492 #ifdef HAVE_GFAPI_VER_7_11
2493         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2494         if (pglfd == NULL) {
2495                 DBG_ERR("Failed to fetch gluster fd\n");
2496                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2497         }
2498
2499         referral_len = glfs_readlinkat(pglfd,
2500                                        smb_fname->base_name,
2501                                        link_target,
2502                                        bufsize - 1);
2503 #else
2504         referral_len = glfs_readlink(handle->data,
2505                                 full_fname->base_name,
2506                                 link_target,
2507                                 bufsize - 1);
2508 #endif
2509         if (referral_len < 0) {
2510                 if (errno == EINVAL) {
2511                         DBG_INFO("%s is not a link.\n", full_fname->base_name);
2512                         status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2513                 } else {
2514                         status = map_nt_error_from_unix(errno);
2515                         DBG_ERR("Error reading "
2516                                 "msdfs link %s: %s\n",
2517                                 full_fname->base_name,
2518                                 strerror(errno));
2519                 }
2520                 goto err;
2521         }
2522         link_target[referral_len] = '\0';
2523
2524         DBG_INFO("%s -> %s\n",
2525                         full_fname->base_name,
2526                         link_target);
2527
2528         if (!strnequal(link_target, "msdfs:", 6)) {
2529                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2530                 goto err;
2531         }
2532
2533         if (ppreflist == NULL && preferral_count == NULL) {
2534                 /* Early return for checking if this is a DFS link. */
2535                 TALLOC_FREE(full_fname);
2536                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2537                 return NT_STATUS_OK;
2538         }
2539
2540         ok = parse_msdfs_symlink(mem_ctx,
2541                         lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
2542                         link_target,
2543                         ppreflist,
2544                         preferral_count);
2545
2546         if (ok) {
2547                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2548                 status = NT_STATUS_OK;
2549         } else {
2550                 status = NT_STATUS_NO_MEMORY;
2551         }
2552
2553   err:
2554
2555         if (link_target != link_target_buf) {
2556                 TALLOC_FREE(link_target);
2557         }
2558         TALLOC_FREE(full_fname);
2559         return status;
2560 }
2561
2562 static struct vfs_fn_pointers glusterfs_fns = {
2563
2564         /* Disk Operations */
2565
2566         .connect_fn = vfs_gluster_connect,
2567         .disconnect_fn = vfs_gluster_disconnect,
2568         .disk_free_fn = vfs_gluster_disk_free,
2569         .get_quota_fn = vfs_gluster_get_quota,
2570         .set_quota_fn = vfs_gluster_set_quota,
2571         .statvfs_fn = vfs_gluster_statvfs,
2572         .fs_capabilities_fn = vfs_gluster_fs_capabilities,
2573
2574         .get_dfs_referrals_fn = NULL,
2575
2576         /* Directory Operations */
2577
2578         .fdopendir_fn = vfs_gluster_fdopendir,
2579         .readdir_fn = vfs_gluster_readdir,
2580         .rewind_dir_fn = vfs_gluster_rewinddir,
2581         .mkdirat_fn = vfs_gluster_mkdirat,
2582         .closedir_fn = vfs_gluster_closedir,
2583
2584         /* File Operations */
2585
2586         .openat_fn = vfs_gluster_openat,
2587         .create_file_fn = NULL,
2588         .close_fn = vfs_gluster_close,
2589         .pread_fn = vfs_gluster_pread,
2590         .pread_send_fn = vfs_gluster_pread_send,
2591         .pread_recv_fn = vfs_gluster_pread_recv,
2592         .pwrite_fn = vfs_gluster_pwrite,
2593         .pwrite_send_fn = vfs_gluster_pwrite_send,
2594         .pwrite_recv_fn = vfs_gluster_pwrite_recv,
2595         .lseek_fn = vfs_gluster_lseek,
2596         .sendfile_fn = vfs_gluster_sendfile,
2597         .recvfile_fn = vfs_gluster_recvfile,
2598         .renameat_fn = vfs_gluster_renameat,
2599         .fsync_send_fn = vfs_gluster_fsync_send,
2600         .fsync_recv_fn = vfs_gluster_fsync_recv,
2601
2602         .stat_fn = vfs_gluster_stat,
2603         .fstat_fn = vfs_gluster_fstat,
2604         .fstatat_fn = vfs_gluster_fstatat,
2605         .lstat_fn = vfs_gluster_lstat,
2606         .get_alloc_size_fn = vfs_gluster_get_alloc_size,
2607         .unlinkat_fn = vfs_gluster_unlinkat,
2608
2609         .fchmod_fn = vfs_gluster_fchmod,
2610         .fchown_fn = vfs_gluster_fchown,
2611         .lchown_fn = vfs_gluster_lchown,
2612         .chdir_fn = vfs_gluster_chdir,
2613         .getwd_fn = vfs_gluster_getwd,
2614         .fntimes_fn = vfs_gluster_fntimes,
2615         .ftruncate_fn = vfs_gluster_ftruncate,
2616         .fallocate_fn = vfs_gluster_fallocate,
2617         .lock_fn = vfs_gluster_lock,
2618         .filesystem_sharemode_fn = vfs_gluster_filesystem_sharemode,
2619         .fcntl_fn = vfs_gluster_fcntl,
2620         .linux_setlease_fn = vfs_gluster_linux_setlease,
2621         .getlock_fn = vfs_gluster_getlock,
2622         .symlinkat_fn = vfs_gluster_symlinkat,
2623         .readlinkat_fn = vfs_gluster_readlinkat,
2624         .linkat_fn = vfs_gluster_linkat,
2625         .mknodat_fn = vfs_gluster_mknodat,
2626         .realpath_fn = vfs_gluster_realpath,
2627         .fchflags_fn = vfs_gluster_fchflags,
2628         .file_id_create_fn = NULL,
2629         .fstreaminfo_fn = NULL,
2630         .get_real_filename_at_fn = vfs_gluster_get_real_filename_at,
2631         .connectpath_fn = vfs_gluster_connectpath,
2632         .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
2633         .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
2634
2635         .brl_lock_windows_fn = NULL,
2636         .brl_unlock_windows_fn = NULL,
2637         .strict_lock_check_fn = NULL,
2638         .translate_name_fn = NULL,
2639         .fsctl_fn = NULL,
2640
2641         /* NT ACL Operations */
2642         .fget_nt_acl_fn = NULL,
2643         .fset_nt_acl_fn = NULL,
2644         .audit_file_fn = NULL,
2645
2646         /* Posix ACL Operations */
2647         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
2648         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2649         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
2650         .sys_acl_delete_def_fd_fn = posixacl_xattr_acl_delete_def_fd,
2651
2652         /* EA Operations */
2653         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2654         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2655         .fgetxattr_fn = vfs_gluster_fgetxattr,
2656         .flistxattr_fn = vfs_gluster_flistxattr,
2657         .fremovexattr_fn = vfs_gluster_fremovexattr,
2658         .fsetxattr_fn = vfs_gluster_fsetxattr,
2659
2660         /* AIO Operations */
2661         .aio_force_fn = vfs_gluster_aio_force,
2662
2663         /* Durable handle Operations */
2664         .durable_cookie_fn = NULL,
2665         .durable_disconnect_fn = NULL,
2666         .durable_reconnect_fn = NULL,
2667 };
2668
2669 static_decl_vfs;
2670 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
2671 {
2672         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2673                                 "glusterfs", &glusterfs_fns);
2674 }