s3:rpc_client: Implement dcerpc_lsa_open_policy_fallback()
[Samba.git] / source3 / modules / vfs_glusterfs.c
blob235329f090d5e4c925b71fe6c53ef11bd8410f40
1 /*
2 Unix SMB/CIFS implementation.
4 Wrap GlusterFS GFAPI calls in vfs functions.
6 Copyright (c) 2013 Anand Avati <avati@redhat.com>
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.
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.
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/>.
22 /**
23 * @file vfs_glusterfs.c
24 * @author Anand Avati <avati@redhat.com>
25 * @date May 2013
26 * @brief Samba VFS module for glusterfs
28 * @todo
29 * - sendfile/recvfile support
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.
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"
50 #define DEFAULT_VOLFILE_SERVER "localhost"
51 #define GLUSTER_NAME_MAX 255
53 /**
54 * Helper to convert struct stat to struct stat_ex.
56 static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
58 ZERO_STRUCTP(dst);
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
82 /* pre-opened glfs_t */
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;
93 static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
95 struct glfs_preopened *entry = NULL;
97 entry = talloc_zero(NULL, struct glfs_preopened);
98 if (!entry) {
99 errno = ENOMEM;
100 return -1;
103 entry->volume = talloc_strdup(entry, volume);
104 if (!entry->volume) {
105 talloc_free(entry);
106 errno = ENOMEM;
107 return -1;
110 entry->connectpath = talloc_strdup(entry, connectpath);
111 if (entry->connectpath == NULL) {
112 talloc_free(entry);
113 errno = ENOMEM;
114 return -1;
117 entry->fs = fs;
118 entry->ref = 1;
120 DLIST_ADD(glfs_preopened, entry);
122 return 0;
125 static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
127 struct glfs_preopened *entry = NULL;
129 for (entry = glfs_preopened; entry; entry = entry->next) {
130 if (strcmp(entry->volume, volume) == 0 &&
131 strcmp(entry->connectpath, connectpath) == 0)
133 entry->ref++;
134 return entry->fs;
138 return NULL;
141 static void glfs_clear_preopened(glfs_t *fs)
143 struct glfs_preopened *entry = NULL;
145 for (entry = glfs_preopened; entry; entry = entry->next) {
146 if (entry->fs == fs) {
147 if (--entry->ref)
148 return;
150 DLIST_REMOVE(glfs_preopened, entry);
152 glfs_fini(entry->fs);
153 talloc_free(entry);
154 break;
159 static int vfs_gluster_set_volfile_servers(glfs_t *fs,
160 const char *volfile_servers)
162 char *server = NULL;
163 size_t server_count = 0;
164 size_t server_success = 0;
165 int ret = -1;
166 TALLOC_CTX *frame = talloc_stackframe();
168 DBG_INFO("servers list %s\n", volfile_servers);
170 while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
171 char *transport = NULL;
172 char *host = NULL;
173 int port = 0;
175 server_count++;
176 DBG_INFO("server %zu %s\n", server_count, server);
178 /* Determine the transport type */
179 if (strncmp(server, "unix+", 5) == 0) {
180 port = 0;
181 transport = talloc_strdup(frame, "unix");
182 if (!transport) {
183 errno = ENOMEM;
184 goto out;
186 host = talloc_strdup(frame, server + 5);
187 if (!host) {
188 errno = ENOMEM;
189 goto out;
191 } else {
192 char *p = NULL;
193 char *port_index = NULL;
195 if (strncmp(server, "tcp+", 4) == 0) {
196 server += 4;
199 /* IPv6 is enclosed in []
200 * ':' before ']' is part of IPv6
201 * ':' after ']' indicates port
203 p = server;
204 if (server[0] == '[') {
205 server++;
206 p = index(server, ']');
207 if (p == NULL) {
208 /* Malformed IPv6 */
209 continue;
211 p[0] = '\0';
212 p++;
215 port_index = index(p, ':');
217 if (port_index == NULL) {
218 port = 0;
219 } else {
220 port = atoi(port_index + 1);
221 port_index[0] = '\0';
223 transport = talloc_strdup(frame, "tcp");
224 if (!transport) {
225 errno = ENOMEM;
226 goto out;
228 host = talloc_strdup(frame, server);
229 if (!host) {
230 errno = ENOMEM;
231 goto out;
235 DBG_INFO("Calling set volfile server with params "
236 "transport=%s, host=%s, port=%d\n", transport,
237 host, port);
239 ret = glfs_set_volfile_server(fs, transport, host, port);
240 if (ret < 0) {
241 DBG_WARNING("Failed to set volfile_server "
242 "transport=%s, host=%s, port=%d (%s)\n",
243 transport, host, port, strerror(errno));
244 } else {
245 server_success++;
249 out:
250 if (server_count == 0) {
251 ret = -1;
252 } else if (server_success < server_count) {
253 DBG_WARNING("Failed to set %zu out of %zu servers parsed\n",
254 server_count - server_success, server_count);
255 ret = 0;
258 TALLOC_FREE(frame);
259 return ret;
262 /* Disk Operations */
264 static int check_for_write_behind_translator(TALLOC_CTX *mem_ctx,
265 glfs_t *fs,
266 const char *volume)
268 char *buf = NULL;
269 char **lines = NULL;
270 int numlines = 0;
271 int i;
272 char *option;
273 bool write_behind_present = false;
274 size_t newlen;
275 int ret;
277 ret = glfs_get_volfile(fs, NULL, 0);
278 if (ret == 0) {
279 DBG_ERR("%s: Failed to get volfile for "
280 "volume (%s): No volfile\n",
281 volume,
282 strerror(errno));
283 return -1;
285 if (ret > 0) {
286 DBG_ERR("%s: Invalid return %d for glfs_get_volfile for "
287 "volume (%s): No volfile\n",
288 volume,
289 ret,
290 strerror(errno));
291 return -1;
294 newlen = 0 - ret;
296 buf = talloc_zero_array(mem_ctx, char, newlen);
297 if (buf == NULL) {
298 return -1;
301 ret = glfs_get_volfile(fs, buf, newlen);
302 if (ret != newlen) {
303 TALLOC_FREE(buf);
304 DBG_ERR("%s: Failed to get volfile for volume (%s)\n",
305 volume, strerror(errno));
306 return -1;
309 option = talloc_asprintf(mem_ctx, "volume %s-write-behind", volume);
310 if (option == NULL) {
311 TALLOC_FREE(buf);
312 return -1;
316 * file_lines_parse() plays horrible tricks with
317 * the passed-in talloc pointers and the hierarchy
318 * which makes freeing hard to get right.
320 * As we know mem_ctx is freed by the caller, after
321 * this point don't free on exit and let the caller
322 * handle it. This violates good Samba coding practice
323 * but we know we're not leaking here.
326 lines = file_lines_parse(buf,
327 newlen,
328 &numlines,
329 mem_ctx);
330 if (lines == NULL || numlines <= 0) {
331 return -1;
333 /* On success, buf is now a talloc child of lines !! */
335 for (i=0; i < numlines; i++) {
336 if (strequal(lines[i], option)) {
337 write_behind_present = true;
338 break;
342 if (write_behind_present) {
343 DBG_ERR("Write behind translator is enabled for "
344 "volume (%s), refusing to connect! "
345 "Please turn off the write behind translator by calling "
346 "'gluster volume set %s performance.write-behind off' "
347 "on the commandline. "
348 "Check the vfs_glusterfs(8) manpage for "
349 "further details.\n",
350 volume, volume);
351 return -1;
354 return 0;
357 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
358 const char *service,
359 const char *user)
361 const struct loadparm_substitution *lp_sub =
362 loadparm_s3_global_substitution();
363 const char *volfile_servers;
364 const char *volume;
365 char *logfile;
366 int loglevel;
367 glfs_t *fs = NULL;
368 TALLOC_CTX *tmp_ctx;
369 int ret = 0;
370 bool write_behind_pass_through_set = false;
372 tmp_ctx = talloc_new(NULL);
373 if (tmp_ctx == NULL) {
374 ret = -1;
375 goto done;
377 logfile = lp_parm_substituted_string(tmp_ctx,
378 lp_sub,
379 SNUM(handle->conn),
380 "glusterfs",
381 "logfile",
382 NULL);
384 loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
386 volfile_servers = lp_parm_substituted_string(tmp_ctx,
387 lp_sub,
388 SNUM(handle->conn),
389 "glusterfs",
390 "volfile_server",
391 NULL);
392 if (volfile_servers == NULL) {
393 volfile_servers = DEFAULT_VOLFILE_SERVER;
396 volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
397 NULL);
398 if (volume == NULL) {
399 volume = service;
402 fs = glfs_find_preopened(volume, handle->conn->connectpath);
403 if (fs) {
404 goto done;
407 fs = glfs_new(volume);
408 if (fs == NULL) {
409 ret = -1;
410 goto done;
413 ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
414 if (ret < 0) {
415 DBG_ERR("Failed to set volfile_servers from list %s\n",
416 volfile_servers);
417 goto done;
420 ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
421 "true");
422 if (ret < 0) {
423 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
424 goto done;
427 ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-selinux",
428 "true");
429 if (ret < 0) {
430 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
431 goto done;
434 ret = glfs_set_xlator_option(fs, "*-snapview-client",
435 "snapdir-entry-path",
436 handle->conn->connectpath);
437 if (ret < 0) {
438 DEBUG(0, ("%s: Failed to set xlator option:"
439 " snapdir-entry-path\n", volume));
440 goto done;
443 #ifdef HAVE_GFAPI_VER_7_9
444 ret = glfs_set_xlator_option(fs, "*-write-behind", "pass-through",
445 "true");
446 if (ret < 0) {
447 DBG_ERR("%s: Failed to set xlator option: pass-through\n",
448 volume);
449 goto done;
451 write_behind_pass_through_set = true;
452 #endif
454 ret = glfs_set_logging(fs, logfile, loglevel);
455 if (ret < 0) {
456 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
457 volume, logfile, loglevel));
458 goto done;
461 ret = glfs_init(fs);
462 if (ret < 0) {
463 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
464 volume, strerror(errno)));
465 goto done;
468 if (!write_behind_pass_through_set) {
469 ret = check_for_write_behind_translator(tmp_ctx, fs, volume);
470 if (ret < 0) {
471 goto done;
475 ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
476 if (ret < 0) {
477 DEBUG(0, ("%s: Failed to register volume (%s)\n",
478 volume, strerror(errno)));
479 goto done;
483 * The shadow_copy2 module will fail to export subdirectories
484 * of a gluster volume unless we specify the mount point,
485 * because the detection fails if the file system is not
486 * locally mounted:
487 * https://bugzilla.samba.org/show_bug.cgi?id=13091
489 lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
492 * Unless we have an async implementation of getxattrat turn this off.
494 lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
496 done:
497 if (ret < 0) {
498 if (fs)
499 glfs_fini(fs);
500 } else {
501 DBG_ERR("%s: Initialized volume from servers %s\n",
502 volume, volfile_servers);
503 handle->data = fs;
505 talloc_free(tmp_ctx);
506 return ret;
509 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
511 glfs_t *fs = NULL;
513 fs = handle->data;
515 glfs_clear_preopened(fs);
518 static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
519 const struct smb_filename *smb_fname,
520 uint64_t *bsize_p,
521 uint64_t *dfree_p,
522 uint64_t *dsize_p)
524 struct statvfs statvfs = { 0, };
525 int ret;
527 ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
528 if (ret < 0) {
529 return -1;
532 if (bsize_p != NULL) {
533 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
535 if (dfree_p != NULL) {
536 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
538 if (dsize_p != NULL) {
539 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
542 return (uint64_t)statvfs.f_bavail;
545 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
546 const struct smb_filename *smb_fname,
547 enum SMB_QUOTA_TYPE qtype,
548 unid_t id,
549 SMB_DISK_QUOTA *qt)
551 errno = ENOSYS;
552 return -1;
555 static int
556 vfs_gluster_set_quota(struct vfs_handle_struct *handle,
557 enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
559 errno = ENOSYS;
560 return -1;
563 static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
564 const struct smb_filename *smb_fname,
565 struct vfs_statvfs_struct *vfs_statvfs)
567 struct statvfs statvfs = { 0, };
568 int ret;
570 ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
571 if (ret < 0) {
572 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
573 smb_fname->base_name, strerror(errno)));
574 return -1;
577 ZERO_STRUCTP(vfs_statvfs);
579 vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
580 vfs_statvfs->BlockSize = statvfs.f_bsize;
581 vfs_statvfs->TotalBlocks = statvfs.f_blocks;
582 vfs_statvfs->BlocksAvail = statvfs.f_bfree;
583 vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
584 vfs_statvfs->TotalFileNodes = statvfs.f_files;
585 vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
586 vfs_statvfs->FsIdentifier = statvfs.f_fsid;
587 vfs_statvfs->FsCapabilities =
588 FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
590 return ret;
593 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
594 enum timestamp_set_resolution *p_ts_res)
596 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
598 #ifdef HAVE_GFAPI_VER_6
599 caps |= FILE_SUPPORTS_SPARSE_FILES;
600 #endif
602 #ifdef STAT_HAVE_NSEC
603 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
604 #endif
606 return caps;
609 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
610 const files_struct *fsp)
612 glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
613 if (glfd == NULL) {
614 DBG_INFO("Failed to fetch fsp extension\n");
615 return NULL;
617 if (*glfd == NULL) {
618 DBG_INFO("Empty glfs_fd_t pointer\n");
619 return NULL;
622 return *glfd;
625 static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
626 files_struct *fsp, const char *mask,
627 uint32_t attributes)
629 glfs_fd_t *glfd = NULL;
631 glfd = glfs_opendir(handle->data, fsp->fsp_name->base_name);
632 if (glfd == NULL) {
633 return NULL;
636 return (DIR *)glfd;
639 static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
641 int ret;
643 START_PROFILE(syscall_closedir);
644 ret = glfs_closedir((void *)dirp);
645 END_PROFILE(syscall_closedir);
647 return ret;
650 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
651 struct files_struct *dirfsp,
652 DIR *dirp)
654 static char direntbuf[512];
655 int ret;
656 struct dirent *dirent = 0;
658 START_PROFILE(syscall_readdir);
660 ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
662 if ((ret < 0) || (dirent == NULL)) {
663 END_PROFILE(syscall_readdir);
664 return NULL;
667 END_PROFILE(syscall_readdir);
668 return dirent;
671 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
673 START_PROFILE(syscall_rewinddir);
674 glfs_seekdir((void *)dirp, 0);
675 END_PROFILE(syscall_rewinddir);
678 static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
679 struct files_struct *dirfsp,
680 const struct smb_filename *smb_fname,
681 mode_t mode)
683 int ret;
685 #ifdef HAVE_GFAPI_VER_7_11
686 glfs_fd_t *pglfd = NULL;
688 START_PROFILE(syscall_mkdirat);
690 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
691 if (pglfd == NULL) {
692 END_PROFILE(syscall_mkdirat);
693 DBG_ERR("Failed to fetch gluster fd\n");
694 return -1;
697 ret = glfs_mkdirat(pglfd, smb_fname->base_name, mode);
698 #else
699 struct smb_filename *full_fname = NULL;
701 START_PROFILE(syscall_mkdirat);
703 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
704 dirfsp,
705 smb_fname);
706 if (full_fname == NULL) {
707 END_PROFILE(syscall_mkdirat);
708 return -1;
711 ret = glfs_mkdir(handle->data, full_fname->base_name, mode);
713 TALLOC_FREE(full_fname);
714 #endif
716 END_PROFILE(syscall_mkdirat);
718 return ret;
721 static int vfs_gluster_openat(struct vfs_handle_struct *handle,
722 const struct files_struct *dirfsp,
723 const struct smb_filename *smb_fname,
724 files_struct *fsp,
725 const struct vfs_open_how *how)
727 int flags = how->flags;
728 struct smb_filename *full_fname = NULL;
729 bool have_opath = false;
730 bool became_root = false;
731 glfs_fd_t *glfd = NULL;
732 glfs_fd_t *pglfd = NULL;
733 glfs_fd_t **p_tmp;
735 START_PROFILE(syscall_openat);
737 if (how->resolve != 0) {
738 END_PROFILE(syscall_openat);
739 errno = ENOSYS;
740 return -1;
743 p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
744 if (p_tmp == NULL) {
745 END_PROFILE(syscall_openat);
746 errno = ENOMEM;
747 return -1;
750 #ifdef O_PATH
751 have_opath = true;
752 if (fsp->fsp_flags.is_pathref) {
753 flags |= O_PATH;
755 #endif
757 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
758 dirfsp,
759 smb_fname);
760 if (full_fname == NULL) {
761 END_PROFILE(syscall_openat);
762 return -1;
765 if (fsp->fsp_flags.is_pathref && !have_opath) {
766 become_root();
767 became_root = true;
770 if (fsp_get_pathref_fd(dirfsp) != AT_FDCWD) {
771 #ifdef HAVE_GFAPI_VER_7_11
773 * Fetch Gluster fd for parent directory using dirfsp
774 * before calling glfs_openat();
776 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
777 if (pglfd == NULL) {
778 END_PROFILE(syscall_openat);
779 DBG_ERR("Failed to fetch gluster fd\n");
780 return -1;
783 glfd = glfs_openat(pglfd,
784 smb_fname->base_name,
785 flags,
786 how->mode);
787 #else
789 * Replace smb_fname with full_path constructed above.
791 smb_fname = full_fname;
792 #endif
795 if (pglfd == NULL) {
797 * smb_fname can either be a full_path or the same one
798 * as received from the caller. In the latter case we
799 * are operating at current working directory.
801 if (flags & O_CREAT) {
802 glfd = glfs_creat(handle->data,
803 smb_fname->base_name,
804 flags,
805 how->mode);
806 } else {
807 glfd = glfs_open(handle->data,
808 smb_fname->base_name,
809 flags);
813 if (became_root) {
814 unbecome_root();
817 TALLOC_FREE(full_fname);
819 fsp->fsp_flags.have_proc_fds = false;
821 if (glfd == NULL) {
822 END_PROFILE(syscall_openat);
823 /* no extension destroy_fn, so no need to save errno */
824 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
825 return -1;
828 *p_tmp = glfd;
830 END_PROFILE(syscall_openat);
831 /* An arbitrary value for error reporting, so you know its us. */
832 return 13371337;
835 static int vfs_gluster_close(struct vfs_handle_struct *handle,
836 files_struct *fsp)
838 int ret;
839 glfs_fd_t *glfd = NULL;
841 START_PROFILE(syscall_close);
843 glfd = vfs_gluster_fetch_glfd(handle, fsp);
844 if (glfd == NULL) {
845 END_PROFILE(syscall_close);
846 DBG_ERR("Failed to fetch gluster fd\n");
847 return -1;
850 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
852 ret = glfs_close(glfd);
853 END_PROFILE(syscall_close);
855 return ret;
858 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
859 files_struct *fsp, void *data, size_t n,
860 off_t offset)
862 ssize_t ret;
863 glfs_fd_t *glfd = NULL;
865 START_PROFILE_BYTES(syscall_pread, n);
867 glfd = vfs_gluster_fetch_glfd(handle, fsp);
868 if (glfd == NULL) {
869 END_PROFILE_BYTES(syscall_pread);
870 DBG_ERR("Failed to fetch gluster fd\n");
871 return -1;
874 #ifdef HAVE_GFAPI_VER_7_6
875 ret = glfs_pread(glfd, data, n, offset, 0, NULL);
876 #else
877 ret = glfs_pread(glfd, data, n, offset, 0);
878 #endif
879 END_PROFILE_BYTES(syscall_pread);
881 return ret;
884 struct vfs_gluster_pread_state {
885 ssize_t ret;
886 glfs_fd_t *fd;
887 void *buf;
888 size_t count;
889 off_t offset;
891 struct vfs_aio_state vfs_aio_state;
892 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
895 static void vfs_gluster_pread_do(void *private_data);
896 static void vfs_gluster_pread_done(struct tevent_req *subreq);
897 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
899 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
900 *handle, TALLOC_CTX *mem_ctx,
901 struct tevent_context *ev,
902 files_struct *fsp,
903 void *data, size_t n,
904 off_t offset)
906 struct vfs_gluster_pread_state *state;
907 struct tevent_req *req, *subreq;
909 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
910 if (glfd == NULL) {
911 DBG_ERR("Failed to fetch gluster fd\n");
912 return NULL;
915 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
916 if (req == NULL) {
917 return NULL;
920 state->ret = -1;
921 state->fd = glfd;
922 state->buf = data;
923 state->count = n;
924 state->offset = offset;
926 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
927 state->profile_bytes, n);
928 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
930 subreq = pthreadpool_tevent_job_send(
931 state, ev, handle->conn->sconn->pool,
932 vfs_gluster_pread_do, state);
933 if (tevent_req_nomem(subreq, req)) {
934 return tevent_req_post(req, ev);
936 tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
938 talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
940 return req;
943 static void vfs_gluster_pread_do(void *private_data)
945 struct vfs_gluster_pread_state *state = talloc_get_type_abort(
946 private_data, struct vfs_gluster_pread_state);
947 struct timespec start_time;
948 struct timespec end_time;
950 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
952 PROFILE_TIMESTAMP(&start_time);
954 do {
955 #ifdef HAVE_GFAPI_VER_7_6
956 state->ret = glfs_pread(state->fd, state->buf, state->count,
957 state->offset, 0, NULL);
958 #else
959 state->ret = glfs_pread(state->fd, state->buf, state->count,
960 state->offset, 0);
961 #endif
962 } while ((state->ret == -1) && (errno == EINTR));
964 if (state->ret == -1) {
965 state->vfs_aio_state.error = errno;
968 PROFILE_TIMESTAMP(&end_time);
970 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
972 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
975 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
977 return -1;
980 static void vfs_gluster_pread_done(struct tevent_req *subreq)
982 struct tevent_req *req = tevent_req_callback_data(
983 subreq, struct tevent_req);
984 struct vfs_gluster_pread_state *state = tevent_req_data(
985 req, struct vfs_gluster_pread_state);
986 int ret;
988 ret = pthreadpool_tevent_job_recv(subreq);
989 TALLOC_FREE(subreq);
990 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
991 talloc_set_destructor(state, NULL);
992 if (ret != 0) {
993 if (ret != EAGAIN) {
994 tevent_req_error(req, ret);
995 return;
998 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
999 * means the lower level pthreadpool failed to create a new
1000 * thread. Fallback to sync processing in that case to allow
1001 * some progress for the client.
1003 vfs_gluster_pread_do(state);
1006 tevent_req_done(req);
1009 static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
1010 struct vfs_aio_state *vfs_aio_state)
1012 struct vfs_gluster_pread_state *state = tevent_req_data(
1013 req, struct vfs_gluster_pread_state);
1015 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1016 return -1;
1019 *vfs_aio_state = state->vfs_aio_state;
1020 return state->ret;
1023 struct vfs_gluster_pwrite_state {
1024 ssize_t ret;
1025 glfs_fd_t *fd;
1026 const void *buf;
1027 size_t count;
1028 off_t offset;
1030 struct vfs_aio_state vfs_aio_state;
1031 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1034 static void vfs_gluster_pwrite_do(void *private_data);
1035 static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
1036 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
1038 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
1039 *handle, TALLOC_CTX *mem_ctx,
1040 struct tevent_context *ev,
1041 files_struct *fsp,
1042 const void *data, size_t n,
1043 off_t offset)
1045 struct tevent_req *req, *subreq;
1046 struct vfs_gluster_pwrite_state *state;
1048 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1049 if (glfd == NULL) {
1050 DBG_ERR("Failed to fetch gluster fd\n");
1051 return NULL;
1054 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
1055 if (req == NULL) {
1056 return NULL;
1059 state->ret = -1;
1060 state->fd = glfd;
1061 state->buf = data;
1062 state->count = n;
1063 state->offset = offset;
1065 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1066 state->profile_bytes, n);
1067 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1069 subreq = pthreadpool_tevent_job_send(
1070 state, ev, handle->conn->sconn->pool,
1071 vfs_gluster_pwrite_do, state);
1072 if (tevent_req_nomem(subreq, req)) {
1073 return tevent_req_post(req, ev);
1075 tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
1077 talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
1079 return req;
1082 static void vfs_gluster_pwrite_do(void *private_data)
1084 struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
1085 private_data, struct vfs_gluster_pwrite_state);
1086 struct timespec start_time;
1087 struct timespec end_time;
1089 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1091 PROFILE_TIMESTAMP(&start_time);
1093 do {
1094 #ifdef HAVE_GFAPI_VER_7_6
1095 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1096 state->offset, 0, NULL, NULL);
1097 #else
1098 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1099 state->offset, 0);
1100 #endif
1101 } while ((state->ret == -1) && (errno == EINTR));
1103 if (state->ret == -1) {
1104 state->vfs_aio_state.error = errno;
1107 PROFILE_TIMESTAMP(&end_time);
1109 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1111 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1114 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
1116 return -1;
1119 static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
1121 struct tevent_req *req = tevent_req_callback_data(
1122 subreq, struct tevent_req);
1123 struct vfs_gluster_pwrite_state *state = tevent_req_data(
1124 req, struct vfs_gluster_pwrite_state);
1125 int ret;
1127 ret = pthreadpool_tevent_job_recv(subreq);
1128 TALLOC_FREE(subreq);
1129 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1130 talloc_set_destructor(state, NULL);
1131 if (ret != 0) {
1132 if (ret != EAGAIN) {
1133 tevent_req_error(req, ret);
1134 return;
1137 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1138 * means the lower level pthreadpool failed to create a new
1139 * thread. Fallback to sync processing in that case to allow
1140 * some progress for the client.
1142 vfs_gluster_pwrite_do(state);
1145 tevent_req_done(req);
1148 static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
1149 struct vfs_aio_state *vfs_aio_state)
1151 struct vfs_gluster_pwrite_state *state = tevent_req_data(
1152 req, struct vfs_gluster_pwrite_state);
1154 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1155 return -1;
1158 *vfs_aio_state = state->vfs_aio_state;
1160 return state->ret;
1163 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
1164 files_struct *fsp, const void *data,
1165 size_t n, off_t offset)
1167 ssize_t ret;
1168 glfs_fd_t *glfd = NULL;
1170 START_PROFILE_BYTES(syscall_pwrite, n);
1172 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1173 if (glfd == NULL) {
1174 END_PROFILE_BYTES(syscall_pwrite);
1175 DBG_ERR("Failed to fetch gluster fd\n");
1176 return -1;
1179 #ifdef HAVE_GFAPI_VER_7_6
1180 ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1181 #else
1182 ret = glfs_pwrite(glfd, data, n, offset, 0);
1183 #endif
1184 END_PROFILE_BYTES(syscall_pwrite);
1186 return ret;
1189 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1190 files_struct *fsp, off_t offset, int whence)
1192 off_t ret = 0;
1193 glfs_fd_t *glfd = NULL;
1195 START_PROFILE(syscall_lseek);
1197 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1198 if (glfd == NULL) {
1199 END_PROFILE(syscall_lseek);
1200 DBG_ERR("Failed to fetch gluster fd\n");
1201 return -1;
1204 ret = glfs_lseek(glfd, offset, whence);
1205 END_PROFILE(syscall_lseek);
1207 return ret;
1210 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1211 files_struct *fromfsp,
1212 const DATA_BLOB *hdr,
1213 off_t offset, size_t n)
1215 errno = ENOTSUP;
1216 return -1;
1219 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1220 int fromfd, files_struct *tofsp,
1221 off_t offset, size_t n)
1223 errno = ENOTSUP;
1224 return -1;
1227 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1228 files_struct *srcfsp,
1229 const struct smb_filename *smb_fname_src,
1230 files_struct *dstfsp,
1231 const struct smb_filename *smb_fname_dst)
1233 int ret;
1235 #ifdef HAVE_GFAPI_VER_7_11
1236 glfs_fd_t *src_pglfd = NULL;
1237 glfs_fd_t *dst_pglfd = NULL;
1239 START_PROFILE(syscall_renameat);
1241 src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
1242 if (src_pglfd == NULL) {
1243 END_PROFILE(syscall_renameat);
1244 DBG_ERR("Failed to fetch gluster fd\n");
1245 return -1;
1248 dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
1249 if (dst_pglfd == NULL) {
1250 END_PROFILE(syscall_renameat);
1251 DBG_ERR("Failed to fetch gluster fd\n");
1252 return -1;
1255 ret = glfs_renameat(src_pglfd, smb_fname_src->base_name,
1256 dst_pglfd, smb_fname_dst->base_name);
1257 #else
1258 struct smb_filename *full_fname_src = NULL;
1259 struct smb_filename *full_fname_dst = NULL;
1261 START_PROFILE(syscall_renameat);
1263 full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
1264 srcfsp,
1265 smb_fname_src);
1266 if (full_fname_src == NULL) {
1267 END_PROFILE(syscall_renameat);
1268 errno = ENOMEM;
1269 return -1;
1272 full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
1273 dstfsp,
1274 smb_fname_dst);
1275 if (full_fname_dst == NULL) {
1276 END_PROFILE(syscall_renameat);
1277 TALLOC_FREE(full_fname_src);
1278 errno = ENOMEM;
1279 return -1;
1281 ret = glfs_rename(handle->data,
1282 full_fname_src->base_name,
1283 full_fname_dst->base_name);
1285 TALLOC_FREE(full_fname_src);
1286 TALLOC_FREE(full_fname_dst);
1287 #endif
1289 END_PROFILE(syscall_renameat);
1291 return ret;
1294 struct vfs_gluster_fsync_state {
1295 ssize_t ret;
1296 glfs_fd_t *fd;
1298 struct vfs_aio_state vfs_aio_state;
1299 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1302 static void vfs_gluster_fsync_do(void *private_data);
1303 static void vfs_gluster_fsync_done(struct tevent_req *subreq);
1304 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
1306 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1307 *handle, TALLOC_CTX *mem_ctx,
1308 struct tevent_context *ev,
1309 files_struct *fsp)
1311 struct tevent_req *req, *subreq;
1312 struct vfs_gluster_fsync_state *state;
1314 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1315 if (glfd == NULL) {
1316 DBG_ERR("Failed to fetch gluster fd\n");
1317 return NULL;
1320 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
1321 if (req == NULL) {
1322 return NULL;
1325 state->ret = -1;
1326 state->fd = glfd;
1328 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1329 state->profile_bytes, 0);
1330 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1332 subreq = pthreadpool_tevent_job_send(
1333 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
1334 if (tevent_req_nomem(subreq, req)) {
1335 return tevent_req_post(req, ev);
1337 tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
1339 talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
1341 return req;
1344 static void vfs_gluster_fsync_do(void *private_data)
1346 struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
1347 private_data, struct vfs_gluster_fsync_state);
1348 struct timespec start_time;
1349 struct timespec end_time;
1351 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1353 PROFILE_TIMESTAMP(&start_time);
1355 do {
1356 #ifdef HAVE_GFAPI_VER_7_6
1357 state->ret = glfs_fsync(state->fd, NULL, NULL);
1358 #else
1359 state->ret = glfs_fsync(state->fd);
1360 #endif
1361 } while ((state->ret == -1) && (errno == EINTR));
1363 if (state->ret == -1) {
1364 state->vfs_aio_state.error = errno;
1367 PROFILE_TIMESTAMP(&end_time);
1369 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1371 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1374 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
1376 return -1;
1379 static void vfs_gluster_fsync_done(struct tevent_req *subreq)
1381 struct tevent_req *req = tevent_req_callback_data(
1382 subreq, struct tevent_req);
1383 struct vfs_gluster_fsync_state *state = tevent_req_data(
1384 req, struct vfs_gluster_fsync_state);
1385 int ret;
1387 ret = pthreadpool_tevent_job_recv(subreq);
1388 TALLOC_FREE(subreq);
1389 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1390 talloc_set_destructor(state, NULL);
1391 if (ret != 0) {
1392 if (ret != EAGAIN) {
1393 tevent_req_error(req, ret);
1394 return;
1397 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1398 * means the lower level pthreadpool failed to create a new
1399 * thread. Fallback to sync processing in that case to allow
1400 * some progress for the client.
1402 vfs_gluster_fsync_do(state);
1405 tevent_req_done(req);
1408 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1409 struct vfs_aio_state *vfs_aio_state)
1411 struct vfs_gluster_fsync_state *state = tevent_req_data(
1412 req, struct vfs_gluster_fsync_state);
1414 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1415 return -1;
1418 *vfs_aio_state = state->vfs_aio_state;
1419 return state->ret;
1422 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1423 struct smb_filename *smb_fname)
1425 struct stat st;
1426 int ret;
1428 START_PROFILE(syscall_stat);
1429 ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1430 if (ret == 0) {
1431 smb_stat_ex_from_stat(&smb_fname->st, &st);
1433 if (ret < 0 && errno != ENOENT) {
1434 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1435 smb_fname->base_name, strerror(errno)));
1437 END_PROFILE(syscall_stat);
1439 return ret;
1442 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1443 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1445 struct stat st;
1446 int ret;
1447 glfs_fd_t *glfd = NULL;
1449 START_PROFILE(syscall_fstat);
1451 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1452 if (glfd == NULL) {
1453 END_PROFILE(syscall_fstat);
1454 DBG_ERR("Failed to fetch gluster fd\n");
1455 return -1;
1458 ret = glfs_fstat(glfd, &st);
1459 if (ret == 0) {
1460 smb_stat_ex_from_stat(sbuf, &st);
1462 if (ret < 0) {
1463 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1464 fsp_get_io_fd(fsp), strerror(errno)));
1466 END_PROFILE(syscall_fstat);
1468 return ret;
1471 static int vfs_gluster_fstatat(struct vfs_handle_struct *handle,
1472 const struct files_struct *dirfsp,
1473 const struct smb_filename *smb_fname,
1474 SMB_STRUCT_STAT *sbuf,
1475 int flags)
1477 struct stat st;
1478 int ret;
1480 #ifdef HAVE_GFAPI_VER_7_11
1481 glfs_fd_t *pglfd = NULL;
1483 START_PROFILE(syscall_fstatat);
1485 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
1486 if (pglfd == NULL) {
1487 END_PROFILE(syscall_fstatat);
1488 DBG_ERR("Failed to fetch gluster fd\n");
1489 return -1;
1492 ret = glfs_fstatat(pglfd, smb_fname->base_name, &st, flags);
1493 #else
1494 struct smb_filename *full_fname = NULL;
1496 START_PROFILE(syscall_fstatat);
1498 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1499 dirfsp,
1500 smb_fname);
1501 if (full_fname == NULL) {
1502 END_PROFILE(syscall_fstatat);
1503 return -1;
1506 ret = glfs_stat(handle->data, full_fname->base_name, &st);
1508 TALLOC_FREE(full_fname->base_name);
1509 #endif
1511 if (ret == 0) {
1512 smb_stat_ex_from_stat(sbuf, &st);
1515 END_PROFILE(syscall_fstatat);
1517 return ret;
1520 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1521 struct smb_filename *smb_fname)
1523 struct stat st;
1524 int ret;
1526 START_PROFILE(syscall_lstat);
1527 ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1528 if (ret == 0) {
1529 smb_stat_ex_from_stat(&smb_fname->st, &st);
1531 if (ret < 0 && errno != ENOENT) {
1532 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1533 smb_fname->base_name, strerror(errno)));
1535 END_PROFILE(syscall_lstat);
1537 return ret;
1540 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1541 files_struct *fsp,
1542 const SMB_STRUCT_STAT *sbuf)
1544 uint64_t ret;
1546 START_PROFILE(syscall_get_alloc_size);
1547 ret = sbuf->st_ex_blocks * 512;
1548 END_PROFILE(syscall_get_alloc_size);
1550 return ret;
1553 static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
1554 struct files_struct *dirfsp,
1555 const struct smb_filename *smb_fname,
1556 int flags)
1558 int ret;
1560 #ifdef HAVE_GFAPI_VER_7_11
1561 glfs_fd_t *pglfd = NULL;
1563 START_PROFILE(syscall_unlinkat);
1565 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
1566 if (pglfd == NULL) {
1567 END_PROFILE(syscall_unlinkat);
1568 DBG_ERR("Failed to fetch gluster fd\n");
1569 return -1;
1572 ret = glfs_unlinkat(pglfd, smb_fname->base_name, flags);
1573 #else
1574 struct smb_filename *full_fname = NULL;
1576 START_PROFILE(syscall_unlinkat);
1578 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1579 dirfsp,
1580 smb_fname);
1581 if (full_fname == NULL) {
1582 END_PROFILE(syscall_unlinkat);
1583 return -1;
1586 if (flags & AT_REMOVEDIR) {
1587 ret = glfs_rmdir(handle->data, full_fname->base_name);
1588 } else {
1589 ret = glfs_unlink(handle->data, full_fname->base_name);
1592 TALLOC_FREE(full_fname);
1593 #endif
1595 END_PROFILE(syscall_unlinkat);
1597 return ret;
1600 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1601 files_struct *fsp, mode_t mode)
1603 int ret;
1604 glfs_fd_t *glfd = NULL;
1606 START_PROFILE(syscall_fchmod);
1608 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1609 if (glfd == NULL) {
1610 END_PROFILE(syscall_fchmod);
1611 DBG_ERR("Failed to fetch gluster fd\n");
1612 return -1;
1615 if (!fsp->fsp_flags.is_pathref) {
1617 * We can use an io_fd to remove xattrs.
1619 ret = glfs_fchmod(glfd, mode);
1620 } else {
1622 * This is no longer a handle based call.
1624 ret = glfs_chmod(handle->data, fsp->fsp_name->base_name, mode);
1626 END_PROFILE(syscall_fchmod);
1628 return ret;
1631 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1632 files_struct *fsp, uid_t uid, gid_t gid)
1634 int ret;
1635 glfs_fd_t *glfd = NULL;
1637 START_PROFILE(syscall_fchown);
1639 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1640 if (glfd == NULL) {
1641 END_PROFILE(syscall_fchown);
1642 DBG_ERR("Failed to fetch gluster fd\n");
1643 return -1;
1646 ret = glfs_fchown(glfd, uid, gid);
1647 END_PROFILE(syscall_fchown);
1649 return ret;
1652 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1653 const struct smb_filename *smb_fname,
1654 uid_t uid,
1655 gid_t gid)
1657 int ret;
1659 START_PROFILE(syscall_lchown);
1660 ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1661 END_PROFILE(syscall_lchown);
1663 return ret;
1666 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1667 const struct smb_filename *smb_fname)
1669 int ret;
1671 START_PROFILE(syscall_chdir);
1672 ret = glfs_chdir(handle->data, smb_fname->base_name);
1673 END_PROFILE(syscall_chdir);
1675 return ret;
1678 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1679 TALLOC_CTX *ctx)
1681 char cwd[PATH_MAX] = { '\0' };
1682 char *ret;
1683 struct smb_filename *smb_fname = NULL;
1685 START_PROFILE(syscall_getwd);
1687 ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1688 END_PROFILE(syscall_getwd);
1690 if (ret == NULL) {
1691 return NULL;
1693 smb_fname = synthetic_smb_fname(ctx,
1694 ret,
1695 NULL,
1696 NULL,
1699 return smb_fname;
1702 static int vfs_gluster_fntimes(struct vfs_handle_struct *handle,
1703 files_struct *fsp,
1704 struct smb_file_time *ft)
1706 int ret = -1;
1707 struct timespec times[2];
1708 glfs_fd_t *glfd = NULL;
1710 START_PROFILE(syscall_fntimes);
1712 if (is_omit_timespec(&ft->atime)) {
1713 times[0].tv_sec = fsp->fsp_name->st.st_ex_atime.tv_sec;
1714 times[0].tv_nsec = fsp->fsp_name->st.st_ex_atime.tv_nsec;
1715 } else {
1716 times[0].tv_sec = ft->atime.tv_sec;
1717 times[0].tv_nsec = ft->atime.tv_nsec;
1720 if (is_omit_timespec(&ft->mtime)) {
1721 times[1].tv_sec = fsp->fsp_name->st.st_ex_mtime.tv_sec;
1722 times[1].tv_nsec = fsp->fsp_name->st.st_ex_mtime.tv_nsec;
1723 } else {
1724 times[1].tv_sec = ft->mtime.tv_sec;
1725 times[1].tv_nsec = ft->mtime.tv_nsec;
1728 if ((timespec_compare(&times[0],
1729 &fsp->fsp_name->st.st_ex_atime) == 0) &&
1730 (timespec_compare(&times[1],
1731 &fsp->fsp_name->st.st_ex_mtime) == 0)) {
1732 END_PROFILE(syscall_fntimes);
1733 return 0;
1736 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1737 if (glfd == NULL) {
1738 END_PROFILE(syscall_fntimes);
1739 DBG_ERR("Failed to fetch gluster fd\n");
1740 return -1;
1743 if (!fsp->fsp_flags.is_pathref) {
1744 ret = glfs_futimens(glfd, times);
1745 } else {
1746 ret = glfs_utimens(handle->data,
1747 fsp->fsp_name->base_name,
1748 times);
1750 END_PROFILE(syscall_fntimes);
1752 return ret;
1755 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1756 files_struct *fsp, off_t offset)
1758 int ret;
1759 glfs_fd_t *glfd = NULL;
1761 START_PROFILE(syscall_ftruncate);
1763 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1764 if (glfd == NULL) {
1765 END_PROFILE(syscall_ftruncate);
1766 DBG_ERR("Failed to fetch gluster fd\n");
1767 return -1;
1770 #ifdef HAVE_GFAPI_VER_7_6
1771 ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1772 #else
1773 ret = glfs_ftruncate(glfd, offset);
1774 #endif
1775 END_PROFILE(syscall_ftruncate);
1777 return ret;
1780 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1781 struct files_struct *fsp,
1782 uint32_t mode,
1783 off_t offset, off_t len)
1785 int ret;
1786 #ifdef HAVE_GFAPI_VER_6
1787 glfs_fd_t *glfd = NULL;
1788 int keep_size, punch_hole;
1790 START_PROFILE(syscall_fallocate);
1792 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1793 if (glfd == NULL) {
1794 END_PROFILE(syscall_fallocate);
1795 DBG_ERR("Failed to fetch gluster fd\n");
1796 return -1;
1799 keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1800 punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1802 mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1803 if (mode != 0) {
1804 END_PROFILE(syscall_fallocate);
1805 errno = ENOTSUP;
1806 return -1;
1809 if (punch_hole) {
1810 ret = glfs_discard(glfd, offset, len);
1811 if (ret != 0) {
1812 DBG_DEBUG("glfs_discard failed: %s\n",
1813 strerror(errno));
1817 ret = glfs_fallocate(glfd, keep_size, offset, len);
1818 END_PROFILE(syscall_fallocate);
1819 #else
1820 errno = ENOTSUP;
1821 ret = -1;
1822 #endif
1823 return ret;
1826 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1827 TALLOC_CTX *ctx,
1828 const struct smb_filename *smb_fname)
1830 char *result = NULL;
1831 struct smb_filename *result_fname = NULL;
1832 char *resolved_path = NULL;
1834 START_PROFILE(syscall_realpath);
1836 resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1837 if (resolved_path == NULL) {
1838 END_PROFILE(syscall_realpath);
1839 errno = ENOMEM;
1840 return NULL;
1843 result = glfs_realpath(handle->data,
1844 smb_fname->base_name,
1845 resolved_path);
1846 if (result != NULL) {
1847 result_fname = synthetic_smb_fname(ctx,
1848 result,
1849 NULL,
1850 NULL,
1855 SAFE_FREE(resolved_path);
1856 END_PROFILE(syscall_realpath);
1858 return result_fname;
1861 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1862 files_struct *fsp, int op, off_t offset,
1863 off_t count, int type)
1865 struct flock flock = { 0, };
1866 int ret;
1867 glfs_fd_t *glfd = NULL;
1868 bool ok = false;
1870 START_PROFILE(syscall_fcntl_lock);
1872 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1873 if (glfd == NULL) {
1874 DBG_ERR("Failed to fetch gluster fd\n");
1875 ok = false;
1876 goto out;
1879 flock.l_type = type;
1880 flock.l_whence = SEEK_SET;
1881 flock.l_start = offset;
1882 flock.l_len = count;
1883 flock.l_pid = 0;
1885 ret = glfs_posix_lock(glfd, op, &flock);
1887 if (op == F_GETLK) {
1888 /* lock query, true if someone else has locked */
1889 if ((ret != -1) &&
1890 (flock.l_type != F_UNLCK) &&
1891 (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1892 ok = true;
1893 goto out;
1895 /* not me */
1896 ok = false;
1897 goto out;
1900 if (ret == -1) {
1901 ok = false;
1902 goto out;
1905 ok = true;
1906 out:
1907 END_PROFILE(syscall_fcntl_lock);
1909 return ok;
1912 static int vfs_gluster_filesystem_sharemode(struct vfs_handle_struct *handle,
1913 files_struct *fsp,
1914 uint32_t share_access,
1915 uint32_t access_mask)
1917 errno = ENOSYS;
1918 return -1;
1921 static int vfs_gluster_fcntl(vfs_handle_struct *handle,
1922 files_struct *fsp, int cmd, va_list cmd_arg)
1925 * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
1926 * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
1928 if (cmd == F_GETFL) {
1929 return 0;
1930 } else if (cmd == F_SETFL) {
1931 va_list dup_cmd_arg;
1932 int opt;
1934 va_copy(dup_cmd_arg, cmd_arg);
1935 opt = va_arg(dup_cmd_arg, int);
1936 va_end(dup_cmd_arg);
1937 if (opt == 0) {
1938 return 0;
1940 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
1941 goto err_out;
1943 DBG_ERR("unexpected fcntl: %d\n", cmd);
1944 err_out:
1945 errno = EINVAL;
1946 return -1;
1949 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1950 files_struct *fsp, int leasetype)
1952 errno = ENOSYS;
1953 return -1;
1956 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1957 files_struct *fsp, off_t *poffset,
1958 off_t *pcount, int *ptype, pid_t *ppid)
1960 struct flock flock = { 0, };
1961 int ret;
1962 glfs_fd_t *glfd = NULL;
1964 START_PROFILE(syscall_fcntl_getlock);
1966 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1967 if (glfd == NULL) {
1968 END_PROFILE(syscall_fcntl_getlock);
1969 DBG_ERR("Failed to fetch gluster fd\n");
1970 return false;
1973 flock.l_type = *ptype;
1974 flock.l_whence = SEEK_SET;
1975 flock.l_start = *poffset;
1976 flock.l_len = *pcount;
1977 flock.l_pid = 0;
1979 ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1981 if (ret == -1) {
1982 END_PROFILE(syscall_fcntl_getlock);
1983 return false;
1986 *ptype = flock.l_type;
1987 *poffset = flock.l_start;
1988 *pcount = flock.l_len;
1989 *ppid = flock.l_pid;
1990 END_PROFILE(syscall_fcntl_getlock);
1992 return true;
1995 static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
1996 const struct smb_filename *link_target,
1997 struct files_struct *dirfsp,
1998 const struct smb_filename *new_smb_fname)
2000 int ret;
2002 #ifdef HAVE_GFAPI_VER_7_11
2003 glfs_fd_t *pglfd = NULL;
2005 START_PROFILE(syscall_symlinkat);
2007 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2008 if (pglfd == NULL) {
2009 END_PROFILE(syscall_symlinkat);
2010 DBG_ERR("Failed to fetch gluster fd\n");
2011 return -1;
2014 ret = glfs_symlinkat(link_target->base_name,
2015 pglfd,
2016 new_smb_fname->base_name);
2017 #else
2018 struct smb_filename *full_fname = NULL;
2020 START_PROFILE(syscall_symlinkat);
2022 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2023 dirfsp,
2024 new_smb_fname);
2025 if (full_fname == NULL) {
2026 END_PROFILE(syscall_symlinkat);
2027 return -1;
2030 ret = glfs_symlink(handle->data,
2031 link_target->base_name,
2032 full_fname->base_name);
2034 TALLOC_FREE(full_fname);
2035 #endif
2037 END_PROFILE(syscall_symlinkat);
2039 return ret;
2042 static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
2043 const struct files_struct *dirfsp,
2044 const struct smb_filename *smb_fname,
2045 char *buf,
2046 size_t bufsiz)
2048 int ret;
2050 #ifdef HAVE_GFAPI_VER_7_11
2051 glfs_fd_t *pglfd = NULL;
2053 START_PROFILE(syscall_readlinkat);
2055 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2056 if (pglfd == NULL) {
2057 END_PROFILE(syscall_readlinkat);
2058 DBG_ERR("Failed to fetch gluster fd\n");
2059 return -1;
2062 ret = glfs_readlinkat(pglfd, smb_fname->base_name, buf, bufsiz);
2063 #else
2064 struct smb_filename *full_fname = NULL;
2066 START_PROFILE(syscall_readlinkat);
2068 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2069 dirfsp,
2070 smb_fname);
2071 if (full_fname == NULL) {
2072 END_PROFILE(syscall_readlinkat);
2073 return -1;
2076 ret = glfs_readlink(handle->data, full_fname->base_name, buf, bufsiz);
2078 TALLOC_FREE(full_fname);
2079 #endif
2081 END_PROFILE(syscall_readlinkat);
2083 return ret;
2086 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
2087 files_struct *srcfsp,
2088 const struct smb_filename *old_smb_fname,
2089 files_struct *dstfsp,
2090 const struct smb_filename *new_smb_fname,
2091 int flags)
2093 int ret;
2095 #ifdef HAVE_GFAPI_VER_7_11
2096 glfs_fd_t *src_pglfd = NULL;
2097 glfs_fd_t *dst_pglfd = NULL;
2099 START_PROFILE(syscall_linkat);
2101 src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
2102 if (src_pglfd == NULL) {
2103 END_PROFILE(syscall_linkat);
2104 DBG_ERR("Failed to fetch gluster fd\n");
2105 return -1;
2108 dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
2109 if (dst_pglfd == NULL) {
2110 END_PROFILE(syscall_linkat);
2111 DBG_ERR("Failed to fetch gluster fd\n");
2112 return -1;
2115 ret = glfs_linkat(src_pglfd,
2116 old_smb_fname->base_name,
2117 dst_pglfd,
2118 new_smb_fname->base_name,
2119 flags);
2120 #else
2121 struct smb_filename *full_fname_old = NULL;
2122 struct smb_filename *full_fname_new = NULL;
2124 START_PROFILE(syscall_linkat);
2126 full_fname_old = full_path_from_dirfsp_atname(talloc_tos(),
2127 srcfsp,
2128 old_smb_fname);
2129 if (full_fname_old == NULL) {
2130 END_PROFILE(syscall_linkat);
2131 return -1;
2134 full_fname_new = full_path_from_dirfsp_atname(talloc_tos(),
2135 dstfsp,
2136 new_smb_fname);
2137 if (full_fname_new == NULL) {
2138 END_PROFILE(syscall_linkat);
2139 TALLOC_FREE(full_fname_old);
2140 return -1;
2143 ret = glfs_link(handle->data,
2144 full_fname_old->base_name,
2145 full_fname_new->base_name);
2147 TALLOC_FREE(full_fname_old);
2148 TALLOC_FREE(full_fname_new);
2149 #endif
2151 END_PROFILE(syscall_linkat);
2153 return ret;
2156 static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
2157 files_struct *dirfsp,
2158 const struct smb_filename *smb_fname,
2159 mode_t mode,
2160 SMB_DEV_T dev)
2162 int ret;
2164 #ifdef HAVE_GFAPI_VER_7_11
2165 glfs_fd_t *pglfd = NULL;
2167 START_PROFILE(syscall_mknodat);
2169 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2170 if (pglfd == NULL) {
2171 END_PROFILE(syscall_mknodat);
2172 DBG_ERR("Failed to fetch gluster fd\n");
2173 return -1;
2176 ret = glfs_mknodat(pglfd, smb_fname->base_name, mode, dev);
2177 #else
2178 struct smb_filename *full_fname = NULL;
2180 START_PROFILE(syscall_mknodat);
2182 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2183 dirfsp,
2184 smb_fname);
2185 if (full_fname == NULL) {
2186 END_PROFILE(syscall_mknodat);
2187 return -1;
2190 ret = glfs_mknod(handle->data, full_fname->base_name, mode, dev);
2192 TALLOC_FREE(full_fname);
2193 #endif
2195 END_PROFILE(syscall_mknodat);
2197 return ret;
2200 static int vfs_gluster_fchflags(struct vfs_handle_struct *handle,
2201 struct files_struct *fsp,
2202 unsigned int flags)
2204 errno = ENOSYS;
2205 return -1;
2208 static NTSTATUS vfs_gluster_get_real_filename_at(
2209 struct vfs_handle_struct *handle,
2210 struct files_struct *dirfsp,
2211 const char *name,
2212 TALLOC_CTX *mem_ctx,
2213 char **found_name)
2215 int ret;
2216 char key_buf[GLUSTER_NAME_MAX + 64];
2217 char val_buf[GLUSTER_NAME_MAX + 1];
2219 if (strlen(name) >= GLUSTER_NAME_MAX) {
2220 return NT_STATUS_OBJECT_NAME_INVALID;
2223 snprintf(key_buf, GLUSTER_NAME_MAX + 64,
2224 "glusterfs.get_real_filename:%s", name);
2226 ret = glfs_getxattr(handle->data,
2227 dirfsp->fsp_name->base_name,
2228 key_buf,
2229 val_buf,
2230 GLUSTER_NAME_MAX + 1);
2231 if (ret == -1) {
2232 if (errno == ENOATTR) {
2233 errno = ENOENT;
2235 return map_nt_error_from_unix(errno);
2238 *found_name = talloc_strdup(mem_ctx, val_buf);
2239 if (found_name[0] == NULL) {
2240 return NT_STATUS_NO_MEMORY;
2243 return NT_STATUS_OK;
2246 static const char *vfs_gluster_connectpath(
2247 struct vfs_handle_struct *handle,
2248 const struct files_struct *dirfsp,
2249 const struct smb_filename *smb_fname)
2251 return handle->conn->connectpath;
2254 /* EA Operations */
2256 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
2257 files_struct *fsp, const char *name,
2258 void *value, size_t size)
2260 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2261 if (glfd == NULL) {
2262 DBG_ERR("Failed to fetch gluster fd\n");
2263 return -1;
2266 if (!fsp->fsp_flags.is_pathref) {
2268 * We can use an io_fd to retrieve xattr value.
2270 return glfs_fgetxattr(glfd, name, value, size);
2274 * This is no longer a handle based call.
2276 return glfs_getxattr(handle->data,
2277 fsp->fsp_name->base_name,
2278 name,
2279 value,
2280 size);
2283 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
2284 files_struct *fsp, char *list,
2285 size_t size)
2287 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2288 if (glfd == NULL) {
2289 DBG_ERR("Failed to fetch gluster fd\n");
2290 return -1;
2292 if (!fsp->fsp_flags.is_pathref) {
2294 * We can use an io_fd to list xattrs.
2296 return glfs_flistxattr(glfd, list, size);
2297 } else {
2299 * This is no longer a handle based call.
2301 return glfs_listxattr(handle->data,
2302 fsp->fsp_name->base_name,
2303 list,
2304 size);
2308 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
2309 files_struct *fsp, const char *name)
2311 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2312 if (glfd == NULL) {
2313 DBG_ERR("Failed to fetch gluster fd\n");
2314 return -1;
2316 if (!fsp->fsp_flags.is_pathref) {
2318 * We can use an io_fd to remove xattrs.
2320 return glfs_fremovexattr(glfd, name);
2321 } else {
2323 * This is no longer a handle based call.
2325 return glfs_removexattr(handle->data,
2326 fsp->fsp_name->base_name,
2327 name);
2331 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
2332 files_struct *fsp, const char *name,
2333 const void *value, size_t size, int flags)
2335 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2336 if (glfd == NULL) {
2337 DBG_ERR("Failed to fetch gluster fd\n");
2338 return -1;
2341 if (!fsp->fsp_flags.is_pathref) {
2343 * We can use an io_fd to set xattrs.
2345 return glfs_fsetxattr(glfd, name, value, size, flags);
2346 } else {
2348 * This is no longer a handle based call.
2350 return glfs_setxattr(handle->data,
2351 fsp->fsp_name->base_name,
2352 name,
2353 value,
2354 size,
2355 flags);
2359 /* AIO Operations */
2361 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
2362 files_struct *fsp)
2364 return false;
2367 static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
2368 struct files_struct *dirfsp,
2369 const struct smb_filename *smb_fname,
2370 const struct referral *reflist,
2371 size_t referral_count)
2373 TALLOC_CTX *frame = talloc_stackframe();
2374 NTSTATUS status = NT_STATUS_NO_MEMORY;
2375 int ret;
2376 char *msdfs_link = NULL;
2377 #ifdef HAVE_GFAPI_VER_7_11
2378 glfs_fd_t *pglfd = NULL;
2379 #else
2380 struct smb_filename *full_fname = NULL;
2381 #endif
2383 /* Form the msdfs_link contents */
2384 msdfs_link = msdfs_link_string(frame,
2385 reflist,
2386 referral_count);
2387 if (msdfs_link == NULL) {
2388 goto out;
2391 #ifdef HAVE_GFAPI_VER_7_11
2392 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2393 if (pglfd == NULL) {
2394 DBG_ERR("Failed to fetch gluster fd\n");
2395 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2396 goto out;
2399 ret = glfs_symlinkat(msdfs_link, pglfd, smb_fname->base_name);
2400 #else
2401 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2402 dirfsp,
2403 smb_fname);
2404 if (full_fname == NULL) {
2405 goto out;
2408 ret = glfs_symlink(handle->data, msdfs_link, full_fname->base_name);
2410 TALLOC_FREE(full_fname);
2411 #endif
2412 if (ret == 0) {
2413 status = NT_STATUS_OK;
2414 } else {
2415 status = map_nt_error_from_unix(errno);
2418 out:
2420 TALLOC_FREE(frame);
2421 return status;
2425 * Read and return the contents of a DFS redirect given a
2426 * pathname. A caller can pass in NULL for ppreflist and
2427 * preferral_count but still determine if this was a
2428 * DFS redirect point by getting NT_STATUS_OK back
2429 * without incurring the overhead of reading and parsing
2430 * the referral contents.
2433 static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
2434 TALLOC_CTX *mem_ctx,
2435 struct files_struct *dirfsp,
2436 struct smb_filename *smb_fname,
2437 struct referral **ppreflist,
2438 size_t *preferral_count)
2440 NTSTATUS status = NT_STATUS_NO_MEMORY;
2441 size_t bufsize;
2442 char *link_target = NULL;
2443 int referral_len;
2444 bool ok;
2445 #if defined(HAVE_BROKEN_READLINK)
2446 char link_target_buf[PATH_MAX];
2447 #else
2448 char link_target_buf[7];
2449 #endif
2450 struct stat st;
2451 struct smb_filename *full_fname = NULL;
2452 int ret;
2453 #ifdef HAVE_GFAPI_VER_7_11
2454 glfs_fd_t *pglfd = NULL;
2455 #endif
2457 if (is_named_stream(smb_fname)) {
2458 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2459 goto err;
2462 if (ppreflist == NULL && preferral_count == NULL) {
2464 * We're only checking if this is a DFS
2465 * redirect. We don't need to return data.
2467 bufsize = sizeof(link_target_buf);
2468 link_target = link_target_buf;
2469 } else {
2470 bufsize = PATH_MAX;
2471 link_target = talloc_array(mem_ctx, char, bufsize);
2472 if (!link_target) {
2473 goto err;
2477 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2478 dirfsp,
2479 smb_fname);
2480 if (full_fname == NULL) {
2481 status = NT_STATUS_NO_MEMORY;
2482 goto err;
2485 ret = glfs_lstat(handle->data, full_fname->base_name, &st);
2486 if (ret < 0) {
2487 status = map_nt_error_from_unix(errno);
2488 goto err;
2491 #ifdef HAVE_GFAPI_VER_7_11
2492 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2493 if (pglfd == NULL) {
2494 DBG_ERR("Failed to fetch gluster fd\n");
2495 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2498 referral_len = glfs_readlinkat(pglfd,
2499 smb_fname->base_name,
2500 link_target,
2501 bufsize - 1);
2502 #else
2503 referral_len = glfs_readlink(handle->data,
2504 full_fname->base_name,
2505 link_target,
2506 bufsize - 1);
2507 #endif
2508 if (referral_len < 0) {
2509 if (errno == EINVAL) {
2510 DBG_INFO("%s is not a link.\n", full_fname->base_name);
2511 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2512 } else {
2513 status = map_nt_error_from_unix(errno);
2514 DBG_ERR("Error reading "
2515 "msdfs link %s: %s\n",
2516 full_fname->base_name,
2517 strerror(errno));
2519 goto err;
2521 link_target[referral_len] = '\0';
2523 DBG_INFO("%s -> %s\n",
2524 full_fname->base_name,
2525 link_target);
2527 if (!strnequal(link_target, "msdfs:", 6)) {
2528 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2529 goto err;
2532 if (ppreflist == NULL && preferral_count == NULL) {
2533 /* Early return for checking if this is a DFS link. */
2534 TALLOC_FREE(full_fname);
2535 smb_stat_ex_from_stat(&smb_fname->st, &st);
2536 return NT_STATUS_OK;
2539 ok = parse_msdfs_symlink(mem_ctx,
2540 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
2541 link_target,
2542 ppreflist,
2543 preferral_count);
2545 if (ok) {
2546 smb_stat_ex_from_stat(&smb_fname->st, &st);
2547 status = NT_STATUS_OK;
2548 } else {
2549 status = NT_STATUS_NO_MEMORY;
2552 err:
2554 if (link_target != link_target_buf) {
2555 TALLOC_FREE(link_target);
2557 TALLOC_FREE(full_fname);
2558 return status;
2561 static struct vfs_fn_pointers glusterfs_fns = {
2563 /* Disk Operations */
2565 .connect_fn = vfs_gluster_connect,
2566 .disconnect_fn = vfs_gluster_disconnect,
2567 .disk_free_fn = vfs_gluster_disk_free,
2568 .get_quota_fn = vfs_gluster_get_quota,
2569 .set_quota_fn = vfs_gluster_set_quota,
2570 .statvfs_fn = vfs_gluster_statvfs,
2571 .fs_capabilities_fn = vfs_gluster_fs_capabilities,
2573 .get_dfs_referrals_fn = NULL,
2575 /* Directory Operations */
2577 .fdopendir_fn = vfs_gluster_fdopendir,
2578 .readdir_fn = vfs_gluster_readdir,
2579 .rewind_dir_fn = vfs_gluster_rewinddir,
2580 .mkdirat_fn = vfs_gluster_mkdirat,
2581 .closedir_fn = vfs_gluster_closedir,
2583 /* File Operations */
2585 .openat_fn = vfs_gluster_openat,
2586 .create_file_fn = NULL,
2587 .close_fn = vfs_gluster_close,
2588 .pread_fn = vfs_gluster_pread,
2589 .pread_send_fn = vfs_gluster_pread_send,
2590 .pread_recv_fn = vfs_gluster_pread_recv,
2591 .pwrite_fn = vfs_gluster_pwrite,
2592 .pwrite_send_fn = vfs_gluster_pwrite_send,
2593 .pwrite_recv_fn = vfs_gluster_pwrite_recv,
2594 .lseek_fn = vfs_gluster_lseek,
2595 .sendfile_fn = vfs_gluster_sendfile,
2596 .recvfile_fn = vfs_gluster_recvfile,
2597 .renameat_fn = vfs_gluster_renameat,
2598 .fsync_send_fn = vfs_gluster_fsync_send,
2599 .fsync_recv_fn = vfs_gluster_fsync_recv,
2601 .stat_fn = vfs_gluster_stat,
2602 .fstat_fn = vfs_gluster_fstat,
2603 .fstatat_fn = vfs_gluster_fstatat,
2604 .lstat_fn = vfs_gluster_lstat,
2605 .get_alloc_size_fn = vfs_gluster_get_alloc_size,
2606 .unlinkat_fn = vfs_gluster_unlinkat,
2608 .fchmod_fn = vfs_gluster_fchmod,
2609 .fchown_fn = vfs_gluster_fchown,
2610 .lchown_fn = vfs_gluster_lchown,
2611 .chdir_fn = vfs_gluster_chdir,
2612 .getwd_fn = vfs_gluster_getwd,
2613 .fntimes_fn = vfs_gluster_fntimes,
2614 .ftruncate_fn = vfs_gluster_ftruncate,
2615 .fallocate_fn = vfs_gluster_fallocate,
2616 .lock_fn = vfs_gluster_lock,
2617 .filesystem_sharemode_fn = vfs_gluster_filesystem_sharemode,
2618 .fcntl_fn = vfs_gluster_fcntl,
2619 .linux_setlease_fn = vfs_gluster_linux_setlease,
2620 .getlock_fn = vfs_gluster_getlock,
2621 .symlinkat_fn = vfs_gluster_symlinkat,
2622 .readlinkat_fn = vfs_gluster_readlinkat,
2623 .linkat_fn = vfs_gluster_linkat,
2624 .mknodat_fn = vfs_gluster_mknodat,
2625 .realpath_fn = vfs_gluster_realpath,
2626 .fchflags_fn = vfs_gluster_fchflags,
2627 .file_id_create_fn = NULL,
2628 .fstreaminfo_fn = NULL,
2629 .get_real_filename_at_fn = vfs_gluster_get_real_filename_at,
2630 .connectpath_fn = vfs_gluster_connectpath,
2631 .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
2632 .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
2634 .brl_lock_windows_fn = NULL,
2635 .brl_unlock_windows_fn = NULL,
2636 .strict_lock_check_fn = NULL,
2637 .translate_name_fn = NULL,
2638 .fsctl_fn = NULL,
2640 /* NT ACL Operations */
2641 .fget_nt_acl_fn = NULL,
2642 .fset_nt_acl_fn = NULL,
2643 .audit_file_fn = NULL,
2645 /* Posix ACL Operations */
2646 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
2647 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2648 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
2649 .sys_acl_delete_def_fd_fn = posixacl_xattr_acl_delete_def_fd,
2651 /* EA Operations */
2652 .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2653 .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2654 .fgetxattr_fn = vfs_gluster_fgetxattr,
2655 .flistxattr_fn = vfs_gluster_flistxattr,
2656 .fremovexattr_fn = vfs_gluster_fremovexattr,
2657 .fsetxattr_fn = vfs_gluster_fsetxattr,
2659 /* AIO Operations */
2660 .aio_force_fn = vfs_gluster_aio_force,
2662 /* Durable handle Operations */
2663 .durable_cookie_fn = NULL,
2664 .durable_disconnect_fn = NULL,
2665 .durable_reconnect_fn = NULL,
2668 static_decl_vfs;
2669 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
2671 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2672 "glusterfs", &glusterfs_fns);