--- /dev/null
+From f2f684d4eadadeebf725b513bf4945ccf0aa7371 Mon Sep 17 00:00:00 2001
+From: Anand Avati <avati@redhat.com>
+Date: Wed, 29 May 2013 07:21:46 -0400
+Subject: [PATCH 1/9] PATCHSET13: vfs_glusterfs: Samba VFS module for glusterfs
+
+Implement a Samba VFS plugin for glusterfs based on gluster's gfapi.
+This is a "bottom" vfs plugin (not something to be stacked on top of
+another module), and translates (most) calls into closest actions
+on gfapi.
+
+Reviewed-by: Andrew Bartlett <abartlet@samba.org>
+Reviewed-by: Simo Sorce <idra@samba.org>
+Signed-off-by: Anand Avati <avati@redhat.com>
+---
+ source3/Makefile.in | 5 +
+ source3/configure.in | 23 +
+ source3/modules/vfs_glusterfs.c | 1461 +++++++++++++++++++++++++++++++++++++++
+ source3/modules/wscript_build | 9 +
+ source3/wscript | 22 +
+ 5 files changed, 1520 insertions(+)
+ create mode 100644 source3/modules/vfs_glusterfs.c
+
+diff --git a/source3/Makefile.in b/source3/Makefile.in
+index 9e8e03d..27bc43e 100644
+--- a/source3/Makefile.in
++++ b/source3/Makefile.in
+@@ -848,6 +848,7 @@ VFS_SCANNEDONLY_OBJ = modules/vfs_scannedonly.o
+ VFS_CROSSRENAME_OBJ = modules/vfs_crossrename.o
+ VFS_LINUX_XFS_SGID_OBJ = modules/vfs_linux_xfs_sgid.o
+ VFS_TIME_AUDIT_OBJ = modules/vfs_time_audit.o
++VFS_GLUSTERFS_OBJ = modules/vfs_glusterfs.o
+
+ PAM_ERRORS_OBJ = ../libcli/auth/pam_errors.o
+ PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o $(PAM_ERRORS_OBJ)
+@@ -3191,6 +3192,10 @@ bin/time_audit.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_TIME_AUDIT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_TIME_AUDIT_OBJ)
+
++bin/glusterfs.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_GLUSTERFS_OBJ)
++ @echo "Building plugin $@"
++ $(SHLD_MODULE) $(VFS_GLUSTERFS_OBJ) @GLUSTERFS_LIBS@
++
+ #########################################################
+ ## IdMap NSS plugins
+
+diff --git a/source3/configure.in b/source3/configure.in
+index 42c23e3..3cc78e9 100644
+--- a/source3/configure.in
++++ b/source3/configure.in
+@@ -6688,6 +6688,29 @@
+ fi
+
+
++#############
++AC_ARG_ENABLE([glusterfs],
++ AC_HELP_STRING([--disable-glusterfs],[Do not build vfs_glusterfs module]))
++
++GLUTERFS_LIBS=""
++
++if test "x$enable_glusterfs" != "xno"; then
++ PKG_CHECK_MODULES([GLFS], [glusterfs-api >= 4], glfs_found=yes, glfs_found=no)
++fi
++
++if test "x$enable_glusterfs" = "xyes" -a "x$glfs_found" != "xyes"; then
++ echo "GFAPI not found in build system"
++ exit 1
++fi
++
++if test "x$glfs_found" = "xyes"; then
++ CFLAGS="$CFLAGS $GLFS_CFLAGS"
++ GLUSTERFS_LIBS="$GLFS_LIBS"
++ default_shared_modules="$default_shared_modules vfs_glusterfs"
++fi
++AC_SUBST(GLUSTERFS_LIBS)
++
++
+ #################################################
+ # Set pthread stuff
+
+@@ -7007,6 +7030,7 @@
+ SMB_MODULE(vfs_crossrename, \$(VFS_CROSSRENAME_OBJ), "bin/crossrename.$SHLIBEXT", VFS)
+ SMB_MODULE(vfs_linux_xfs_sgid, \$(VFS_LINUX_XFS_SGID_OBJ), "bin/linux_xfs_sgid.$SHLIBEXT", VFS)
+ SMB_MODULE(vfs_time_audit, \$(VFS_TIME_AUDIT_OBJ), "bin/time_audit.$SHLIBEXT", VFS)
++SMB_MODULE(vfs_glusterfs, \$(VFS_GLUSTERFS_OBJ), "bin/glusterfs.$SHLIBEXT", VFS)
+
+ SMB_SUBSYSTEM(VFS,smbd/vfs.o)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+new file mode 100644
+index 0000000..4beac1d
+--- /dev/null
++++ b/source3/modules/vfs_glusterfs.c
+@@ -0,0 +1,1461 @@
++/*
++ Unix SMB/CIFS implementation.
++
++ Wrap GlusterFS GFAPI calls in vfs functions.
++
++ Copyright (c) 2013 Anand Avati <avati@redhat.com>
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "includes.h"
++#include "smbd/smbd.h"
++#include <stdio.h>
++#include "api/glfs.h"
++
++#define DEFAULT_VOLFILE_SERVER "localhost"
++
++/*
++ TODO
++ ----
++ Short term:
++ - AIO support
++ - sendfile/recvfile support
++*/
++
++/* Helpers to provide 'integer' fds */
++
++/* This is global. gfapi's FD operations do not
++ require filesystem context.
++*/
++static glfs_fd_t **glfd_fd;
++static int glfd_fd_size;
++static int glfd_fd_used;
++static int glfd_fd_store(glfs_fd_t *glfd)
++{
++ int i;
++ void *tmp;
++
++ if (glfd_fd_size == glfd_fd_used) {
++ if (glfd_fd_size >= INT_MAX - 1) {
++ errno = ENOMEM;
++ return -1;
++ }
++
++ tmp = talloc_realloc(glfd_fd, glfd_fd, glfs_fd_t *,
++ glfd_fd_size + 1);
++ if (tmp == NULL) {
++ errno = ENOMEM;
++ return -1;
++ }
++
++ glfd_fd = tmp;
++ glfd_fd[glfd_fd_size] = 0;
++ glfd_fd_size++;
++ }
++
++ for (i = 0; i < glfd_fd_size; i++) {
++ if (!glfd_fd[i]) {
++ break;
++ }
++ }
++ glfd_fd_used++;
++ glfd_fd[i] = glfd;
++ return i;
++}
++
++static glfs_fd_t *glfd_fd_get(int i)
++{
++ if (i < 0 || i >= glfd_fd_size) {
++ return NULL;
++ }
++ return glfd_fd[i];
++}
++
++static glfs_fd_t *glfd_fd_clear(int i)
++{
++ glfs_fd_t *glfd = NULL;
++
++ if (i < 0 || i >= glfd_fd_size) {
++ return NULL;
++ }
++
++ glfd = glfd_fd[i];
++ glfd_fd[i] = 0;
++ glfd_fd_used--;
++ return glfd;
++}
++
++/* Helper to convert stat to stat_ex */
++
++static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
++{
++ ZERO_STRUCTP(dst);
++
++ dst->st_ex_dev = src->st_dev;
++ dst->st_ex_ino = src->st_ino;
++ dst->st_ex_mode = src->st_mode;
++ dst->st_ex_nlink = src->st_nlink;
++ dst->st_ex_uid = src->st_uid;
++ dst->st_ex_gid = src->st_gid;
++ dst->st_ex_rdev = src->st_rdev;
++ dst->st_ex_size = src->st_size;
++ dst->st_ex_atime.tv_sec = src->st_atime;
++#ifdef STAT_HAVE_NSEC
++ dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
++#endif
++ dst->st_ex_mtime.tv_sec = src->st_mtime;
++#ifdef STAT_HAVE_NSEC
++ dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
++#endif
++ dst->st_ex_ctime.tv_sec = src->st_ctime;
++#ifdef STAT_HAVE_NSEC
++ dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
++#endif
++ dst->st_ex_btime.tv_sec = src->st_mtime;
++#ifdef STAT_HAVE_NSEC
++ dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
++#endif
++ dst->st_ex_blksize = src->st_blksize;
++ dst->st_ex_blocks = src->st_blocks;
++}
++
++/* pre-opened glfs_t */
++
++static struct glfs_preopened {
++ char *volume;
++ glfs_t *fs;
++ int ref;
++ struct glfs_preopened *next, *prev;
++} *glfs_preopened;
++
++
++int glfs_set_preopened(const char *volume, glfs_t *fs)
++{
++ struct glfs_preopened *entry = NULL;
++
++ entry = talloc_zero(NULL, struct glfs_preopened);
++ if (!entry) {
++ errno = ENOMEM;
++ return -1;
++ }
++
++ entry->volume = talloc_strdup(entry, volume);
++ if (!entry->volume) {
++ talloc_free(entry);
++ errno = ENOMEM;
++ return -1;
++ }
++
++ entry->fs = fs;
++ entry->ref = 1;
++
++ DLIST_ADD(glfs_preopened, entry);
++
++ return 0;
++}
++
++static glfs_t *glfs_find_preopened(const char *volume)
++{
++ struct glfs_preopened *entry = NULL;
++
++ for (entry = glfs_preopened; entry; entry = entry->next) {
++ if (strcmp(entry->volume, volume) == 0) {
++ entry->ref++;
++ return entry->fs;
++ }
++ }
++
++ return NULL;
++}
++
++static void glfs_clear_preopened(glfs_t *fs)
++{
++ int i;
++ struct glfs_preopened *entry = NULL;
++
++ for (entry = glfs_preopened; entry; entry = entry->next) {
++ if (entry->fs == fs) {
++ if (--entry->ref)
++ return;
++
++ DLIST_REMOVE(glfs_preopened, entry);
++
++ glfs_fini(entry->fs);
++ talloc_free(entry);
++ }
++ }
++}
++
++/* Disk Operations */
++
++static int vfs_gluster_connect(struct vfs_handle_struct *handle,
++ const char *service, const char *user)
++{
++ const char *volfile_server;
++ const char *volume;
++ const char *logfile;
++ int loglevel;
++ glfs_t *fs;
++ int ret;
++
++ logfile = lp_parm_const_string(SNUM(handle->conn), "glusterfs",
++ "logfile", NULL);
++
++ loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
++
++ volfile_server = lp_parm_const_string(SNUM(handle->conn), "glusterfs",
++ "volfile_server", NULL);
++ if (volfile_server == NULL) {
++ volfile_server = DEFAULT_VOLFILE_SERVER;
++ }
++
++ volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
++ NULL);
++ if (volume == NULL) {
++ volume = service;
++ }
++
++ fs = glfs_find_preopened(volume);
++ if (fs) {
++ goto found;
++ }
++
++ fs = glfs_new(volume);
++ if (fs == NULL) {
++ return -1;
++ }
++
++ ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 0);
++ if (ret < 0) {
++ DEBUG(0, ("Failed to set volfile_server %s\n", volfile_server));
++ glfs_fini(fs);
++ return -1;
++ }
++
++ ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
++ "true");
++ if (ret < 0) {
++ DEBUG(0, ("%s: Failed to set xlator options\n", volume));
++ glfs_fini(fs);
++ return -1;
++ }
++
++ ret = glfs_set_logging(fs, logfile, loglevel);
++ if (ret < 0) {
++ DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
++ volume, logfile, loglevel));
++ glfs_fini(fs);
++ return -1;
++ }
++
++ ret = glfs_init(fs);
++ if (ret < 0) {
++ DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
++ volume, strerror(errno)));
++ glfs_fini(fs);
++ return -1;
++ }
++
++ ret = glfs_set_preopened(volume, fs);
++ if (ret < 0) {
++ DEBUG(0, ("%s: Failed to register volume (%s)\n",
++ volume, strerror(errno)));
++ glfs_fini(fs);
++ return -1;
++ }
++found:
++ DEBUG(0, ("%s: Initialized volume from server %s\n",
++ volume, volfile_server));
++ handle->data = fs;
++ return 0;
++}
++
++static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
++{
++ glfs_t *fs = NULL;
++
++ fs = handle->data;
++
++ glfs_clear_preopened(fs);
++}
++
++static uint64_t
++vfs_gluster_disk_free(struct vfs_handle_struct *handle, const char *path,
++ bool small_query, uint64_t *bsize_p, uint64_t *dfree_p,
++ uint64_t *dsize_p)
++{
++ struct statvfs statvfs = { 0, };
++ uint64_t dfree = 0;
++ int ret;
++
++ ret = glfs_statvfs(handle->data, path, &statvfs);
++ if (ret < 0) {
++ DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
++ path, strerror(errno)));
++ return -1;
++ }
++
++ dfree = statvfs.f_bsize * statvfs.f_bavail;
++
++ if (bsize_p) {
++ *bsize_p = statvfs.f_bsize;
++ }
++ if (dfree_p) {
++ *dfree_p = dfree;
++ }
++ if (dsize_p) {
++ *dsize_p = statvfs.f_bsize * statvfs.f_blocks;
++ }
++
++ return dfree;
++}
++
++static int
++vfs_gluster_get_quota(struct vfs_handle_struct *handle,
++ enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
++{
++ errno = ENOSYS;
++ return -1;
++}
++
++static int
++vfs_gluster_set_quota(struct vfs_handle_struct *handle,
++ enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
++{
++ errno = ENOSYS;
++ return -1;
++}
++
++static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
++ const char *path,
++ struct vfs_statvfs_struct *vfs_statvfs)
++{
++ struct statvfs statvfs = { 0, };
++ int ret;
++
++ ret = glfs_statvfs(handle->data, path, &statvfs);
++ if (ret < 0) {
++ DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
++ path, strerror(errno)));
++ return -1;
++ }
++
++ ZERO_STRUCTP(vfs_statvfs);
++
++ vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
++ vfs_statvfs->BlockSize = statvfs.f_bsize;
++ vfs_statvfs->TotalBlocks = statvfs.f_blocks;
++ vfs_statvfs->BlocksAvail = statvfs.f_bfree;
++ vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
++ vfs_statvfs->TotalFileNodes = statvfs.f_files;
++ vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
++ vfs_statvfs->FsIdentifier = statvfs.f_fsid;
++ vfs_statvfs->FsCapabilities =
++ FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
++
++ return ret;
++}
++
++static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
++ enum timestamp_set_resolution *p_ts_res)
++{
++ uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
++
++#ifdef STAT_HAVE_NSEC
++ *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
++#endif
++
++ return caps;
++}
++
++static DIR *vfs_gluster_opendir(struct vfs_handle_struct *handle,
++ const char *path, const char *mask,
++ uint32 attributes)
++{
++ glfs_fd_t *fd;
++
++ fd = glfs_opendir(handle->data, path);
++ if (fd == NULL) {
++ DEBUG(0, ("glfs_opendir(%s) failed: %s\n",
++ path, strerror(errno)));
++ }
++
++ return (DIR *) fd;
++}
++
++static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
++ files_struct *fsp, const char *mask,
++ uint32 attributes)
++{
++ return (DIR *) glfd_fd_get(fsp->fh->fd);
++}
++
++static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
++{
++ return glfs_closedir((void *)dirp);
++}
++
++static SMB_STRUCT_DIRENT *vfs_gluster_readdir(struct vfs_handle_struct *handle,
++ SMB_STRUCT_DIR *dirp,
++ SMB_STRUCT_STAT *sbuf)
++{
++ char direntbuf[512];
++ int ret;
++ struct stat stat;
++ struct dirent *dirent = 0;
++ static SMB_STRUCT_DIRENT result;
++
++ if (sbuf != NULL) {
++ ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
++ &dirent);
++ } else {
++ ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
++ }
++
++ if (ret < 0 || (dirent == NULL)) {
++ return NULL;
++ }
++
++ if (sbuf != NULL) {
++ smb_stat_ex_from_stat(sbuf, &stat);
++ }
++
++ result.d_ino = dirent->d_ino;
++ result.d_off = dirent->d_off;
++ result.d_reclen = dirent->d_reclen;
++ result.d_type = dirent->d_type;
++ strncpy(result.d_name, dirent->d_name, 256);
++
++ return &result;
++}
++
++static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
++{
++ return glfs_telldir((void *)dirp);
++}
++
++static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
++ long offset)
++{
++ glfs_seekdir((void *)dirp, offset);
++}
++
++static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle,
++ DIR *dirp)
++{
++ glfs_seekdir((void *)dirp, 0);
++}
++
++static void vfs_gluster_init_search_op(struct vfs_handle_struct *handle,
++ DIR *dirp)
++{
++ return;
++}
++
++static int vfs_gluster_mkdir(struct vfs_handle_struct *handle, const char *path,
++ mode_t mode)
++{
++ return glfs_mkdir(handle->data, path, mode);
++}
++
++static int vfs_gluster_rmdir(struct vfs_handle_struct *handle, const char *path)
++{
++ return glfs_rmdir(handle->data, path);
++}
++
++static int vfs_gluster_open(struct vfs_handle_struct *handle,
++ struct smb_filename *smb_fname, files_struct *fsp,
++ int flags, mode_t mode)
++{
++ glfs_fd_t *glfd;
++
++ if (flags & O_DIRECTORY) {
++ glfd = glfs_opendir(handle->data, smb_fname->base_name);
++ } else if (flags & O_CREAT) {
++ glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
++ mode);
++ } else {
++ glfd = glfs_open(handle->data, smb_fname->base_name, flags);
++ }
++
++ if (glfd == NULL) {
++ DEBUG(0, ("glfs_{open[dir],creat}(%s) failed: %s\n",
++ smb_fname->base_name, strerror(errno)));
++ return -1;
++ }
++
++ return glfd_fd_store(glfd);
++}
++
++static int vfs_gluster_close(struct vfs_handle_struct *handle,
++ files_struct *fsp)
++{
++ return glfs_close(glfd_fd_clear(fsp->fh->fd));
++}
++
++static ssize_t vfs_gluster_read(struct vfs_handle_struct *handle,
++ files_struct *fsp, void *data, size_t n)
++{
++ return glfs_read(glfd_fd_get(fsp->fh->fd), data, n, 0);
++}
++
++static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
++ files_struct *fsp, void *data, size_t n,
++ off_t offset)
++{
++ return glfs_pread(glfd_fd_get(fsp->fh->fd), data, n, offset, 0);
++}
++
++static ssize_t vfs_gluster_write(struct vfs_handle_struct *handle,
++ files_struct *fsp, const void *data, size_t n)
++{
++ return glfs_write(glfd_fd_get(fsp->fh->fd), data, n, 0);
++}
++
++static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
++ files_struct *fsp, const void *data, size_t n,
++ off_t offset)
++{
++ return glfs_pwrite(glfd_fd_get(fsp->fh->fd), data, n, offset, 0);
++}
++
++static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
++ files_struct *fsp, off_t offset, int whence)
++{
++ return glfs_lseek(glfd_fd_get(fsp->fh->fd), offset, whence);
++}
++
++static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
++ files_struct *fromfsp, const DATA_BLOB *hdr,
++ off_t offset, size_t n)
++{
++ errno = ENOTSUP;
++ return -1;
++}
++
++static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
++ int fromfd, files_struct *tofsp,
++ off_t offset, size_t n)
++{
++ errno = ENOTSUP;
++ return -1;
++}
++
++static int vfs_gluster_rename(struct vfs_handle_struct *handle,
++ const struct smb_filename *smb_fname_src,
++ const struct smb_filename *smb_fname_dst)
++{
++ return glfs_rename(handle->data, smb_fname_src->base_name,
++ smb_fname_dst->base_name);
++}
++
++static int vfs_gluster_fsync(struct vfs_handle_struct *handle,
++ files_struct *fsp)
++{
++ return glfs_fsync(glfd_fd_get(fsp->fh->fd));
++}
++
++static int vfs_gluster_stat(struct vfs_handle_struct *handle,
++ struct smb_filename *smb_fname)
++{
++ struct stat st;
++ int ret;
++
++ ret = glfs_stat(handle->data, smb_fname->base_name, &st);
++ if (ret == 0) {
++ smb_stat_ex_from_stat(&smb_fname->st, &st);
++ }
++ if (ret < 0 && errno != ENOENT) {
++ DEBUG(0, ("glfs_stat(%s) failed: %s\n",
++ smb_fname->base_name, strerror(errno)));
++ }
++ return ret;
++}
++
++static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
++ files_struct *fsp, SMB_STRUCT_STAT *sbuf)
++{
++ struct stat st;
++ int ret;
++
++ ret = glfs_fstat(glfd_fd_get(fsp->fh->fd), &st);
++ if (ret == 0) {
++ smb_stat_ex_from_stat(sbuf, &st);
++ }
++ if (ret < 0) {
++ DEBUG(0, ("glfs_ftat(%d) failed: %s\n",
++ fsp->fh->fd, strerror(errno)));
++ }
++ return ret;
++}
++
++static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
++ struct smb_filename *smb_fname)
++{
++ struct stat st;
++ int ret;
++
++ ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
++ if (ret == 0) {
++ smb_stat_ex_from_stat(&smb_fname->st, &st);
++ }
++ if (ret < 0 && errno != ENOENT) {
++ DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
++ smb_fname->base_name, strerror(errno)));
++ }
++
++ return ret;
++}
++
++static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
++ files_struct *fsp,
++ const SMB_STRUCT_STAT *sbuf)
++{
++ return sbuf->st_ex_blocks * 512;
++}
++
++static int vfs_gluster_unlink(struct vfs_handle_struct *handle,
++ const struct smb_filename *smb_fname)
++{
++ return glfs_unlink(handle->data, smb_fname->base_name);
++}
++
++static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
++ const char *path, mode_t mode)
++{
++ return glfs_chmod(handle->data, path, mode);
++}
++
++static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
++ files_struct *fsp, mode_t mode)
++{
++ return glfs_fchmod(glfd_fd_get(fsp->fh->fd), mode);
++}
++
++static int vfs_gluster_chown(struct vfs_handle_struct *handle,
++ const char *path, uid_t uid, gid_t gid)
++{
++ return glfs_chown(handle->data, path, uid, gid);
++}
++
++static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
++ files_struct *fsp, uid_t uid, gid_t gid)
++{
++ return glfs_fchown(glfd_fd_get(fsp->fh->fd), uid, gid);
++}
++
++static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
++ const char *path, uid_t uid, gid_t gid)
++{
++ return glfs_lchown(handle->data, path, uid, gid);
++}
++
++static int vfs_gluster_chdir(struct vfs_handle_struct *handle, const char *path)
++{
++ return glfs_chdir(handle->data, path);
++}
++
++static char *vfs_gluster_getwd(struct vfs_handle_struct *handle, char *path)
++{
++ return glfs_getcwd(handle->data, path, PATH_MAX);
++}
++
++static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
++ const struct smb_filename *smb_fname,
++ struct smb_file_time *ft)
++{
++ struct timespec times[2];
++
++ times[0].tv_sec = ft->atime.tv_sec;
++ times[0].tv_nsec = ft->atime.tv_nsec;
++ times[1].tv_sec = ft->mtime.tv_sec;
++ times[1].tv_nsec = ft->mtime.tv_nsec;
++
++ return glfs_utimens(handle->data, smb_fname->base_name, times);
++}
++
++static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
++ files_struct *fsp, off_t offset)
++{
++ return glfs_ftruncate(glfd_fd_get(fsp->fh->fd), offset);
++}
++
++static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
++ struct files_struct *fsp,
++ enum vfs_fallocate_mode mode,
++ off_t offset, off_t len)
++{
++ errno = ENOTSUP;
++ return -1;
++}
++
++static char *vfs_gluster_realpath(struct vfs_handle_struct *handle,
++ const char *path)
++{
++ return glfs_realpath(handle->data, path, 0);
++}
++
++static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
++ files_struct *fsp, int op, off_t offset,
++ off_t count, int type)
++{
++ struct flock flock = { 0, };
++ int ret;
++
++ flock.l_type = type;
++ flock.l_whence = SEEK_SET;
++ flock.l_start = offset;
++ flock.l_len = count;
++ flock.l_pid = 0;
++
++ ret = glfs_posix_lock(glfd_fd_get(fsp->fh->fd), op, &flock);
++
++ if (op == F_GETLK) {
++ /* lock query, true if someone else has locked */
++ if ((ret != -1) &&
++ (flock.l_type != F_UNLCK) &&
++ (flock.l_pid != 0) && (flock.l_pid != getpid()))
++ return true;
++ /* not me */
++ return false;
++ }
++
++ if (ret == -1) {
++ return false;
++ }
++
++ return true;
++}
++
++static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
++ files_struct *fsp, uint32 share_mode,
++ uint32_t access_mask)
++{
++ return 0;
++}
++
++static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
++ files_struct *fsp, int leasetype)
++{
++ errno = ENOSYS;
++ return -1;
++}
++
++static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
++ files_struct *fsp, off_t *poffset,
++ off_t *pcount, int *ptype, pid_t *ppid)
++{
++ struct flock flock = { 0, };
++ int ret;
++
++ flock.l_type = *ptype;
++ flock.l_whence = SEEK_SET;
++ flock.l_start = *poffset;
++ flock.l_len = *pcount;
++ flock.l_pid = 0;
++
++ ret = glfs_posix_lock(glfd_fd_get(fsp->fh->fd), F_GETLK, &flock);
++
++ if (ret == -1) {
++ return false;
++ }
++
++ *ptype = flock.l_type;
++ *poffset = flock.l_start;
++ *pcount = flock.l_len;
++ *ppid = flock.l_pid;
++
++ return true;
++}
++
++static int vfs_gluster_symlink(struct vfs_handle_struct *handle,
++ const char *oldpath, const char *newpath)
++{
++ return glfs_symlink(handle->data, oldpath, newpath);
++}
++
++static int vfs_gluster_readlink(struct vfs_handle_struct *handle,
++ const char *path, char *buf, size_t bufsiz)
++{
++ return glfs_readlink(handle->data, path, buf, bufsiz);
++}
++
++static int vfs_gluster_link(struct vfs_handle_struct *handle,
++ const char *oldpath, const char *newpath)
++{
++ return glfs_link(handle->data, oldpath, newpath);
++}
++
++static int vfs_gluster_mknod(struct vfs_handle_struct *handle, const char *path,
++ mode_t mode, SMB_DEV_T dev)
++{
++ return glfs_mknod(handle->data, path, mode, dev);
++}
++
++static NTSTATUS vfs_gluster_notify_watch(struct vfs_handle_struct *vfs_handle,
++ struct sys_notify_context *ctx,
++ struct notify_entry *e,
++ void (*callback) (struct sys_notify_context *ctx,
++ void *private_data,
++ struct notify_event *ev),
++ void *private_data, void *handle)
++{
++ return NT_STATUS_NOT_IMPLEMENTED;
++}
++
++static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
++ const char *path, unsigned int flags)
++{
++ errno = ENOSYS;
++ return -1;
++}
++
++static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
++ const char *path, const char *name,
++ TALLOC_CTX *mem_ctx, char **found_name)
++{
++ int ret;
++ char key_buf[NAME_MAX + 64];
++ char val_buf[NAME_MAX + 1];
++
++ if (strlen(name) >= NAME_MAX) {
++ errno = ENAMETOOLONG;
++ return -1;
++ }
++
++ snprintf(key_buf, NAME_MAX + 64,
++ "user.glusterfs.get_real_filename:%s", name);
++
++ ret = glfs_getxattr(handle->data, path, key_buf, val_buf, NAME_MAX + 1);
++ if (ret == -1 && errno == ENODATA) {
++ errno = EOPNOTSUPP;
++ return -1;
++ }
++
++ *found_name = talloc_strdup(mem_ctx, val_buf);
++ if (found_name[0] == NULL) {
++ errno = ENOMEM;
++ return -1;
++ }
++ return 0;
++}
++
++static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
++ const char *filename)
++{
++ return handle->conn->connectpath;
++}
++
++/* EA Operations */
++
++static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
++ const char *path, const char *name,
++ void *value, size_t size)
++{
++ return glfs_getxattr(handle->data, path, name, value, size);
++}
++
++static ssize_t vfs_gluster_lgetxattr(struct vfs_handle_struct *handle,
++ const char *path, const char *name,
++ void *value, size_t size)
++{
++ return glfs_lgetxattr(handle->data, path, name, value, size);
++}
++
++static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
++ files_struct *fsp, const char *name,
++ void *value, size_t size)
++{
++ return glfs_fgetxattr(glfd_fd_get(fsp->fh->fd), name, value, size);
++}
++
++static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
++ const char *path, char *list, size_t size)
++{
++ return glfs_listxattr(handle->data, path, list, size);
++}
++
++static ssize_t vfs_gluster_llistxattr(struct vfs_handle_struct *handle,
++ const char *path, char *list, size_t size)
++{
++ return glfs_llistxattr(handle->data, path, list, size);
++}
++
++static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
++ files_struct *fsp, char *list,
++ size_t size)
++{
++ return glfs_flistxattr(glfd_fd_get(fsp->fh->fd), list, size);
++}
++
++static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
++ const char *path, const char *name)
++{
++ return glfs_removexattr(handle->data, path, name);
++}
++
++static int vfs_gluster_lremovexattr(struct vfs_handle_struct *handle,
++ const char *path, const char *name)
++{
++ return glfs_lremovexattr(handle->data, path, name);
++}
++
++static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
++ files_struct *fsp, const char *name)
++{
++ return glfs_fremovexattr(glfd_fd_get(fsp->fh->fd), name);
++}
++
++static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
++ const char *path, const char *name,
++ const void *value, size_t size, int flags)
++{
++ return glfs_setxattr(handle->data, path, name, value, size, flags);
++}
++
++static int vfs_gluster_lsetxattr(struct vfs_handle_struct *handle,
++ const char *path, const char *name,
++ const void *value, size_t size, int flags)
++{
++ return glfs_lsetxattr(handle->data, path, name, value, size, flags);
++}
++
++static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
++ files_struct *fsp, const char *name,
++ const void *value, size_t size, int flags)
++{
++ return glfs_fsetxattr(glfd_fd_get(fsp->fh->fd), name, value, size,
++ flags);
++}
++
++/* AIO Operations */
++
++static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
++ files_struct *fsp)
++{
++ return false;
++}
++
++/* Offline Operations */
++
++static bool vfs_gluster_is_offline(struct vfs_handle_struct *handle,
++ const struct smb_filename *fname,
++ SMB_STRUCT_STAT *sbuf)
++{
++ return false;
++}
++
++static int vfs_gluster_set_offline(struct vfs_handle_struct *handle,
++ const struct smb_filename *fname)
++{
++ errno = ENOTSUP;
++ return -1;
++}
++
++/* Posix ACL Operations */
++
++#define GLUSTER_ACL_VERSION 2
++#define GLUSTER_ACL_READ 0x04
++#define GLUSTER_ACL_WRITE 0x02
++#define GLUSTER_ACL_EXECUTE 0x01
++
++#define GLUSTER_ACL_UNDEFINED_TAG 0x00
++#define GLUSTER_ACL_USER_OBJ 0x01
++#define GLUSTER_ACL_USER 0x02
++#define GLUSTER_ACL_GROUP_OBJ 0x04
++#define GLUSTER_ACL_GROUP 0x08
++#define GLUSTER_ACL_MASK 0x10
++#define GLUSTER_ACL_OTHER 0x20
++
++#define GLUSTER_ACL_UNDEFINED_ID (-1)
++
++struct gluster_ace {
++ uint16_t tag;
++ uint16_t perm;
++ uint32_t id;
++};
++
++struct gluster_acl_header {
++ uint32_t version;
++ struct gluster_ace entries[];
++};
++
++static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size)
++{
++ int count;
++ size_t size;
++ struct gluster_ace *ace;
++ struct smb_acl_entry *smb_ace;
++ struct gluster_acl_header *hdr;
++ struct smb_acl_t *result;
++ int i;
++ uint16_t tag;
++ uint16_t perm;
++ uint32_t id;
++
++ size = xattr_size;
++
++ if (size < sizeof(*hdr)) {
++ /* ACL should be at least as big as the header */
++ errno = EINVAL;
++ return NULL;
++ }
++
++ size -= sizeof(*hdr);
++
++ if (size % sizeof(*ace)) {
++ /* Size of entries must strictly be a multiple of
++ size of an ACE
++ */
++ errno = EINVAL;
++ return NULL;
++ }
++
++ count = size / sizeof(*ace);
++
++ hdr = (void *)buf;
++
++ if (ntohl(hdr->version) != GLUSTER_ACL_VERSION) {
++ DEBUG(0, ("Unknown gluster ACL version: %d\n",
++ ntohl(hdr->version)));
++ return NULL;
++ }
++
++ result = SMB_MALLOC(sizeof(struct smb_acl_t) + (sizeof(struct smb_acl_entry) * count));
++ if (!result) {
++ errno = ENOMEM;
++ return NULL;
++ }
++
++ result->count = count;
++
++ smb_ace = result->acl;
++ ace = hdr->entries;
++
++ for (i = 0; i < count; i++) {
++ tag = ntohs(ace->tag);
++
++ switch(tag) {
++ case GLUSTER_ACL_USER:
++ smb_ace->a_type = SMB_ACL_USER;
++ break;
++ case GLUSTER_ACL_USER_OBJ:
++ smb_ace->a_type = SMB_ACL_USER_OBJ;
++ break;
++ case GLUSTER_ACL_GROUP:
++ smb_ace->a_type = SMB_ACL_GROUP;
++ break;
++ case GLUSTER_ACL_GROUP_OBJ:
++ smb_ace->a_type = SMB_ACL_GROUP_OBJ;
++ break;
++ case GLUSTER_ACL_OTHER:
++ smb_ace->a_type = SMB_ACL_OTHER;
++ break;
++ case GLUSTER_ACL_MASK:
++ smb_ace->a_type = SMB_ACL_MASK;
++ break;
++ default:
++ DEBUG(0, ("unknown tag type %d\n", (unsigned int) tag));
++ return NULL;
++ }
++
++ id = ntohl(ace->id);
++
++ switch(smb_ace->a_type) {
++ case SMB_ACL_USER:
++ smb_ace->uid = id;
++ break;
++ case SMB_ACL_GROUP:
++ smb_ace->gid = id;
++ break;
++ default:
++ break;
++ }
++
++ perm = ntohs(ace->perm);
++
++ smb_ace->a_perm = 0;
++ smb_ace->a_perm |=
++ ((perm & GLUSTER_ACL_READ) ? SMB_ACL_READ : 0);
++ smb_ace->a_perm |=
++ ((perm & GLUSTER_ACL_WRITE) ? SMB_ACL_WRITE : 0);
++ smb_ace->a_perm |=
++ ((perm & GLUSTER_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
++
++ ace++;
++ smb_ace++;
++ }
++
++ return result;
++}
++
++static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
++{
++ ssize_t size;
++ struct gluster_ace *ace;
++ struct smb_acl_entry *smb_ace;
++ struct gluster_acl_header *hdr;
++ int i;
++ int count;
++ uint16_t tag;
++ uint16_t perm;
++ uint32_t id;
++
++ count = theacl->count;
++
++ size = sizeof(*hdr) + (count * sizeof(*ace));
++ if (!buf) {
++ return size;
++ }
++
++ if (len < size) {
++ errno = ERANGE;
++ return -1;
++ }
++
++ hdr = (void *)buf;
++ ace = hdr->entries;
++ smb_ace = theacl->acl;
++
++ hdr->version = htonl(GLUSTER_ACL_VERSION);
++
++ for (i = 0; i < count; i++) {
++ switch(smb_ace->a_type) {
++ case SMB_ACL_USER:
++ tag = GLUSTER_ACL_USER;
++ break;
++ case SMB_ACL_USER_OBJ:
++ tag = GLUSTER_ACL_USER_OBJ;
++ break;
++ case SMB_ACL_GROUP:
++ tag = GLUSTER_ACL_GROUP;
++ break;
++ case SMB_ACL_GROUP_OBJ:
++ tag = GLUSTER_ACL_GROUP_OBJ;
++ break;
++ case SMB_ACL_OTHER:
++ tag = GLUSTER_ACL_OTHER;
++ break;
++ case SMB_ACL_MASK:
++ tag = GLUSTER_ACL_MASK;
++ break;
++ default:
++ DEBUG(0, ("Unknown tag value %d\n",
++ smb_ace->a_type));
++ errno = EINVAL;
++ return -1;
++ }
++
++ ace->tag = ntohs(tag);
++
++ switch(smb_ace->a_type) {
++ case SMB_ACL_USER:
++ id = smb_ace->uid;
++ break;
++ case SMB_ACL_GROUP:
++ id = smb_ace->gid;
++ break;
++ default:
++ id = GLUSTER_ACL_UNDEFINED_ID;
++ break;
++ }
++
++ ace->id = ntohl(id);
++
++ ace->perm = 0;
++ ace->perm |=
++ ((smb_ace->a_perm & SMB_ACL_READ) ? GLUSTER_ACL_READ : 0);
++ ace->perm |=
++ ((smb_ace->a_perm & SMB_ACL_WRITE) ? GLUSTER_ACL_WRITE : 0);
++ ace->perm |=
++ ((smb_ace->a_perm & SMB_ACL_EXECUTE) ? GLUSTER_ACL_EXECUTE : 0);
++
++ ace++;
++ smb_ace++;
++ }
++
++ return size;
++}
++
++
++static SMB_ACL_T vfs_gluster_sys_acl_get_file(struct vfs_handle_struct *handle,
++ const char *path_p,
++ SMB_ACL_TYPE_T type)
++{
++ struct smb_acl_t *result;
++ char *buf;
++ char *key;
++ ssize_t ret;
++
++ switch (type) {
++ case SMB_ACL_TYPE_ACCESS:
++ key = "system.posix_acl_access";
++ break;
++ case SMB_ACL_TYPE_DEFAULT:
++ key = "system.posix_acl_default";
++ break;
++ default:
++ errno = EINVAL;
++ return NULL;
++ }
++
++ ret = glfs_getxattr(handle->data, path_p, key, 0, 0);
++ if (ret <= 0) {
++ return NULL;
++ }
++
++ buf = alloca(ret);
++ ret = glfs_getxattr(handle->data, path_p, key, buf, ret);
++ if (ret <= 0) {
++ return NULL;
++ }
++
++ result = gluster_to_smb_acl(buf, ret);
++
++ return result;
++}
++
++static SMB_ACL_T vfs_gluster_sys_acl_get_fd(struct vfs_handle_struct *handle,
++ struct files_struct *fsp)
++{
++ struct smb_acl_t *result;
++ int ret;
++ char *buf;
++
++ ret = glfs_fgetxattr(glfd_fd_get(fsp->fh->fd),
++ "system.posix_acl_access", 0, 0);
++ if (ret <= 0) {
++ return NULL;
++ }
++
++ buf = alloca(ret);
++ ret = glfs_fgetxattr(glfd_fd_get(fsp->fh->fd),
++ "system.posix_acl_access", buf, ret);
++ if (ret <= 0) {
++ return NULL;
++ }
++
++ result = gluster_to_smb_acl(buf, ret);
++
++ return result;
++}
++
++static int vfs_gluster_sys_acl_set_file(struct vfs_handle_struct *handle,
++ const char *name,
++ SMB_ACL_TYPE_T acltype,
++ SMB_ACL_T theacl)
++{
++ int ret;
++ char *key;
++ char *buf;
++ ssize_t size;
++
++ switch (acltype) {
++ case SMB_ACL_TYPE_ACCESS:
++ key = "system.posix_acl_access";
++ break;
++ case SMB_ACL_TYPE_DEFAULT:
++ key = "system.posix_acl_default";
++ break;
++ default:
++ errno = EINVAL;
++ return -1;
++ }
++
++ size = smb_to_gluster_acl(theacl, 0, 0);
++ buf = alloca(size);
++
++ size = smb_to_gluster_acl(theacl, buf, size);
++ if (size == -1) {
++ return -1;
++ }
++
++ ret = glfs_setxattr(handle->data, name, key, buf, size, 0);
++
++ return ret;
++}
++
++static int vfs_gluster_sys_acl_set_fd(struct vfs_handle_struct *handle,
++ struct files_struct *fsp,
++ SMB_ACL_T theacl)
++{
++ int ret;
++ char *buf;
++ ssize_t size;
++
++ size = smb_to_gluster_acl(theacl, 0, 0);
++ buf = alloca(size);
++
++ size = smb_to_gluster_acl(theacl, buf, size);
++ if (size == -1) {
++ return -1;
++ }
++
++ ret = glfs_fsetxattr(glfd_fd_get(fsp->fh->fd),
++ "system.posix_acl_access", buf, size, 0);
++ return ret;
++}
++
++static int vfs_gluster_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
++ const char *path)
++{
++ return glfs_removexattr(handle->data, path, "system.posix_acl_default");
++}
++
++static struct vfs_fn_pointers glusterfs_fns = {
++
++ /* Disk Operations */
++
++ .connect_fn = vfs_gluster_connect,
++ .disconnect = vfs_gluster_disconnect,
++ .disk_free = vfs_gluster_disk_free,
++ .get_quota = vfs_gluster_get_quota,
++ .set_quota = vfs_gluster_set_quota,
++ .statvfs = vfs_gluster_statvfs,
++ .fs_capabilities = vfs_gluster_fs_capabilities,
++
++ /* Directory Operations */
++
++ .opendir = vfs_gluster_opendir,
++ .fdopendir = vfs_gluster_fdopendir,
++ .readdir = vfs_gluster_readdir,
++ .seekdir = vfs_gluster_seekdir,
++ .telldir = vfs_gluster_telldir,
++ .rewind_dir = vfs_gluster_rewinddir,
++ .mkdir = vfs_gluster_mkdir,
++ .rmdir = vfs_gluster_rmdir,
++ .closedir = vfs_gluster_closedir,
++ .init_search_op = vfs_gluster_init_search_op,
++
++ /* File Operations */
++
++ .open_fn = vfs_gluster_open,
++ .create_file = NULL,
++ .close_fn = vfs_gluster_close,
++ .vfs_read = vfs_gluster_read,
++ .pread = vfs_gluster_pread,
++ .write = vfs_gluster_write,
++ .pwrite = vfs_gluster_pwrite,
++ .lseek = vfs_gluster_lseek,
++ .sendfile = vfs_gluster_sendfile,
++ .recvfile = vfs_gluster_recvfile,
++ .rename = vfs_gluster_rename,
++ .fsync = vfs_gluster_fsync,
++ .stat = vfs_gluster_stat,
++ .fstat = vfs_gluster_fstat,
++ .lstat = vfs_gluster_lstat,
++ .get_alloc_size = vfs_gluster_get_alloc_size,
++ .unlink = vfs_gluster_unlink,
++
++ .chmod = vfs_gluster_chmod,
++ .fchmod = vfs_gluster_fchmod,
++ .chown = vfs_gluster_chown,
++ .fchown = vfs_gluster_fchown,
++ .lchown = vfs_gluster_lchown,
++ .chdir = vfs_gluster_chdir,
++ .getwd = vfs_gluster_getwd,
++ .ntimes = vfs_gluster_ntimes,
++ .ftruncate = vfs_gluster_ftruncate,
++ .fallocate = vfs_gluster_fallocate,
++ .lock = vfs_gluster_lock,
++ .kernel_flock = vfs_gluster_kernel_flock,
++ .linux_setlease = vfs_gluster_linux_setlease,
++ .getlock = vfs_gluster_getlock,
++ .symlink = vfs_gluster_symlink,
++ .vfs_readlink = vfs_gluster_readlink,
++ .link = vfs_gluster_link,
++ .mknod = vfs_gluster_mknod,
++ .realpath = vfs_gluster_realpath,
++ .notify_watch = vfs_gluster_notify_watch,
++ .chflags = vfs_gluster_chflags,
++ .file_id_create = NULL,
++ .streaminfo = NULL,
++ .get_real_filename = vfs_gluster_get_real_filename,
++ .connectpath = vfs_gluster_connectpath,
++
++ .brl_lock_windows = NULL,
++ .brl_unlock_windows = NULL,
++ .brl_cancel_windows = NULL,
++ .strict_lock = NULL,
++ .strict_unlock = NULL,
++ .translate_name = NULL,
++
++ /* NT ACL Operations */
++ .fget_nt_acl = NULL,
++ .get_nt_acl = NULL,
++ .fset_nt_acl = NULL,
++
++ /* Posix ACL Operations */
++ .chmod_acl = NULL, /* passthrough to default */
++ .fchmod_acl = NULL, /* passthrough to default */
++
++ .sys_acl_get_entry = NULL,
++ .sys_acl_get_tag_type = NULL,
++ .sys_acl_get_permset = NULL,
++ .sys_acl_get_qualifier = NULL,
++ .sys_acl_get_file = vfs_gluster_sys_acl_get_file,
++ .sys_acl_get_fd = vfs_gluster_sys_acl_get_fd,
++ .sys_acl_clear_perms = NULL,
++ .sys_acl_add_perm = NULL,
++ .sys_acl_to_text = NULL,
++ .sys_acl_init = NULL,
++ .sys_acl_create_entry = NULL,
++ .sys_acl_set_tag_type = NULL,
++ .sys_acl_set_qualifier = NULL,
++ .sys_acl_set_permset = NULL,
++ .sys_acl_valid = NULL,
++ .sys_acl_set_file = vfs_gluster_sys_acl_set_file,
++ .sys_acl_set_fd = vfs_gluster_sys_acl_set_fd,
++ .sys_acl_delete_def_file = vfs_gluster_sys_acl_delete_def_file,
++ .sys_acl_get_perm = NULL,
++ .sys_acl_free_text = NULL,
++ .sys_acl_free_acl = NULL,
++ .sys_acl_free_qualifier = NULL,
++
++ /* EA Operations */
++ .getxattr = vfs_gluster_getxattr,
++ .lgetxattr = vfs_gluster_lgetxattr,
++ .fgetxattr = vfs_gluster_fgetxattr,
++ .listxattr = vfs_gluster_listxattr,
++ .llistxattr = vfs_gluster_llistxattr,
++ .flistxattr = vfs_gluster_flistxattr,
++ .removexattr = vfs_gluster_removexattr,
++ .lremovexattr = vfs_gluster_lremovexattr,
++ .fremovexattr = vfs_gluster_fremovexattr,
++ .setxattr = vfs_gluster_setxattr,
++ .lsetxattr = vfs_gluster_lsetxattr,
++ .fsetxattr = vfs_gluster_fsetxattr,
++
++ /* AIO Operations */
++ .aio_read = NULL,
++ .aio_write = NULL,
++ .aio_return_fn = NULL,
++ .aio_cancel = NULL,
++ .aio_error_fn = NULL,
++ .aio_fsync = NULL,
++ .aio_suspend = NULL,
++ .aio_force = vfs_gluster_aio_force,
++
++ /* Offline Operations */
++ .is_offline = vfs_gluster_is_offline,
++ .set_offline = vfs_gluster_set_offline,
++};
++
++NTSTATUS vfs_glusterfs_init(void);
++NTSTATUS vfs_glusterfs_init(void)
++{
++ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
++ "glusterfs", &glusterfs_fns);
++}
+diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
+index ff7163f..31c93be 100644
+--- a/source3/modules/wscript_build
++++ b/source3/modules/wscript_build
+@@ -50,6 +50,7 @@ VFS_SCANNEDONLY_SRC = 'vfs_scannedonly.c'
+ VFS_CROSSRENAME_SRC = 'vfs_crossrename.c'
+ VFS_LINUX_XFS_SGID_SRC = 'vfs_linux_xfs_sgid.c'
+ VFS_TIME_AUDIT_SRC = 'vfs_time_audit.c'
++VFS_GLUSTERFS_SRC = 'vfs_glusterfs.c'
+
+
+ bld.SAMBA3_SUBSYSTEM('NFS4_ACLS',
+@@ -408,6 +409,14 @@ bld.SAMBA3_MODULE('vfs_time_audit',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_time_audit'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_time_audit'))
+
++bld.SAMBA3_MODULE('vfs_glusterfs',
++ subsystem='vfs',
++ source=VFS_GLUSTERFS_SRC,
++ deps='samba-util gfapi',
++ init_function='',
++ internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_glusterfs'),
++ enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_glusterfs'),
++ allow_undefined_symbols=False)
+
+
+ CHARSET_WEIRD_SRC = 'weird.c'
+diff --git a/source3/wscript b/source3/wscript
+index bcc6ce1..7e34db5 100644
+--- a/source3/wscript
++++ b/source3/wscript
+@@ -60,6 +60,7 @@ def set_options(opt):
+ opt.SAMBA3_ADD_OPTION('automount')
+ opt.SAMBA3_ADD_OPTION('aio-support')
+ opt.SAMBA3_ADD_OPTION('profiling-data')
++ opt.SAMBA3_ADD_OPTION('glusterfs', with_name="enable", without_name="disable", default=True)
+
+ opt.SAMBA3_ADD_OPTION('cluster-support')
+
+@@ -1701,6 +1702,24 @@ main() {
+ conf.undefine('CLUSTER_SUPPORT')
+
+
++ #
++ # Checking for GlusterFS
++ #
++ if Options.options.with_glusterfs:
++ conf.check_cfg(package='glusterfs-api', args='"glusterfs-api >= 4" --cflags --libs',
++ msg='Checking for glusterfs-api >= 4', uselib_store="GFAPI")
++ conf.CHECK_HEADERS('api/glfs.h', lib='gfapi')
++ conf.CHECK_LIB('gfapi', shlib=True)
++
++ if conf.CONFIG_SET('HAVE_API_GLFS_H'):
++ conf.DEFINE('HAVE_GLUSTERFS', '1')
++ else:
++ conf.SET_TARGET_TYPE('gfapi', 'EMPTY')
++ conf.undefine('HAVE_GLUSTERFS')
++ else:
++ conf.SET_TARGET_TYPE('gfapi', 'EMPTY')
++ conf.undefine('HAVE_GLUSTERFS')
++
+
+ conf.CHECK_CODE('__attribute__((destructor)) static void cleanup(void) { }',
+ 'HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR',
+@@ -1794,6 +1813,9 @@ main() {
+ if conf.CONFIG_SET('HAVE_GPFS'):
+ default_shared_modules.extend(TO_LIST('vfs_gpfs vfs_gpfs_hsm_notify'))
+
++ if conf.CONFIG_SET('HAVE_GLUSTERFS'):
++ default_shared_modules.extend(TO_LIST('vfs_glusterfs'))
++
+ explicit_shared_modules = TO_LIST(Options.options.shared_modules, delimiter=',')
+ explicit_static_modules = TO_LIST(Options.options.static_modules, delimiter=',')
+
+--
+1.9.3
+
+
+From e2b70ae1e9b072173de2b7d6140381b910d436b4 Mon Sep 17 00:00:00 2001
+From: Raghavendra Talur <rtalur@redhat.com>
+Date: Thu, 20 Jun 2013 17:58:15 -0700
+Subject: [PATCH 2/9] PATCHSET13: vfs_glusterfs: New file creation fix.
+
+When a new document is created in explorer, a check for file_exist is made.
+vfs_gluster_get_real_filename was returning 0 even when the file did not
+exist.
+---
+ source3/modules/vfs_glusterfs.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index 4beac1d..3752940 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -839,8 +839,10 @@ static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
+ "user.glusterfs.get_real_filename:%s", name);
+
+ ret = glfs_getxattr(handle->data, path, key_buf, val_buf, NAME_MAX + 1);
+- if (ret == -1 && errno == ENODATA) {
+- errno = EOPNOTSUPP;
++ if (ret == -1) {
++ if (errno == ENODATA) {
++ errno = EOPNOTSUPP;
++ }
+ return -1;
+ }
+
+--
+1.9.3
+
+
+From e963ec42b17cdc7369e4b79387447bb3ddc99d2a Mon Sep 17 00:00:00 2001
+From: susant <spalai@redhat.com>
+Date: Wed, 7 Aug 2013 01:00:31 -0500
+Subject: [PATCH 3/9] PATCHSET13: vfs_glusterfs: Volume capacity reported to
+ Windows is incorrect
+
+VFS plugin was sending the actual size of the volume instead of the
+total number of block units because of which windows was getting the
+wrong volume capacity.
+
+Signed-off-by: susant <spalai@redhat.com>
+Reviewed-by: Anand Avati <avati@redhat.com>
+---
+ source3/modules/vfs_glusterfs.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index 3752940..1502776 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -297,7 +297,6 @@ vfs_gluster_disk_free(struct vfs_handle_struct *handle, const char *path,
+ uint64_t *dsize_p)
+ {
+ struct statvfs statvfs = { 0, };
+- uint64_t dfree = 0;
+ int ret;
+
+ ret = glfs_statvfs(handle->data, path, &statvfs);
+@@ -307,19 +306,17 @@ vfs_gluster_disk_free(struct vfs_handle_struct *handle, const char *path,
+ return -1;
+ }
+
+- dfree = statvfs.f_bsize * statvfs.f_bavail;
+-
+ if (bsize_p) {
+- *bsize_p = statvfs.f_bsize;
++ *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
+ }
+ if (dfree_p) {
+- *dfree_p = dfree;
++ *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
+ }
+ if (dsize_p) {
+- *dsize_p = statvfs.f_bsize * statvfs.f_blocks;
++ *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
+ }
+
+- return dfree;
++ return (uint64_t)statvfs.f_bavail;
+ }
+
+ static int
+--
+1.9.3
+
+
+From 1d41227866ede7ae14857105abd6b322e8e41525 Mon Sep 17 00:00:00 2001
+From: Anand Avati <avati@redhat.com>
+Date: Mon, 12 Aug 2013 14:59:24 -0500
+Subject: [PATCH 4/9] PATCHSET13: vfs_glusterfs: Implement proper
+ mashalling/unmarshalling of ACLs
+
+Use the primitives available in Samba byteorder.h for implementing
+proper (un)marshalling of ACL xattrs.
+
+Signed-off-by: Anand Avati <avati@redhat.com>
+Reviewed-by: Raghavendra Talur <rtalur@redhat.com>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+Tested-by: "Jose A. Rivera" <jarrpa@redhat.com>
+---
+ source3/modules/vfs_glusterfs.c | 154 +++++++++++++++++++++++++++++-----------
+ 1 file changed, 112 insertions(+), 42 deletions(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index 1502776..1b81d06 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -963,13 +963,36 @@ static int vfs_gluster_set_offline(struct vfs_handle_struct *handle,
+ return -1;
+ }
+
+-/* Posix ACL Operations */
++/*
++ Gluster ACL Format:
++
++ Size = 4 (header) + N * 8 (entry)
++
++ Offset Size Field (Little Endian)
++ -------------------------------------
++ 0-3 4-byte Version
++
++ 4-5 2-byte Entry-1 tag
++ 6-7 2-byte Entry-1 perm
++ 8-11 4-byte Entry-1 id
++
++ 12-13 2-byte Entry-2 tag
++ 14-15 2-byte Entry-2 perm
++ 16-19 4-byte Entry-2 id
+
++ ...
++
++ */
++
++/* header version */
+ #define GLUSTER_ACL_VERSION 2
++
++/* perm bits */
+ #define GLUSTER_ACL_READ 0x04
+ #define GLUSTER_ACL_WRITE 0x02
+ #define GLUSTER_ACL_EXECUTE 0x01
+
++/* tag values */
+ #define GLUSTER_ACL_UNDEFINED_TAG 0x00
+ #define GLUSTER_ACL_USER_OBJ 0x01
+ #define GLUSTER_ACL_USER 0x02
+@@ -980,57 +1003,48 @@ static int vfs_gluster_set_offline(struct vfs_handle_struct *handle,
+
+ #define GLUSTER_ACL_UNDEFINED_ID (-1)
+
+-struct gluster_ace {
+- uint16_t tag;
+- uint16_t perm;
+- uint32_t id;
+-};
+-
+-struct gluster_acl_header {
+- uint32_t version;
+- struct gluster_ace entries[];
+-};
++#define GLUSTER_ACL_HEADER_SIZE 4
++#define GLUSTER_ACL_ENTRY_SIZE 8
+
+ static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size)
+ {
+ int count;
+ size_t size;
+- struct gluster_ace *ace;
+ struct smb_acl_entry *smb_ace;
+- struct gluster_acl_header *hdr;
+ struct smb_acl_t *result;
+ int i;
++ int offset;
+ uint16_t tag;
+ uint16_t perm;
+ uint32_t id;
+
+ size = xattr_size;
+
+- if (size < sizeof(*hdr)) {
+- /* ACL should be at least as big as the header */
++ if (size < GLUSTER_ACL_HEADER_SIZE) {
++ /* ACL should be at least as big as the header (4 bytes) */
+ errno = EINVAL;
+ return NULL;
+ }
+
+- size -= sizeof(*hdr);
++ size -= GLUSTER_ACL_HEADER_SIZE; /* size of header = 4 bytes */
+
+- if (size % sizeof(*ace)) {
++ if (size % GLUSTER_ACL_ENTRY_SIZE) {
+ /* Size of entries must strictly be a multiple of
+- size of an ACE
++ size of an ACE (8 bytes)
+ */
+ errno = EINVAL;
+ return NULL;
+ }
+
+- count = size / sizeof(*ace);
+-
+- hdr = (void *)buf;
++ count = size / GLUSTER_ACL_ENTRY_SIZE;
+
+- if (ntohl(hdr->version) != GLUSTER_ACL_VERSION) {
++ /* Version is the first 4 bytes of the ACL */
++ if (IVAL(buf, 0) != GLUSTER_ACL_VERSION) {
+ DEBUG(0, ("Unknown gluster ACL version: %d\n",
+- ntohl(hdr->version)));
++ IVAL(buf, 0)));
+ return NULL;
+ }
++ offset = GLUSTER_ACL_HEADER_SIZE;
+
+ result = SMB_MALLOC(sizeof(struct smb_acl_t) + (sizeof(struct smb_acl_entry) * count));
+ if (!result) {
+@@ -1041,10 +1055,19 @@ static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size)
+ result->count = count;
+
+ smb_ace = result->acl;
+- ace = hdr->entries;
+
+ for (i = 0; i < count; i++) {
+- tag = ntohs(ace->tag);
++ /* TAG is the first 2 bytes of an entry */
++ tag = SVAL(buf, offset);
++ offset += 2;
++
++ /* PERM is the next 2 bytes of an entry */
++ perm = SVAL(buf, offset);
++ offset += 2;
++
++ /* ID is the last 4 bytes of an entry */
++ id = IVAL(buf, offset);
++ offset += 4;
+
+ switch(tag) {
+ case GLUSTER_ACL_USER:
+@@ -1070,7 +1093,6 @@ static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size)
+ return NULL;
+ }
+
+- id = ntohl(ace->id);
+
+ switch(smb_ace->a_type) {
+ case SMB_ACL_USER:
+@@ -1083,8 +1105,6 @@ static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size)
+ break;
+ }
+
+- perm = ntohs(ace->perm);
+-
+ smb_ace->a_perm = 0;
+ smb_ace->a_perm |=
+ ((perm & GLUSTER_ACL_READ) ? SMB_ACL_READ : 0);
+@@ -1093,28 +1113,61 @@ static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size)
+ smb_ace->a_perm |=
+ ((perm & GLUSTER_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
+
+- ace++;
+ smb_ace++;
+ }
+
+ return result;
+ }
+
++
++static int gluster_ace_cmp(const void *left, const void *right)
++{
++ int ret = 0;
++ uint16_t tag_left, tag_right;
++ uint32_t id_left, id_right;
++
++ /*
++ Sorting precedence:
++
++ - Smaller TAG values must be earlier.
++
++ - Within same TAG, smaller identifiers must be earlier, E.g:
++ UID 0 entry must be earlier than UID 200
++ GID 17 entry must be earlier than GID 19
++ */
++
++ /* TAG is the first element in the entry */
++ tag_left = SVAL(left, 0);
++ tag_right = SVAL(right, 0);
++
++ ret = (tag_left - tag_right);
++ if (!ret) {
++ /* ID is the third element in the entry, after two short
++ integers (tag and perm), i.e at offset 4.
++ */
++ id_left = IVAL(left, 4);
++ id_right = IVAL(right, 4);
++ ret = id_left - id_right;
++ }
++
++ return ret;
++}
++
++
+ static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
+ {
+ ssize_t size;
+- struct gluster_ace *ace;
+ struct smb_acl_entry *smb_ace;
+- struct gluster_acl_header *hdr;
+ int i;
+ int count;
+ uint16_t tag;
+ uint16_t perm;
+ uint32_t id;
++ int offset;
+
+ count = theacl->count;
+
+- size = sizeof(*hdr) + (count * sizeof(*ace));
++ size = GLUSTER_ACL_HEADER_SIZE + (count * GLUSTER_ACL_ENTRY_SIZE);
+ if (!buf) {
+ return size;
+ }
+@@ -1124,13 +1177,14 @@ static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
+ return -1;
+ }
+
+- hdr = (void *)buf;
+- ace = hdr->entries;
+ smb_ace = theacl->acl;
+
+- hdr->version = htonl(GLUSTER_ACL_VERSION);
++ /* Version is the first 4 bytes of the ACL */
++ SIVAL(buf, 0, GLUSTER_ACL_VERSION);
++ offset = GLUSTER_ACL_HEADER_SIZE;
+
+ for (i = 0; i < count; i++) {
++ /* Calculate tag */
+ switch(smb_ace->a_type) {
+ case SMB_ACL_USER:
+ tag = GLUSTER_ACL_USER;
+@@ -1157,8 +1211,8 @@ static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
+ return -1;
+ }
+
+- ace->tag = ntohs(tag);
+
++ /* Calculate id */
+ switch(smb_ace->a_type) {
+ case SMB_ACL_USER:
+ id = smb_ace->uid;
+@@ -1171,20 +1225,36 @@ static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
+ break;
+ }
+
+- ace->id = ntohl(id);
++ /* Calculate perm */
++ perm = 0;
+
+- ace->perm = 0;
+- ace->perm |=
++ perm |=
+ ((smb_ace->a_perm & SMB_ACL_READ) ? GLUSTER_ACL_READ : 0);
+- ace->perm |=
++ perm |=
+ ((smb_ace->a_perm & SMB_ACL_WRITE) ? GLUSTER_ACL_WRITE : 0);
+- ace->perm |=
++ perm |=
+ ((smb_ace->a_perm & SMB_ACL_EXECUTE) ? GLUSTER_ACL_EXECUTE : 0);
+
+- ace++;
++
++ /* TAG is the first 2 bytes of an entry */
++ SSVAL(buf, offset, tag);
++ offset += 2;
++
++ /* PERM is the next 2 bytes of an entry */
++ SSVAL(buf, offset, perm);
++ offset += 2;
++
++ /* ID is the last 4 bytes of an entry */
++ SIVAL(buf, offset, id);
++ offset += 4;
++
+ smb_ace++;
+ }
+
++ /* Skip the header, sort @count number of 8-byte entries */
++ qsort(buf+GLUSTER_ACL_HEADER_SIZE, count, GLUSTER_ACL_ENTRY_SIZE,
++ gluster_ace_cmp);
++
+ return size;
+ }
+
+--
+1.9.3
+
+
+From 26673935299da8ce830ff9d0ea5df18f52092092 Mon Sep 17 00:00:00 2001
+From: "Christopher R. Hertel" <crh@redhat.com>
+Date: Thu, 29 Aug 2013 11:01:24 -0500
+Subject: [PATCH 5/9] PATCHSET13: vfs_glusterfs: Fix excessive debug output
+ from vfs_gluster_open().
+
+The vfs_gluster_open() function generates a debug message (at level 0)
+for every failed attempt to open a pathname. This includes cases in
+which attempts are made to open a directory as a file (those attempts
+are retried calling vfs_gluster_opendir()). The result is that the log
+file fills with messages about failed attempts to open directories,
+because they are directories. This patch ensures that failed attempts
+to open directories as files are logged at log level 4, not 0. In
+addition, other failed open attempts are logged at level 1, not 0.
+
+Signed-off-by: Christopher R. Hertel <crh@redhat.com>
+Reviewed-by : Susant Palai <spalai@redhat.com>
+Reviewed-by : Raghavendra Talur <rtalur@redhat.com>
+Reviewed-by : Jose A. Rivera <jarrpa@redhat.com>
+---
+ source3/modules/vfs_glusterfs.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index 1b81d06..b92c7fd 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -488,11 +488,8 @@ static int vfs_gluster_open(struct vfs_handle_struct *handle,
+ }
+
+ if (glfd == NULL) {
+- DEBUG(0, ("glfs_{open[dir],creat}(%s) failed: %s\n",
+- smb_fname->base_name, strerror(errno)));
+ return -1;
+ }
+-
+ return glfd_fd_store(glfd);
+ }
+
+--
+1.9.3
+
+
+From f396be725dd8e8f93b0eed1b23fcf0a0f61303a9 Mon Sep 17 00:00:00 2001
+From: Andreas Schneider <asn@samba.org>
+Date: Mon, 4 Nov 2013 12:32:05 +0100
+Subject: [PATCH 6/9] PATCHSET13: vfs: Fix some build warnings in glusterfs.
+
+Signed-off-by: Andreas Schneider <asn@samba.org>
+Reviewed-by: David Disseldorp <ddiss@samba.org>
+---
+ source3/modules/vfs_glusterfs.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index b92c7fd..4b8da4a 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -1262,7 +1262,7 @@ static SMB_ACL_T vfs_gluster_sys_acl_get_file(struct vfs_handle_struct *handle,
+ {
+ struct smb_acl_t *result;
+ char *buf;
+- char *key;
++ const char *key;
+ ssize_t ret;
+
+ switch (type) {
+@@ -1324,7 +1324,7 @@ static int vfs_gluster_sys_acl_set_file(struct vfs_handle_struct *handle,
+ SMB_ACL_T theacl)
+ {
+ int ret;
+- char *key;
++ const char *key;
+ char *buf;
+ ssize_t size;
+
+--
+1.9.3
+
+
+From 2b136f8999e171d15736d0a532353799b7251ae2 Mon Sep 17 00:00:00 2001
+From: Andreas Schneider <asn@samba.org>
+Date: Fri, 15 Nov 2013 17:02:19 +0100
+Subject: [PATCH 7/9] PATCHSET13: s3-vfs: Make glfs_set_preopened() static.
+
+Signed-off-by: Andreas Schneider <asn@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+---
+ source3/modules/vfs_glusterfs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index 4b8da4a..ef505a3 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -141,7 +141,7 @@ static struct glfs_preopened {
+ } *glfs_preopened;
+
+
+-int glfs_set_preopened(const char *volume, glfs_t *fs)
++static int glfs_set_preopened(const char *volume, glfs_t *fs)
+ {
+ struct glfs_preopened *entry = NULL;
+
+--
+1.9.3
+
+
+From 9b2c8854a5a27e4fdbe5191abf174d3152b0edfd Mon Sep 17 00:00:00 2001
+From: Poornima Gurusiddaiah <pgurusid@redhat.com>
+Date: Sun, 24 Nov 2013 21:37:53 +0000
+Subject: [PATCH 8/9] PATCHSET13: vfs_glusterfs: Enable per client log file
+
+In Samba configuration file, one of the options of gluster type is
+log file, the value of this option was not allowed to contain any
+variables, as a result all the clients would have a single log file,
+which complicated debugging.
+In this patch, variable substitution is performed for gluster log file.
+Hence allowing user to customise the gluster log file name.
+
+Signed-off-by: Poornima Gurusiddaiah <pgurusid@redhat.com>
+Reviewed-by: Ira Cooper <ira@samba.org>
+---
+ source3/modules/vfs_glusterfs.c | 41 ++++++++++++++++++++++-------------------
+ 1 file changed, 22 insertions(+), 19 deletions(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index ef505a3..3757968 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -205,12 +205,12 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle,
+ {
+ const char *volfile_server;
+ const char *volume;
+- const char *logfile;
++ char *logfile;
+ int loglevel;
+ glfs_t *fs;
+- int ret;
++ int ret = 0;
+
+- logfile = lp_parm_const_string(SNUM(handle->conn), "glusterfs",
++ logfile = lp_parm_talloc_string(SNUM(handle->conn), "glusterfs",
+ "logfile", NULL);
+
+ loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
+@@ -229,57 +229,60 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle,
+
+ fs = glfs_find_preopened(volume);
+ if (fs) {
+- goto found;
++ goto done;
+ }
+
+ fs = glfs_new(volume);
+ if (fs == NULL) {
+- return -1;
++ ret = -1;
++ goto done;
+ }
+
+ ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 0);
+ if (ret < 0) {
+ DEBUG(0, ("Failed to set volfile_server %s\n", volfile_server));
+- glfs_fini(fs);
+- return -1;
++ goto done;
+ }
+
+ ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
+ "true");
+ if (ret < 0) {
+ DEBUG(0, ("%s: Failed to set xlator options\n", volume));
+- glfs_fini(fs);
+- return -1;
++ goto done;
+ }
+
+ ret = glfs_set_logging(fs, logfile, loglevel);
+ if (ret < 0) {
+ DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
+ volume, logfile, loglevel));
+- glfs_fini(fs);
+- return -1;
++ goto done;
+ }
+
+ ret = glfs_init(fs);
+ if (ret < 0) {
+ DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
+ volume, strerror(errno)));
+- glfs_fini(fs);
+- return -1;
++ goto done;
+ }
+
+ ret = glfs_set_preopened(volume, fs);
+ if (ret < 0) {
+ DEBUG(0, ("%s: Failed to register volume (%s)\n",
+ volume, strerror(errno)));
+- glfs_fini(fs);
++ goto done;
++ }
++done:
++ talloc_free(logfile);
++ if (ret < 0) {
++ if (fs)
++ glfs_fini(fs);
+ return -1;
++ } else {
++ DEBUG(0, ("%s: Initialized volume from server %s\n",
++ volume, volfile_server));
++ handle->data = fs;
++ return 0;
+ }
+-found:
+- DEBUG(0, ("%s: Initialized volume from server %s\n",
+- volume, volfile_server));
+- handle->data = fs;
+- return 0;
+ }
+
+ static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
+--
+1.9.3
+
+
+From 8577c573dcd44e26579a6594b83a6d582faef14c Mon Sep 17 00:00:00 2001
+From: Niels de Vos <ndevos@redhat.com>
+Date: Fri, 10 Jan 2014 16:26:18 +0100
+Subject: [PATCH 9/9] PATCHSET13: vfs/glusterfs: in case atime is not passed,
+ set it to the current atime
+
+The Linux CIFS client does not pass an updated atime when a write() is
+done. This causes the vfs/glusterfs module to set the atime to -1 on the
+Gluster backend, resulting in an atime far in the future (year 2106).
+
+Signed-off-by: Niels de Vos <ndevos@redhat.com>
+Reviewed-by: Ira Cooper <ira@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+
+Autobuild-User(master): Jeremy Allison <jra@samba.org>
+Autobuild-Date(master): Wed Jan 15 21:31:30 CET 2014 on sn-devel-104
+---
+ source3/modules/vfs_glusterfs.c | 26 ++++++++++++++++++++++----
+ 1 file changed, 22 insertions(+), 4 deletions(-)
+
+diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
+index 3757968..24f80dd 100644
+--- a/source3/modules/vfs_glusterfs.c
++++ b/source3/modules/vfs_glusterfs.c
+@@ -675,10 +675,28 @@ static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
+ {
+ struct timespec times[2];
+
+- times[0].tv_sec = ft->atime.tv_sec;
+- times[0].tv_nsec = ft->atime.tv_nsec;
+- times[1].tv_sec = ft->mtime.tv_sec;
+- times[1].tv_nsec = ft->mtime.tv_nsec;
++ if (null_timespec(ft->atime)) {
++ times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
++ times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
++ } else {
++ times[0].tv_sec = ft->atime.tv_sec;
++ times[0].tv_nsec = ft->atime.tv_nsec;
++ }
++
++ if (null_timespec(ft->mtime)) {
++ times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
++ times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
++ } else {
++ times[1].tv_sec = ft->mtime.tv_sec;
++ times[1].tv_nsec = ft->mtime.tv_nsec;
++ }
++
++ if ((timespec_compare(×[0],
++ &smb_fname->st.st_ex_atime) == 0) &&
++ (timespec_compare(×[1],
++ &smb_fname->st.st_ex_mtime) == 0)) {
++ return 0;
++ }
+
+ return glfs_utimens(handle->data, smb_fname->base_name, times);
+ }
+--
+1.9.3
+