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