From 6fbebb5369211b72545a1dd588bc6b9fa04210a1 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Sun, 15 Feb 2009 23:38:53 -0800 Subject: s3: Modify SMB_VFS_FILE_ID_CREATE to take a stat struct Since file_id_create_dev is incompatible with the concept of file_ids, it is now static and in the one file that needs it. --- source3/modules/vfs_default.c | 14 ++++++++++++-- source3/modules/vfs_fileid.c | 6 +++--- source3/modules/vfs_full_audit.c | 6 +++--- source3/modules/vfs_streams_depot.c | 3 +-- source3/modules/vfs_xattr_tdb.c | 20 ++++++++++---------- 5 files changed, 29 insertions(+), 20 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index f52ca09c08..c18ec268d3 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1042,9 +1042,19 @@ static int vfswrap_chflags(vfs_handle_struct *handle, const char *path, int flag #endif } -static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, SMB_DEV_T dev, SMB_INO_T inode) +static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, + SMB_STRUCT_STAT *sbuf) { - return file_id_create_dev(dev, inode); + struct file_id key; + + /* the ZERO_STRUCT ensures padding doesn't break using the key as a + * blob */ + ZERO_STRUCT(key); + + key.devid = sbuf->st_dev; + key.inode = sbuf->st_ino; + + return key; } static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle, diff --git a/source3/modules/vfs_fileid.c b/source3/modules/vfs_fileid.c index 787a49f36b..8152c5477e 100644 --- a/source3/modules/vfs_fileid.c +++ b/source3/modules/vfs_fileid.c @@ -226,7 +226,7 @@ static void fileid_disconnect(struct vfs_handle_struct *handle) } static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle, - SMB_DEV_T dev, SMB_INO_T inode) + const SMB_STRUCT_STAT *sbuf) { struct fileid_handle_data *data; struct file_id id; @@ -237,8 +237,8 @@ static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle, struct fileid_handle_data, return id); - id.devid = data->device_mapping_fn(data, dev); - id.inode = inode; + id.devid = data->device_mapping_fn(data, sbuf->st_dev); + id.inode = sbuf->st_ino; return id; } diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 15eafc1b56..3c159f10eb 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -209,7 +209,7 @@ static NTSTATUS smb_full_audit_notify_watch(struct vfs_handle_struct *handle, static int smb_full_audit_chflags(vfs_handle_struct *handle, const char *path, unsigned int flags); static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *handle, - SMB_DEV_T dev, SMB_INO_T inode); + const SMB_STRUCT_STAT *sbuf); static NTSTATUS smb_full_audit_streaminfo(vfs_handle_struct *handle, struct files_struct *fsp, const char *fname, @@ -1664,14 +1664,14 @@ static int smb_full_audit_chflags(vfs_handle_struct *handle, } static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *handle, - SMB_DEV_T dev, SMB_INO_T inode) + const SMB_STRUCT_STAT *sbuf) { struct file_id id_zero; struct file_id result; ZERO_STRUCT(id_zero); - result = SMB_VFS_NEXT_FILE_ID_CREATE(handle, dev, inode); + result = SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf); do_log(SMB_VFS_OP_FILE_ID_CREATE, !file_id_equal(&id_zero, &result), diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index 1c2c0e5f77..9329be7a9c 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -153,8 +153,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, base_sbuf = &sbuf; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf->st_dev, - base_sbuf->st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf); push_file_id_16((char *)id_buf, &id); diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c index 44bfffb94e..908a2a3872 100644 --- a/source3/modules/vfs_xattr_tdb.c +++ b/source3/modules/vfs_xattr_tdb.c @@ -216,7 +216,7 @@ static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_getattr(db, &id, name, value, size); } @@ -235,7 +235,7 @@ static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_getattr(db, &id, name, value, size); } @@ -338,7 +338,7 @@ static int xattr_tdb_setxattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_setattr(db, &id, name, value, size, flags); } @@ -358,7 +358,7 @@ static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_setattr(db, &id, name, value, size, flags); } @@ -443,7 +443,7 @@ static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_listattr(db, &id, list, size); } @@ -462,7 +462,7 @@ static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_listattr(db, &id, list, size); } @@ -543,7 +543,7 @@ static int xattr_tdb_removexattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_removeattr(db, &id, name); } @@ -561,7 +561,7 @@ static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle, return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); return xattr_tdb_removeattr(db, &id, name); } @@ -628,7 +628,7 @@ static int xattr_tdb_unlink(vfs_handle_struct *handle, const char *path) return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id); @@ -667,7 +667,7 @@ static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path) return -1; } - id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino); + id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf); rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id); -- cgit From e4675ce8db436ac572fcc476b9bfb1116e997f9f Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Sun, 15 Feb 2009 23:45:28 -0800 Subject: s3: Add extid to the dev/inode pair This extends the file_id struct to add an additional generic uint64_t field: extid. For backwards compatibility with dev/inodes stored in xattr_tdbs and acl_tdbs, the ext id is ignored for these databases. This patch should cause no functional change on systems that don't use SMB_VFS_FILE_ID_CREATE to set the extid. Existing code that uses the smb_share_mode library will need to be updated to be compatibile with the new extid. --- source3/modules/vfs_acl_tdb.c | 6 ++++++ source3/modules/vfs_default.c | 1 + source3/modules/vfs_xattr_tdb.c | 3 +++ 3 files changed, 10 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c index 57fe73c814..909de9d7c8 100644 --- a/source3/modules/vfs_acl_tdb.c +++ b/source3/modules/vfs_acl_tdb.c @@ -94,6 +94,8 @@ static struct db_record *acl_tdb_lock(TALLOC_CTX *mem_ctx, const struct file_id *id) { uint8 id_buf[16]; + + /* For backwards compatibility only store the dev/inode. */ push_file_id_16((char *)id_buf, id); return db->fetch_locked(db, mem_ctx, @@ -200,6 +202,7 @@ static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, } id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + /* For backwards compatibility only store the dev/inode. */ push_file_id_16((char *)id_buf, &id); if (db->fetch(db, @@ -285,6 +288,7 @@ static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle, } id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + /* For backwards compatibility only store the dev/inode. */ push_file_id_16((char *)id_buf, &id); rec = db->fetch_locked(db, talloc_tos(), make_tdb_data(id_buf, @@ -325,6 +329,8 @@ static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle, } id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + + /* For backwards compatibility only store the dev/inode. */ push_file_id_16((char *)id_buf, &id); rec = db->fetch_locked(db, talloc_tos(), diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index c18ec268d3..7384268dae 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1053,6 +1053,7 @@ static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, key.devid = sbuf->st_dev; key.inode = sbuf->st_ino; + /* key.extid is unused by default. */ return key; } diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c index 908a2a3872..4e37ed6477 100644 --- a/source3/modules/vfs_xattr_tdb.c +++ b/source3/modules/vfs_xattr_tdb.c @@ -100,6 +100,7 @@ static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx, NTSTATUS status; TDB_DATA data; + /* For backwards compatibility only store the dev/inode. */ push_file_id_16((char *)id_buf, id); if (db_ctx->fetch(db_ctx, mem_ctx, @@ -122,6 +123,8 @@ static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx, const struct file_id *id) { uint8 id_buf[16]; + + /* For backwards compatibility only store the dev/inode. */ push_file_id_16((char *)id_buf, id); return db_ctx->fetch_locked(db_ctx, mem_ctx, make_tdb_data(id_buf, sizeof(id_buf))); -- cgit From 53bcd162ee4fd55fc5cc3293596f8733ce636b11 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Tue, 17 Feb 2009 18:38:58 -0800 Subject: s3 OneFS: Add file_id_create implementation to take advantage of snapshots --- source3/modules/vfs_onefs.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index 9667d86dba..522b94399d 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -194,6 +194,22 @@ static uint64_t onefs_get_alloc_size(struct vfs_handle_struct *handle, return result; } +static struct file_id onefs_file_id_create(struct vfs_handle_struct *handle, + SMB_STRUCT_STAT *sbuf) +{ + struct file_id key; + + /* the ZERO_STRUCT ensures padding doesn't break using the key as a + * blob */ + ZERO_STRUCT(key); + + key.devid = sbuf->st_dev; + key.inode = sbuf->st_ino; + key.extid = sbuf->st_snapid; + + return key; +} + static int onefs_statvfs(vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf) { @@ -342,6 +358,8 @@ static vfs_op_tuple onefs_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_chflags), SMB_VFS_OP_CHFLAGS, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_file_id_create), SMB_VFS_OP_FILE_ID_CREATE, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_streaminfo), SMB_VFS_OP_STREAMINFO, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_brl_lock_windows), SMB_VFS_OP_BRL_LOCK_WINDOWS, -- cgit From 73d5f14c04f2487f67695ce2e9ff025e25b2b026 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Tue, 17 Feb 2009 20:39:03 -0800 Subject: s3 OneFS: Add shadow copy module --- source3/modules/onefs_shadow_copy.c | 782 ++++++++++++++++++++++++++++++++ source3/modules/onefs_shadow_copy.h | 32 ++ source3/modules/vfs_onefs_shadow_copy.c | 717 +++++++++++++++++++++++++++++ 3 files changed, 1531 insertions(+) create mode 100644 source3/modules/onefs_shadow_copy.c create mode 100644 source3/modules/onefs_shadow_copy.h create mode 100644 source3/modules/vfs_onefs_shadow_copy.c (limited to 'source3/modules') diff --git a/source3/modules/onefs_shadow_copy.c b/source3/modules/onefs_shadow_copy.c new file mode 100644 index 0000000000..5b02534715 --- /dev/null +++ b/source3/modules/onefs_shadow_copy.c @@ -0,0 +1,782 @@ +/* + * Unix SMB/CIFS implementation. + * + * OneFS shadow copy implementation that utilizes the file system's native + * snapshot support. This file does all of the heavy lifting. + * + * Copyright (C) Dave Richards, 2007 + * Copyright (C) Tim Prouty, 2009 + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "onefs_shadow_copy.h" + +/* Copied from ../include/proto.h */ +void become_root(void); +void unbecome_root(void); + +#define SNAPSHOT_DIRECTORY ".snapshot" + +#define MAX_VERSIONS 64 + +/** + * A snapshot object. + * + * During snapshot enumeration, snapshots are represented by snapshot objects + * and are stored in a snapshot set. The snapshot object represents one + * snapshot within the set. An important thing to note about the set is that + * the key of the snapshot object is the tv_sec component of the is_time + * member. What this means is that we only store one snapshot for each + * second. If multiple snapshots were created within the same second, we'll + * keep the earliest one and ignore the rest. Thus, not all snapshots are + * necessarily retained. + */ +struct osc_snapshot { + char * is_name; + struct timespec is_time; + struct osc_snapshot * is_next; +}; + +/** + * A snapshot context object. + * + * Snapshot contexts are used to pass information throughout the snapshot + * enumeration routines. As a result, snapshot contexts are stored on the + * stack and are both created and destroyed within a single API function. + */ +struct osc_snapshot_ctx { + void * osc_set; + struct timespec osc_mtime; +}; + +/** + * A directory context. + * + * Directory contexts are the underlying data structured used to enumerate + * snapshot versions. An opendir()-, readdir()- and closedir()-like interface + * is provided that utilizes directory contexts. At the API level, directory + * contexts are passed around as void pointers. Directory contexts are + * allocated on the heap and their lifetime is dictated by the calling + * routine. + */ +struct osc_directory_ctx { + size_t idc_pos; + size_t idc_len; + size_t idc_size; + char ** idc_version; +}; + +/** + * Return a file descriptor to the STF names directory. + * + * Opens the STF names directory and returns a file descriptor to it. + * Subsequent calls return the same value (avoiding the need to re-open the + * directory repeatedly). Caveat caller: don't close the file descriptor or + * you will be shot! + */ +static int +osc_get_names_directory_fd(void) +{ + static int fd = -1; + + if (fd == -1) { + become_root(); + fd = pctl2_lin_open(STF_NAMES_LIN, HEAD_SNAPID, O_RDONLY); + unbecome_root(); + } + + return fd; +} + +/** + * Compare two time values. + * + * Accepts two struct timespecs and compares the tv_sec components of these + * values. It returns -1 if the first value preceeds the second, 0 if they + * are equal and +1 if the first values succeeds the second. + */ +static int +osc_time_compare(const struct timespec *tsp1, const struct timespec *tsp2) +{ + return (tsp1->tv_sec < tsp2->tv_sec) ? -1 : + (tsp1->tv_sec > tsp2->tv_sec) ? +1 : 0; +} + +/** + * Compare two timespec values. + * + * Compares two timespec values. It returns -1 if the first value preceeds + * the second, 0 if they are equal and +1 if the first values succeeds the + * second. + */ +static int +osc_timespec_compare(const struct timespec *tsp1, const struct timespec *tsp2) +{ + return (tsp1->tv_sec < tsp2->tv_sec) ? -1 : + (tsp1->tv_sec > tsp2->tv_sec) ? +1 : + (tsp1->tv_nsec < tsp2->tv_nsec) ? -1 : + (tsp1->tv_nsec > tsp2->tv_nsec) ? +1 : 0; +} + +/** + * Determine whether a timespec value is zero. + * + * Return 1 if the struct timespec provided is zero and 0 otherwise. + */ +static int +osc_timespec_is_zero(const struct timespec *tsp) +{ + return (tsp->tv_sec == 0) && + (tsp->tv_nsec == 0); +} + +/** + * Create a snapshot object. + * + * Allocates and initializes a new snapshot object. In addition to allocating + * space for the snapshot object itself, space is allocated for the snapshot + * name. Both the name and time are then copied to the new object. + */ +static struct osc_snapshot * +osc_snapshot_create(const char *name, const struct timespec *tsp) +{ + struct osc_snapshot *isp; + + isp = malloc(sizeof *isp); + if (isp == NULL) + goto out; + + isp->is_name = malloc(strlen(name) + 1); + if (isp->is_name == NULL) { + free(isp); + isp = NULL; + goto out; + } + + strcpy(isp->is_name, name); + isp->is_time = *tsp; + isp->is_next = NULL; + + out: + return isp; +} + +/** + * Destroy a snapshot object. + * + * Frees both the name and the snapshot object itself. Appropriate NULL + * checking is performed because counting on free to do so is immoral. + */ +static void +osc_snapshot_destroy(struct osc_snapshot *isp) +{ + if (isp != NULL) { + if (isp->is_name != NULL) + free(isp->is_name); + free(isp); + } +} + +/** + * Destroy all snapshots in the snapshot list. + * + * Calls osc_snapshot_destroy() on each snapshot in the list. + */ +static void +osc_snapshot_destroy_list(struct osc_snapshot *isp) +{ + struct osc_snapshot *tmp; + + while (isp != NULL) { + tmp = isp; + isp = isp->is_next; + osc_snapshot_destroy(tmp); + } +} + +/** + * Compare two snapshot objects. + * + * Compare two snapshot objects. It is really just a wrapper for + * osc_time_compare(), which compare the time value of the two snapshots. + * N.B. time value in this context refers only to the tv_sec component. + */ +static int +osc_snapshot_compare(const void *vp1, const void *vp2) +{ + const struct osc_snapshot *isp1 = vp1; + const struct osc_snapshot *isp2 = vp2; + + return -osc_time_compare(&isp1->is_time, &isp2->is_time); +} + +/** + * Insert a snapshot into the snapshot set. + * + * Inserts a new snapshot into the snapshot set. The key for snapshots is + * their creation time (it's actually the seconds portion of the creation + * time). If a duplicate snapshot is found in the set, the new snapshot is + * added to a linked list of snapshots for that second. + */ +static void +osc_snapshot_insert(struct osc_snapshot_ctx *oscp, const char *name, + const struct timespec *tsp, int *errorp) +{ + struct osc_snapshot *isp1; + struct osc_snapshot **ispp; + + isp1 = osc_snapshot_create(name, tsp); + if (isp1 == NULL) { + *errorp = 1; + return; + } + + ispp = tsearch(isp1, &oscp->osc_set, osc_snapshot_compare); + if (ispp != NULL) { + struct osc_snapshot *isp2 = *ispp; + + /* If this is the only snapshot for this second, we're done. */ + if (isp2 == isp1) + return; + + /* Collision: add the new snapshot to the list. */ + isp1->is_next = isp2->is_next; + isp2->is_next = isp1; + + } else + *errorp = 1; + +} + +/** + * Process the next snapshot. + * + * Called for (almost) every entry in a .snapshot directory, ("." and ".." are + * ignored in osc_process_snapshot_directory()). All other entries are passed + * to osc_process_snapshot(), however. These entries can fall into one of two + * categories: snapshot names and snapshot aliases. We only care about + * snapshot names (as aliases are just redundant entries). Once it verifies + * that name represents a valid snapshot name, it calls fstat() to get the + * creation time of the snapshot and then calls osc_snapshot_insert() to add + * this entry to the snapshot set. + */ +static void +osc_process_snapshot(struct osc_snapshot_ctx *oscp, const char *name, + int *errorp) +{ + int fd; + struct stf_stat stf_stat; + struct stat stbuf; + + fd = osc_get_names_directory_fd(); + if (fd == -1) + goto out; + + fd = enc_openat(fd, name, ENC_DEFAULT, O_RDONLY); + if (fd == -1) + goto out; + + memset(&stf_stat, 0, sizeof stf_stat); + if (ifs_snap_stat(fd, &stf_stat) == -1) + goto out; + + if (stf_stat.sf_type != SF_STF) + goto out; + + if (fstat(fd, &stbuf) == -1) + goto out; + + osc_snapshot_insert(oscp, name, &stbuf.st_birthtimespec, errorp); + + out: + if (fd != -1) + close(fd); +} + +/** + * Process a snapshot directory. + * + * Opens the snapshot directory and calls osc_process_snapshot() for each + * entry. (Well ok, "." and ".." are ignored.) The goal here is to add all + * snapshots in the directory to the snapshot set. + */ +static void +osc_process_snapshot_directory(struct osc_snapshot_ctx *oscp, int *errorp) +{ + int fd; + struct stat stbuf; + DIR *dirp; + struct dirent *dp; + + fd = osc_get_names_directory_fd(); + if (fd == -1) + goto out; + + if (fstat(fd, &stbuf) == -1) + goto out; + + dirp = opendir(SNAPSHOT_DIRECTORY); + if (dirp == NULL) + goto out; + + for (;;) { + dp = readdir(dirp); + if (dp == NULL) + break; + + if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + continue; + + osc_process_snapshot(oscp, dp->d_name, errorp); + if (*errorp) + break; + } + + closedir(dirp); + + if (!*errorp) + oscp->osc_mtime = stbuf.st_mtimespec; + + out: + return; +} + +/** + * Initialize a snapshot context object. + * + * Clears all members of the context object. + */ +static void +osc_snapshot_ctx_init(struct osc_snapshot_ctx *oscp) +{ + memset(oscp, 0, sizeof *oscp); +} + +/** + * Desoy a snapshot context object. + * + * Frees all snapshots associated with the snapshot context and then calls + * osc_snapshot_ctx_init() to re-initialize the context object. + */ +static void +osc_snapshot_ctx_clean(struct osc_snapshot_ctx *oscp) +{ + struct osc_snapshot *tmp; + + while (oscp->osc_set != NULL) { + tmp = *(void **)oscp->osc_set; + tdelete(tmp, &oscp->osc_set, osc_snapshot_compare); + osc_snapshot_destroy_list(tmp); + } + + osc_snapshot_ctx_init(oscp); +} + +/** + * Return the "global" snapshot context. + * + * We maintain a single open snapshot context. Return a pointer to it. + */ +static struct osc_snapshot_ctx * +osc_get_snapshot_ctx(void) +{ + static struct osc_snapshot_ctx osc = { 0, { 0, 0 } }; + + return &osc; +} + +/** + * Determine whether a snapshot context is still valid. + * + * "Valid" in this context means "reusable". We can re-use a previous + * snapshot context iff we successfully built a previous snapshot context + * and no snapshots have been created or deleted since we did so. + * A "names" directory exists within our snapshot + * implementation in which all snapshot names are entered. Each time a + * snapshot is created or deleted, an entry must be added or removed. + * When this happens the modification time on the "names" directory + * changes. Therefore, a snapshot context is valid iff the context + * pointer is non-NULL, the cached modification time is non-zero + * (zero means uninitialized), and the modification time of the "names" + * directory matches the cached value. + */ +static int +osc_snapshot_ctx_is_valid(struct osc_snapshot_ctx *oscp) +{ + int fd; + struct stat stbuf; + + if (oscp == NULL) + return 0; + + if (osc_timespec_is_zero(&oscp->osc_mtime)) + return 0; + + fd = osc_get_names_directory_fd(); + if (fd == -1) + return 0; + + if (fstat(fd, &stbuf) == -1) + return 0; + + if (osc_timespec_compare(&oscp->osc_mtime, &stbuf.st_mtimespec) != 0) + return 0; + + return 1; +} + +/** + * Create and initialize a directory context. + * + * Allocates a directory context from the heap and initializes it. + */ +static struct osc_directory_ctx * +osc_directory_ctx_create(void) +{ + struct osc_directory_ctx *idcp; + + idcp = malloc(sizeof *idcp); + if (idcp != NULL) + memset(idcp, 0, sizeof *idcp); + + return idcp; +} + +/** + * Destroy a directory context. + * + * Frees any versions associated with the directory context and then frees the + * context itself. + */ +static void +osc_directory_ctx_destroy(struct osc_directory_ctx *idcp) +{ + int i; + + if (idcp == NULL) + return; + + for (i = 0; i < idcp->idc_len; i++) + free(idcp->idc_version[i]); + + free(idcp); +} + +/** + * Expand the size of a directory context's version list. + * + * If osc_directory_ctx_append_version() detects that the version list is too + * small to accomodate a new version string, it called + * osc_directory_ctx_expand_version_list() to expand the version list. + */ +static void +osc_directory_ctx_expand_version_list(struct osc_snapshot_ctx *oscp, + struct osc_directory_ctx *idcp, int *errorp) +{ + size_t size; + char **cpp; + + size = idcp->idc_size * 2 ?: 1; + + cpp = realloc(idcp->idc_version, size * sizeof (char *)); + if (cpp == NULL) { + *errorp = 1; + return; + } + + idcp->idc_size = size; + idcp->idc_version = cpp; +} + +/** + * Append a new version to a directory context. + * + * Appends a snapshot version to the + * directory context's version list. + */ +static void +osc_directory_ctx_append_version(struct osc_snapshot_ctx *oscp, + struct osc_directory_ctx *idcp, const struct timespec *tsp, int *errorp) +{ + char *cp; + struct tm *tmp; + char text[64]; + + if (idcp->idc_len >= MAX_VERSIONS) + return; + + if (idcp->idc_len >= idcp->idc_size) { + osc_directory_ctx_expand_version_list(oscp, idcp, errorp); + if (*errorp) + return; + } + + tmp = gmtime(&tsp->tv_sec); + if (tmp == NULL) { + *errorp = 1; + return; + } + + snprintf(text, sizeof text, + "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", + tmp->tm_year + 1900, + tmp->tm_mon + 1, + tmp->tm_mday, + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec); + + cp = malloc(strlen(text) + 1); + if (cp == NULL) { + *errorp = 1; + return; + } + + strcpy(cp, text); + + idcp->idc_version[idcp->idc_len++] = cp; +} + +/** + * Make a directory context from a snapshot context. + * + * Once a snapshot context has been completely filled-in, + * osc_make_directory_ctx() is used to build a directory context from it. The + * idea here is to create version for each snapshot in the snapshot set. + */ +static void +osc_make_directory_ctx(struct osc_snapshot_ctx *oscp, + struct osc_directory_ctx *idcp, int *errorp) +{ + static void + walk(const void *vp, VISIT v, int level) + { + const struct osc_snapshot *isp; + + if ((v != postorder && v != leaf) || *errorp) + return; + + isp = *(const struct osc_snapshot **)(u_long)vp; + + osc_directory_ctx_append_version(oscp, idcp, &isp->is_time, + errorp); + } + + twalk(oscp->osc_set, walk); +} + +/** + * Open a version directory. + * + * Opens a version directory. What this really means is that + * osc_version_opendir() returns a handle to a directory context, which can be + * used to retrieve version strings. + */ +void * +osc_version_opendir(void) +{ + int error = 0; + struct osc_directory_ctx *idcp; + struct osc_snapshot_ctx *oscp; + + idcp = osc_directory_ctx_create(); + if (idcp == NULL) + goto error_out; + + oscp = osc_get_snapshot_ctx(); + + if (!osc_snapshot_ctx_is_valid(oscp)) { + osc_snapshot_ctx_clean(oscp); + osc_process_snapshot_directory(oscp, &error); + if (error) + goto error_out; + } + + osc_make_directory_ctx(oscp, idcp, &error); + if (error) + goto error_out; + + goto out; + + error_out: + if (idcp != NULL) { + osc_directory_ctx_destroy(idcp); + idcp = NULL; + } + + out: + return (void *)idcp; +} + +/** + * Read the next version directory entry. + * + * Returns the name of the next version in the version directory, or NULL if + * we're at the end of the directory. What this really does is return the + * next version from the version list stored in the directory context. + */ +char * +osc_version_readdir(void *vp) +{ + struct osc_directory_ctx *idcp = vp; + + if (idcp == NULL) + return NULL; + + if (idcp->idc_pos >= idcp->idc_len) + return NULL; + + return idcp->idc_version[idcp->idc_pos++]; +} + +/** + * Close the version directory. + * + * Destroys the underlying directory context. + */ +void +osc_version_closedir(void *vp) +{ + struct osc_directory_ctx *idcp = vp; + + if (idcp != NULL) + osc_directory_ctx_destroy(idcp); +} + +/** + * Canonicalize a path. + * + * Converts paths of the form @GMT-.. to paths of the form ../.snapshot/.. + * It's not the prettiest routine I've ever written, but what the heck? + */ +char * +osc_canonicalize_path(const char *path, char *snap_component) +{ + int error = 0; + struct osc_snapshot_ctx *oscp; + struct tm tm; + int n; + struct osc_snapshot is; + struct osc_snapshot **ispp; + struct osc_snapshot *isp; + char *cpath = NULL; + char *cpath2 = NULL; + const char *snap_component_orig = snap_component; + struct stat sb; + + oscp = osc_get_snapshot_ctx(); + + if (!osc_snapshot_ctx_is_valid(oscp)) { + osc_snapshot_ctx_clean(oscp); + osc_process_snapshot_directory(oscp, &error); + if (error) + goto out; + } + + memset(&tm, 0, sizeof tm); + n = sscanf(snap_component, + "@GMT-%4u.%2u.%2u-%2u.%2u.%2u", + &tm.tm_year, + &tm.tm_mon, + &tm.tm_mday, + &tm.tm_hour, + &tm.tm_min, + &tm.tm_sec); + if (n != 6) + goto out; + + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + is.is_name = NULL; + is.is_time.tv_sec = timegm(&tm); + is.is_time.tv_nsec = 0; + + ispp = tfind(&is, &oscp->osc_set, osc_snapshot_compare); + if (ispp == NULL) + goto out; + isp = *ispp; + + /* Determine the path after "@GMT-..." */ + while (*snap_component != '/' && *snap_component != '\0') + snap_component++; + + while (*snap_component == '/') + snap_component++; + + cpath = malloc(strlen(SNAPSHOT_DIRECTORY) + strlen(isp->is_name) + + strlen(path) + 3); + + if (cpath == NULL) + goto out; + + /* + * Use the first snapshot that has a successful stat for the requested + * path. + */ + while (true) { + + sprintf(cpath, "%s/%s", SNAPSHOT_DIRECTORY, isp->is_name); + + /* Append path before "@GMT-..." */ + if (snap_component_orig != path) { + strcat(cpath, "/"); + strncat(cpath, path, snap_component_orig - path); + } + + /* Append path after "@GMT-..." */ + if (*snap_component != '\0') { + strcat(cpath, "/"); + strcat(cpath, snap_component); + } + + /* If there is a valid snapshot for this file, we're done. */ + if (stat(cpath, &sb) == 0) + break; + + /* Try the next snapshot. If this was the last one, give up. */ + isp = isp->is_next; + if (isp == NULL) + break; + + /* If the realloc fails, give up. */ + cpath2 = realloc(cpath, strlen(SNAPSHOT_DIRECTORY) + + strlen(isp->is_name) + strlen(path) + 3); + if (cpath2 == NULL) + break; + cpath = cpath2; + } + + out: + return cpath; +} diff --git a/source3/modules/onefs_shadow_copy.h b/source3/modules/onefs_shadow_copy.h new file mode 100644 index 0000000000..6415a4be1a --- /dev/null +++ b/source3/modules/onefs_shadow_copy.h @@ -0,0 +1,32 @@ +/* + * Unix SMB/CIFS implementation. + * + * OneFS shadow copy implementation that utilizes the file system's native + * snapshot support. + * + * Copyright (C) Dave Richards, 2007 + * Copyright (C) Tim Prouty, 2009 + * + * 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 . + */ + +#ifndef ONEFS_SHADOW_COPY_H +#define ONEFS_SHADOW_COPY_H + +void *osc_version_opendir(void); +char *osc_version_readdir(void *vp); +void osc_version_closedir(void *vp); +char *osc_canonicalize_path(const char *path, char *snap_component); + +#endif /* ONEFS_SHADOW_COPY_H */ diff --git a/source3/modules/vfs_onefs_shadow_copy.c b/source3/modules/vfs_onefs_shadow_copy.c new file mode 100644 index 0000000000..28bc0c5081 --- /dev/null +++ b/source3/modules/vfs_onefs_shadow_copy.c @@ -0,0 +1,717 @@ +/* + * OneFS shadow copy implementation that utilizes the file system's native + * snapshot support. This is based on the original shadow copy module from + * 2004. + * + * Copyright (C) Stefan Metzmacher 2003-2004 + * Copyright (C) Tim Prouty 2009 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" +#include "onefs_shadow_copy.h" + +static int vfs_onefs_shadow_copy_debug_level = DBGC_VFS; + +#undef DBGC_CLASS +#define DBGC_CLASS vfs_onefs_shadow_copy_debug_level + +#define SHADOW_COPY_PREFIX "@GMT-" +#define SHADOW_COPY_SAMPLE "@GMT-2004.02.18-15.44.00" + +bool +shadow_copy_match_name(const char *name, char **snap_component) +{ + uint32 i = 0; + char delim[] = SHADOW_COPY_PREFIX; + char* start; + + start = strstr( name, delim ); + + /* + * The name could have SHADOW_COPY_PREFIX in it so we need to keep + * trying until we get something that is the full length of the + * SHADOW_COPY_SAMPLE. + */ + while (start != NULL) { + + DEBUG(10,("Processing %s\n", name)); + + /* size / correctness check */ + *snap_component = start; + for ( i = sizeof(SHADOW_COPY_PREFIX); + i < sizeof(SHADOW_COPY_SAMPLE); i++) { + if (start[i] == '/') { + if (i == sizeof(SHADOW_COPY_SAMPLE) - 1) + return true; + else + break; + } else if (start[i] == '\0') + return (i == sizeof(SHADOW_COPY_SAMPLE) - 1); + } + + start = strstr( start, delim ); + } + + return false; +} + +static int +onefs_shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, + files_struct *fsp, + SHADOW_COPY_DATA *shadow_copy_data, + bool labels) +{ + void *p = osc_version_opendir(); + char *snap_component = NULL; + shadow_copy_data->num_volumes = 0; + shadow_copy_data->labels = NULL; + + if (!p) { + DEBUG(0, ("shadow_copy_get_shadow_copy_data: osc_opendir() " + "failed for [%s]\n",fsp->conn->connectpath)); + return -1; + } + + while (true) { + SHADOW_COPY_LABEL *tlabels; + char *d; + + d = osc_version_readdir(p); + if (d == NULL) + break; + + if (!shadow_copy_match_name(d, &snap_component)) { + DEBUG(10,("shadow_copy_get_shadow_copy_data: ignore " + "[%s]\n",d)); + continue; + } + + DEBUG(7,("shadow_copy_get_shadow_copy_data: not ignore " + "[%s]\n",d)); + + if (!labels) { + shadow_copy_data->num_volumes++; + continue; + } + + tlabels = (SHADOW_COPY_LABEL *)TALLOC_REALLOC( + shadow_copy_data->mem_ctx, + shadow_copy_data->labels, + (shadow_copy_data->num_volumes+1) * + sizeof(SHADOW_COPY_LABEL)); + + if (tlabels == NULL) { + DEBUG(0,("shadow_copy_get_shadow_copy_data: Out of " + "memory\n")); + osc_version_closedir(p); + return -1; + } + + snprintf(tlabels[shadow_copy_data->num_volumes++], + sizeof(*tlabels), "%s",d); + + shadow_copy_data->labels = tlabels; + } + + osc_version_closedir(p); + + return 0; +} + +#define SHADOW_NEXT(op, args, rtype) do { \ + char *cpath = NULL; \ + char *snap_component = NULL; \ + rtype ret; \ + if (shadow_copy_match_name(path, &snap_component)) \ + cpath = osc_canonicalize_path(path, snap_component); \ + ret = SMB_VFS_NEXT_ ## op args; \ + SAFE_FREE(cpath); \ + return ret; \ + } while (0) \ + + + +static uint64_t +onefs_shadow_copy_disk_free(vfs_handle_struct *handle, const char *path, + bool small_query, uint64_t *bsize, uint64_t *dfree, + uint64_t *dsize) +{ + + SHADOW_NEXT(DISK_FREE, + (handle, cpath ?: path, small_query, bsize, dfree, dsize), + uint64_t); + +} + +static int +onefs_shadow_copy_statvfs(struct vfs_handle_struct *handle, const char *path, + struct vfs_statvfs_struct *statbuf) +{ + SHADOW_NEXT(STATVFS, + (handle, cpath ?: path, statbuf), + int); +} + +static SMB_STRUCT_DIR * +onefs_shadow_copy_opendir(vfs_handle_struct *handle, const char *path, + const char *mask, uint32_t attr) +{ + SHADOW_NEXT(OPENDIR, + (handle, cpath ?: path, mask, attr), + SMB_STRUCT_DIR *); +} + +static int +onefs_shadow_copy_mkdir(vfs_handle_struct *handle, const char *path, + mode_t mode) +{ + SHADOW_NEXT(MKDIR, + (handle, cpath ?: path, mode), + int); +} + +static int +onefs_shadow_copy_rmdir(vfs_handle_struct *handle, const char *path) +{ + SHADOW_NEXT(RMDIR, + (handle, cpath ?: path), + int); +} + +static int +onefs_shadow_copy_open(vfs_handle_struct *handle, const char *path, + files_struct *fsp, int flags, mode_t mode) +{ + SHADOW_NEXT(OPEN, + (handle, cpath ?: path, fsp, flags, mode), + int); +} + +static NTSTATUS +onefs_shadow_copy_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *path, + uint32_t create_file_flags, + uint32_t access_mask, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint32_t file_attributes, + uint32_t oplock_request, + uint64_t allocation_size, + struct security_descriptor *sd, + struct ea_list *ea_list, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + SHADOW_NEXT(CREATE_FILE, + (handle, req, root_dir_fid, cpath ?: path, + create_file_flags, access_mask, share_access, + create_disposition, create_options, file_attributes, + oplock_request, allocation_size, sd, ea_list, result, + pinfo, psbuf), + NTSTATUS); +} + +/** + * XXX: macro-ize + */ +static int +onefs_shadow_copy_rename(vfs_handle_struct *handle, const char *old_name, + const char *new_name) +{ + char *old_cpath = NULL; + char *old_snap_component = NULL; + char *new_cpath = NULL; + char *new_snap_component = NULL; + int ret; + + if (shadow_copy_match_name(old_name, &old_snap_component)) + old_cpath = osc_canonicalize_path(old_name, old_snap_component); + + if (shadow_copy_match_name(new_name, &new_snap_component)) + new_cpath = osc_canonicalize_path(new_name, new_snap_component); + + ret = SMB_VFS_NEXT_RENAME(handle, old_cpath ?: old_name, + new_cpath ?: new_name); + + SAFE_FREE(old_cpath); + SAFE_FREE(new_cpath); + + return ret; +} + +static int +onefs_shadow_copy_stat(vfs_handle_struct *handle, const char *path, + SMB_STRUCT_STAT *sbuf) +{ + SHADOW_NEXT(STAT, + (handle, cpath ?: path, sbuf), + int); +} + +static int +onefs_shadow_copy_lstat(vfs_handle_struct *handle, const char *path, + SMB_STRUCT_STAT *sbuf) +{ + SHADOW_NEXT(LSTAT, + (handle, cpath ?: path, sbuf), + int); +} + +static int +onefs_shadow_copy_unlink(vfs_handle_struct *handle, const char *path) +{ + SHADOW_NEXT(UNLINK, + (handle, cpath ?: path), + int); +} + +static int +onefs_shadow_copy_chmod(vfs_handle_struct *handle, const char *path, + mode_t mode) +{ + SHADOW_NEXT(CHMOD, + (handle, cpath ?: path, mode), + int); +} + +static int +onefs_shadow_copy_chown(vfs_handle_struct *handle, const char *path, + uid_t uid, gid_t gid) +{ + SHADOW_NEXT(CHOWN, + (handle, cpath ?: path, uid, gid), + int); +} + +static int +onefs_shadow_copy_lchown(vfs_handle_struct *handle, const char *path, + uid_t uid, gid_t gid) +{ + SHADOW_NEXT(LCHOWN, + (handle, cpath ?: path, uid, gid), + int); +} + +static int +onefs_shadow_copy_chdir(vfs_handle_struct *handle, const char *path) +{ + SHADOW_NEXT(CHDIR, + (handle, cpath ?: path), + int); +} + +static int +onefs_shadow_copy_ntimes(vfs_handle_struct *handle, const char *path, + struct smb_file_time *ft) +{ + SHADOW_NEXT(NTIMES, + (handle, cpath ?: path, ft), + int); + +} + +/** + * XXX: macro-ize + */ +static bool +onefs_shadow_copy_symlink(vfs_handle_struct *handle, + const char *oldpath, const char *newpath) +{ + char *old_cpath = NULL; + char *old_snap_component = NULL; + char *new_cpath = NULL; + char *new_snap_component = NULL; + bool ret; + + if (shadow_copy_match_name(oldpath, &old_snap_component)) + old_cpath = osc_canonicalize_path(oldpath, old_snap_component); + + if (shadow_copy_match_name(newpath, &new_snap_component)) + new_cpath = osc_canonicalize_path(newpath, new_snap_component); + + ret = SMB_VFS_NEXT_SYMLINK(handle, old_cpath ?: oldpath, + new_cpath ?: newpath); + + SAFE_FREE(old_cpath); + SAFE_FREE(new_cpath); + + return ret; +} + +static bool +onefs_shadow_copy_readlink(vfs_handle_struct *handle, const char *path, + char *buf, size_t bufsiz) +{ + SHADOW_NEXT(READLINK, + (handle, cpath ?: path, buf, bufsiz), + bool); +} + +/** + * XXX: macro-ize + */ +static int +onefs_shadow_copy_link(vfs_handle_struct *handle, const char *oldpath, + const char *newpath) +{ + char *old_cpath = NULL; + char *old_snap_component = NULL; + char *new_cpath = NULL; + char *new_snap_component = NULL; + int ret; + + if (shadow_copy_match_name(oldpath, &old_snap_component)) + old_cpath = osc_canonicalize_path(oldpath, old_snap_component); + + if (shadow_copy_match_name(newpath, &new_snap_component)) + new_cpath = osc_canonicalize_path(newpath, new_snap_component); + + ret = SMB_VFS_NEXT_LINK(handle, old_cpath ?: oldpath, + new_cpath ?: newpath); + + SAFE_FREE(old_cpath); + SAFE_FREE(new_cpath); + + return ret; +} + +static int +onefs_shadow_copy_mknod(vfs_handle_struct *handle, const char *path, + mode_t mode, SMB_DEV_T dev) +{ + SHADOW_NEXT(MKNOD, + (handle, cpath ?: path, mode, dev), + int); +} + +static char * +onefs_shadow_copy_realpath(vfs_handle_struct *handle, const char *path, + char *resolved_path) +{ + SHADOW_NEXT(REALPATH, + (handle, cpath ?: path, resolved_path), + char *); +} + +static int onefs_shadow_copy_chflags(struct vfs_handle_struct *handle, + const char *path, unsigned int flags) +{ + SHADOW_NEXT(CHFLAGS, + (handle, cpath ?: path, flags), + int); +} + +static NTSTATUS +onefs_shadow_copy_streaminfo(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *path, + TALLOC_CTX *mem_ctx, + unsigned int *num_streams, + struct stream_struct **streams) +{ + SHADOW_NEXT(STREAMINFO, + (handle, fsp, cpath ?: path, mem_ctx, num_streams, + streams), + NTSTATUS); +} + +static int +onefs_shadow_copy_get_real_filename(struct vfs_handle_struct *handle, + const char *full_path, + const char *path, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + SHADOW_NEXT(GET_REAL_FILENAME, + (handle, full_path, cpath ?: path, mem_ctx, found_name), + int); +} + +static NTSTATUS +onefs_shadow_copy_get_nt_acl(struct vfs_handle_struct *handle, + const char *path, uint32 security_info, + struct security_descriptor **ppdesc) +{ + SHADOW_NEXT(GET_NT_ACL, + (handle, cpath ?: path, security_info, ppdesc), + NTSTATUS); +} + +static int +onefs_shadow_copy_chmod_acl(vfs_handle_struct *handle, const char *path, + mode_t mode) +{ + SHADOW_NEXT(CHMOD_ACL, + (handle, cpath ?: path, mode), + int); +} + +static SMB_ACL_T +onefs_shadow_copy_sys_acl_get_file(vfs_handle_struct *handle, + const char *path, SMB_ACL_TYPE_T type) +{ + SHADOW_NEXT(SYS_ACL_GET_FILE, + (handle, cpath ?: path, type), + SMB_ACL_T); +} + +static int +onefs_shadow_copy_sys_acl_set_file(vfs_handle_struct *handle, const char *path, + SMB_ACL_TYPE_T type, SMB_ACL_T theacl) +{ + SHADOW_NEXT(SYS_ACL_SET_FILE, + (handle, cpath ?: path, type, theacl), + int); +} + +static int +onefs_shadow_copy_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + SHADOW_NEXT(SYS_ACL_DELETE_DEF_FILE, + (handle, cpath ?: path), + int); +} + +static ssize_t +onefs_shadow_copy_getxattr(vfs_handle_struct *handle, const char *path, + const char *name, void *value, size_t size) +{ + SHADOW_NEXT(GETXATTR, + (handle, cpath ?: path, name, value, size), + ssize_t); +} + +static ssize_t +onefs_shadow_copy_lgetxattr(vfs_handle_struct *handle, const char *path, + const char *name, void *value, size_t size) +{ + SHADOW_NEXT(LGETXATTR, + (handle, cpath ?: path, name, value, size), + ssize_t); +} + +static ssize_t +onefs_shadow_copy_listxattr(vfs_handle_struct *handle, const char *path, + char *list, size_t size) +{ + SHADOW_NEXT(LISTXATTR, + (handle, cpath ?: path, list, size), + ssize_t); +} + +static ssize_t +onefs_shadow_copy_llistxattr(vfs_handle_struct *handle, const char *path, + char *list, size_t size) +{ + SHADOW_NEXT(LLISTXATTR, + (handle, cpath ?: path, list, size), + ssize_t); +} + +static int +onefs_shadow_copy_removexattr(vfs_handle_struct *handle, const char *path, + const char *name) +{ + SHADOW_NEXT(REMOVEXATTR, + (handle, cpath ?: path, name), + int); +} + +static int +onefs_shadow_copy_lremovexattr(vfs_handle_struct *handle, const char *path, + const char *name) +{ + SHADOW_NEXT(LREMOVEXATTR, + (handle, cpath ?: path, name), + int); +} + +static int +onefs_shadow_copy_setxattr(vfs_handle_struct *handle, const char *path, + const char *name, const void *value, size_t size, + int flags) +{ + SHADOW_NEXT(SETXATTR, + (handle, cpath ?: path, name, value, size, flags), + int); +} + +static int +onefs_shadow_copy_lsetxattr(vfs_handle_struct *handle, const char *path, + const char *name, const void *value, size_t size, + int flags) +{ + SHADOW_NEXT(LSETXATTR, + (handle, cpath ?: path, name, value, size, flags), + int); +} + +static bool +onefs_shadow_copy_is_offline(struct vfs_handle_struct *handle, + const char *path, SMB_STRUCT_STAT *sbuf) +{ + SHADOW_NEXT(IS_OFFLINE, + (handle, cpath ?: path, sbuf), + bool); +} + +static int +onefs_shadow_copy_set_offline(struct vfs_handle_struct *handle, + const char *path) +{ + SHADOW_NEXT(SET_OFFLINE, + (handle, cpath ?: path), + int); +} + +/* VFS operations structure */ + +static vfs_op_tuple onefs_shadow_copy_ops[] = { + + /* Disk operations */ + + {SMB_VFS_OP(onefs_shadow_copy_disk_free), SMB_VFS_OP_DISK_FREE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_get_shadow_copy_data), + SMB_VFS_OP_GET_SHADOW_COPY_DATA, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(onefs_shadow_copy_statvfs), SMB_VFS_OP_STATVFS, + SMB_VFS_LAYER_TRANSPARENT}, + + /* Directory operations */ + + {SMB_VFS_OP(onefs_shadow_copy_opendir), SMB_VFS_OP_OPENDIR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_mkdir), SMB_VFS_OP_MKDIR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_rmdir), SMB_VFS_OP_RMDIR, + SMB_VFS_LAYER_TRANSPARENT}, + + /* File operations */ + + {SMB_VFS_OP(onefs_shadow_copy_open), SMB_VFS_OP_OPEN, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_create_file), SMB_VFS_OP_CREATE_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_rename), SMB_VFS_OP_RENAME, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_stat), SMB_VFS_OP_STAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_stat), SMB_VFS_OP_STAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_lstat), SMB_VFS_OP_LSTAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_unlink), SMB_VFS_OP_UNLINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_chmod), SMB_VFS_OP_CHMOD, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_chown), SMB_VFS_OP_CHOWN, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_lchown), SMB_VFS_OP_LCHOWN, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_chdir), SMB_VFS_OP_CHDIR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_ntimes), SMB_VFS_OP_NTIMES, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_symlink), SMB_VFS_OP_SYMLINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_readlink), SMB_VFS_OP_READLINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_link), SMB_VFS_OP_LINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_mknod), SMB_VFS_OP_MKNOD, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_realpath), SMB_VFS_OP_REALPATH, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_chflags), SMB_VFS_OP_CHFLAGS, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_streaminfo), SMB_VFS_OP_STREAMINFO, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_get_real_filename), + SMB_VFS_OP_GET_REAL_FILENAME, SMB_VFS_LAYER_TRANSPARENT}, + + /* NT File ACL operations */ + + {SMB_VFS_OP(onefs_shadow_copy_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + + /* POSIX ACL operations */ + + {SMB_VFS_OP(onefs_shadow_copy_chmod_acl), SMB_VFS_OP_CHMOD_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_sys_acl_get_file), + SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_sys_acl_set_file), + SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_sys_acl_delete_def_file), + SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT}, + + /* EA operations. */ + + {SMB_VFS_OP(onefs_shadow_copy_getxattr), SMB_VFS_OP_GETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_lgetxattr), SMB_VFS_OP_LGETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_listxattr), SMB_VFS_OP_LISTXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_llistxattr), SMB_VFS_OP_LLISTXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_removexattr), SMB_VFS_OP_REMOVEXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_lremovexattr), SMB_VFS_OP_LREMOVEXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_setxattr), SMB_VFS_OP_SETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_lsetxattr), SMB_VFS_OP_LSETXATTR, + SMB_VFS_LAYER_TRANSPARENT}, + + /* offline operations */ + {SMB_VFS_OP(onefs_shadow_copy_is_offline), SMB_VFS_OP_IS_OFFLINE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_shadow_copy_set_offline), SMB_VFS_OP_SET_OFFLINE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_shadow_copy_init(void) +{ + NTSTATUS ret; + + ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, + "onefs_shadow_copy", + onefs_shadow_copy_ops); + + if (!NT_STATUS_IS_OK(ret)) + return ret; + + vfs_onefs_shadow_copy_debug_level = debug_add_class("onefs_shadow_copy"); + + if (vfs_onefs_shadow_copy_debug_level == -1) { + vfs_onefs_shadow_copy_debug_level = DBGC_VFS; + DEBUG(0, ("Couldn't register custom debugging class!\n")); + } else { + DEBUG(10, ("Debug class number of 'onefs_shadow_copy': %d\n", + vfs_onefs_shadow_copy_debug_level)); + } + + return ret; +} -- cgit From e6a5f11865a55e9644292ae92e4a4b5ec0662ccd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 20 Feb 2009 08:23:52 -0800 Subject: Fix bug #6133 - Cannot delete non-ACL files on Solaris/ZFS/NFSv4 ACL filesystem. As the NFSv4 ACL mapping code doesn't map write directory into the DELETE_CHILD permission bit (which we require before allowing a delete) no one can delete files without an explicit DELETE_CHILD bit set on the directory. Add this mapping. Jeremy. --- source3/modules/nfs4_acls.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source3/modules') diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 556dad6b5e..ba038479af 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -198,6 +198,7 @@ static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf) static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */ DOM_SID *psid_owner, /* in */ DOM_SID *psid_group, /* in */ + bool is_directory, /* in */ SEC_ACE **ppnt_ace_list, /* out */ int *pgood_aces /* out */ ) @@ -256,6 +257,10 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */ DEBUG(10, ("mapped %d to %s\n", ace->who.id, sid_string_dbg(&sid))); + if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) { + ace->aceMask |= SMB_ACE4_DELETE_CHILD; + } + mask = ace->aceMask; init_sec_ace(&nt_ace_list[good_aces++], &sid, ace->aceType, mask, @@ -287,7 +292,8 @@ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf, uid_to_sid(&sid_owner, sbuf->st_uid); gid_to_sid(&sid_group, sbuf->st_gid); - if (smbacl4_nfs42win(mem_ctx, acl, &sid_owner, &sid_group, &nt_ace_list, &good_aces)==False) { + if (smbacl4_nfs42win(mem_ctx, acl, &sid_owner, &sid_group, S_ISDIR(sbuf->st_mode), + &nt_ace_list, &good_aces)==False) { DEBUG(8,("smbacl4_nfs42win failed\n")); return map_nt_error_from_unix(errno); } -- cgit From 5bd7f9c61bb2fea1867ac6657c9b30799ba49d8f Mon Sep 17 00:00:00 2001 From: Steven Danneman Date: Fri, 20 Feb 2009 13:25:17 -0800 Subject: s3: OneFS implementation of change notify The OneFS Samba implementation of change notify is modeled after the usage of Linux's inotify kernel subsystem. A single call is made into the onefs.so VFS module to initialize kernel tracking of certain file change events. When these events occur a kernel notification is sent to smbd and the notification event is translated and given to the general Samba Change Notify layer through a callback function. The most difficult aspect is converting an SMB CompletionFilter to a matching ifs_event mask, and then back to an appropriate change notify action. Currently, not all possible cases are handled by the this module, but the most prevalent ones, which are tested by smbtorture, are implemented. --- source3/modules/onefs.h | 9 + source3/modules/onefs_notify.c | 680 +++++++++++++++++++++++++++++++++++++++++ source3/modules/vfs_onefs.c | 2 + 3 files changed, 691 insertions(+) create mode 100644 source3/modules/onefs_notify.c (limited to 'source3/modules') diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index c002739f1f..ea452a454d 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -204,6 +204,15 @@ bool onefs_brl_cancel_windows(vfs_handle_struct *handle, struct lock_struct *plock, struct blocking_lock_record *blr); +NTSTATUS onefs_notify_watch(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_p); + NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc); diff --git a/source3/modules/onefs_notify.c b/source3/modules/onefs_notify.c new file mode 100644 index 0000000000..40f690876d --- /dev/null +++ b/source3/modules/onefs_notify.c @@ -0,0 +1,680 @@ +/* + * Unix SMB/CIFS implementation. + * + * Support for change notify using OneFS's file event notification system + * + * Copyright (C) Andrew Tridgell, 2006 + * Copyright (C) Steven Danneman, 2008 + * + * 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 . + */ + +/* Implement handling of change notify requests on files and directories using + * Isilon OneFS's "ifs event" file notification system. + * + * The structure of this file is based off the implementation of change notify + * using the inotify system calls in smbd/notify_inotify.c */ + +/* TODO: We could reduce the number of file descriptors used by merging + * multiple watch requests on the same directory into the same + * onefs_notify_watch_context. To do this we'd need mux/demux routines that + * when receiving an event on that watch context would check it against the + * CompletionFilter and WatchTree of open SMB requests, and return notify + * events back to the proper SMB requests */ + +#include "onefs.h" + +#include +#include +#include + +#include + +#define ONEFS_IFS_EVENT_MAX_NUM 8 +#define ONEFS_IFS_EVENT_MAX_BYTES (ONEFS_IFS_EVENT_MAX_NUM * \ + sizeof(struct ifs_event)) + +struct onefs_notify_watch_context { + struct sys_notify_context *ctx; + int watch_fd; + ino_t watch_lin; + const char *path; + int ifs_event_fd; + uint32_t ifs_filter; /* the ifs event mask */ + uint32_t smb_filter; /* the windows completion filter */ + void (*callback)(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *ev); + void *private_data; +}; + +/** + * Conversion map from a SMB completion filter to an IFS event mask. + */ +static const struct { + uint32_t smb_filter; + uint32_t ifs_filter; +} onefs_notify_conv[] = { + {FILE_NOTIFY_CHANGE_FILE_NAME, + NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO}, + {FILE_NOTIFY_CHANGE_DIR_NAME, + NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO}, + {FILE_NOTIFY_CHANGE_ATTRIBUTES, + NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO | + NOTE_ATTRIB}, + {FILE_NOTIFY_CHANGE_SIZE, + NOTE_SIZE | NOTE_EXTEND}, + {FILE_NOTIFY_CHANGE_LAST_WRITE, + NOTE_WRITE | NOTE_ATTRIB}, + /* OneFS doesn't set atime by default, but we can somewhat fake it by + * notifying for other events that imply ACCESS */ + {FILE_NOTIFY_CHANGE_LAST_ACCESS, + NOTE_WRITE | NOTE_ATTRIB}, + /* We don't have an ifs_event for the setting of create time, but we + * can fake by notifying when a "new" file is created via rename */ + {FILE_NOTIFY_CHANGE_CREATION, + NOTE_RENAME_TO}, + {FILE_NOTIFY_CHANGE_SECURITY, + NOTE_SECURITY}, + /* Unsupported bits + FILE_NOTIFY_CHANGE_EA (no EAs in OneFS) + FILE_NOTIFY_CHANGE_STREAM_NAME (no ifs_event equivalent) + FILE_NOTIFY_CHANGE_STREAM_SIZE (no ifs_event equivalent) + FILE_NOTIFY_CHANGE_STREAM_WRITE (no ifs_event equivalent) */ +}; + +#define ONEFS_NOTIFY_UNSUPPORTED (FILE_NOTIFY_CHANGE_LAST_ACCESS | \ + FILE_NOTIFY_CHANGE_CREATION | \ + FILE_NOTIFY_CHANGE_EA | \ + FILE_NOTIFY_CHANGE_STREAM_NAME | \ + FILE_NOTIFY_CHANGE_STREAM_SIZE | \ + FILE_NOTIFY_CHANGE_STREAM_WRITE) + +/** + * Convert Windows/SMB filter/flags to IFS event filter. + * + * @param[in] smb_filter Windows Completion Filter sent in the SMB + * + * @return ifs event filter mask + */ +static uint32_t +onefs_notify_smb_filter_to_ifs_filter(uint32_t smb_filter) +{ + int i; + uint32_t ifs_filter = 0x0; + + for (i=0;iMoveFile needs to send a modified + * notification on the new file, if smb_filter == ATTRIBUTES. + * Here we handle the case where two separate ATTR & NAME notifications + * have been registered. We handle the case where both bits are set in + * the same registration in onefs_notify_dispatch() */ + if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) && + !(smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && + (ifs_filter & NOTE_FILE) && (ifs_filter & NOTE_RENAME_TO)) + { + return NOTIFY_ACTION_MODIFIED; + } + + /* Special case 2: Writes need to send a modified + * notification on the file, if smb_filter = ATTRIBUTES. */ + if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) && + (ifs_filter & NOTE_FILE) && (ifs_filter & NOTE_WRITE)) + { + return NOTIFY_ACTION_MODIFIED; + } + + /* Loop because some events may be filtered out. Eventually all + * relevant events will be taken care of and returned. */ + while (1) { + if (ifs_filter & NOTE_CREATE) { + ifs_filter &= ~NOTE_CREATE; + if ((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && + (ifs_filter & NOTE_FILE)) + return NOTIFY_ACTION_ADDED; + if ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && + (ifs_filter & NOTE_DIRECTORY)) + return NOTIFY_ACTION_ADDED; + } + else if (ifs_filter & NOTE_DELETE) { + ifs_filter &= ~NOTE_DELETE; + if ((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && + (ifs_filter & NOTE_FILE)) + return NOTIFY_ACTION_REMOVED; + if ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && + (ifs_filter & NOTE_DIRECTORY)) + return NOTIFY_ACTION_REMOVED; + } + else if (ifs_filter & NOTE_WRITE) { + ifs_filter &= ~NOTE_WRITE; + if ((smb_filter & FILE_NOTIFY_CHANGE_LAST_WRITE) || + (smb_filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)) + return NOTIFY_ACTION_MODIFIED; + } + else if ((ifs_filter & NOTE_SIZE) || (ifs_filter & NOTE_EXTEND)) { + ifs_filter &= ~NOTE_SIZE; + ifs_filter &= ~NOTE_EXTEND; + + /* TODO: Do something on NOTE_DIR? */ + if ((smb_filter & FILE_NOTIFY_CHANGE_SIZE) && + (ifs_filter & NOTE_FILE)) + return NOTIFY_ACTION_MODIFIED; + } + else if (ifs_filter & NOTE_ATTRIB) { + ifs_filter &= ~NOTE_ATTRIB; + /* NOTE_ATTRIB needs to be converted to a + * LAST_WRITE as well, because we need to send + * LAST_WRITE when the mtime changes. Looking into + * better alternatives as this causes extra LAST_WRITE + * notifications. We also return LAST_ACCESS as a + * modification to attribs implies this. */ + if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) || + (smb_filter & FILE_NOTIFY_CHANGE_LAST_WRITE) || + (smb_filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)) + return NOTIFY_ACTION_MODIFIED; + } + else if (ifs_filter & NOTE_LINK) { + ifs_filter &= ~NOTE_LINK; + /* NOTE_LINK will send out NO notifications */ + } + else if (ifs_filter & NOTE_REVOKE) { + ifs_filter &= ~NOTE_REVOKE; + /* NOTE_REVOKE will send out NO notifications */ + } + else if (ifs_filter & NOTE_RENAME_FROM) { + ifs_filter &= ~NOTE_RENAME_FROM; + + if (((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && + (ifs_filter & NOTE_FILE)) || + ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && + (ifs_filter & NOTE_DIRECTORY))) { + /* Check if this is a RENAME, not a MOVE */ + if (ifs_filter & NOTE_RENAME_SAMEDIR) { + /* Remove the NOTE_RENAME_SAMEDIR, IFF + * RENAME_TO is not in this event */ + if (!(ifs_filter & NOTE_RENAME_TO)) + ifs_filter &= + ~NOTE_RENAME_SAMEDIR; + return NOTIFY_ACTION_OLD_NAME; + } + return NOTIFY_ACTION_REMOVED; + } + } + else if (ifs_filter & NOTE_RENAME_TO) { + ifs_filter &= ~NOTE_RENAME_TO; + + if (((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && + (ifs_filter & NOTE_FILE)) || + ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && + (ifs_filter & NOTE_DIRECTORY))) { + /* Check if this is a RENAME, not a MOVE */ + if (ifs_filter & NOTE_RENAME_SAMEDIR) { + /* Remove the NOTE_RENAME_SAMEDIR, IFF + * RENAME_FROM is not in this event */ + if (!(ifs_filter & NOTE_RENAME_FROM)) + ifs_filter &= + ~NOTE_RENAME_SAMEDIR; + return NOTIFY_ACTION_NEW_NAME; + } + return NOTIFY_ACTION_ADDED; + } + /* RAW-NOTIFY shows us that a rename triggers a + * creation time change */ + if ((smb_filter & FILE_NOTIFY_CHANGE_CREATION) && + (ifs_filter & NOTE_FILE)) + return NOTIFY_ACTION_MODIFIED; + } + else if (ifs_filter & NOTE_SECURITY) { + ifs_filter &= ~NOTE_SECURITY; + + if (smb_filter & FILE_NOTIFY_CHANGE_SECURITY) + return NOTIFY_ACTION_MODIFIED; + } else { + /* No relevant flags found */ + return 0; + } + } +} + +/** + * Retrieve a directory path of a changed file, relative to the watched dir + * + * @param[in] wc watch context for the returned event + * @param[in] e ifs_event notification returned from the kernel + * @param[out] path name relative to the watched dir. This is talloced + * off of wc and needs to be freed by the caller. + * + * @return true on success + * + * TODO: This function currently doesn't handle path names with multiple + * encodings. enc_get_lin_path() should be used in the future to convert + * each path segment's encoding to UTF-8 + */ +static bool +get_ifs_event_path(struct onefs_notify_watch_context *wc, struct ifs_event *e, + char **path) +{ + char *path_buf = NULL; + size_t pathlen = 0; + int error = 0; + + SMB_ASSERT(path); + + /* Lookup the path from watch_dir through our parent dir */ + if (e->namelen > 0) { + error = lin_get_path(wc->watch_lin, + e->parent_lin, + HEAD_SNAPID, + e->parent_parent_lin, + e->parent_name_hash, + &pathlen, &path_buf); + if (!error) { + /* Only add slash if a path exists in path_buf from + * lin_get_path call. Windows does not expect a + * leading '/' */ + if (pathlen > 0) + *path = talloc_asprintf(wc, "%s/%s", + path_buf, e->name); + else + *path = talloc_asprintf(wc, "%s", e->name); + SAFE_FREE(path_buf); + } + } + + /* If ifs_event didn't return a name, or we errored out of our intial + * path lookup, try again using the lin of the changed file */ + if (!(*path)) { + error = lin_get_path(wc->watch_lin, + e->lin, + HEAD_SNAPID, + e->parent_lin, + e->name_hash, + &pathlen, &path_buf); + if (error) { + /* It's possible that both the lin and the parent lin + * are invalid (or not given) -- we will skip these + * events. */ + DEBUG(3,("Path lookup failed. LINS are invalid: " + "e->lin: 0x%llu, e->parent_lin: 0x%llu, " + "e->parent_parent_lin: 0x%llu\n", + e->lin, e->parent_lin, e->parent_parent_lin)); + SAFE_FREE(path_buf); + return false; + } else { + *path = talloc_asprintf(wc, "%s", path_buf); + DEBUG(5, ("Using path from event LIN = %s\n", + path_buf)); + SAFE_FREE(path_buf); + } + } + + /* Replacement of UNIX slashes with WIN slashes is handled at a + * higher layer. */ + + return true; +} + +/** + * Dispatch one OneFS notify event to the general Samba code + * + * @param[in] wc watch context for the returned event + * @param[in] e event returned from the kernel + * + * @return nothing + */ +static void +onefs_notify_dispatch(struct onefs_notify_watch_context *wc, + struct ifs_event *e) +{ + char *path = NULL; + struct notify_event ne; + + DEBUG(5, ("Retrieved ifs event from kernel: lin=%#llx, ifs_events=%#x, " + "parent_lin=%#llx, namelen=%d, name=\"%s\"\n", + e->lin, e->events, e->parent_lin, e->namelen, e->name)); + + /* Check validity of event returned from kernel */ + if (e->lin == 0) { + /* The lin == 0 specifies 1 of 2 cases: + * 1) We are out of events. The kernel has a limited + * amount (somewhere near 90000) + * 2) Split nodes have merged back and had data written + * to them -- thus we've missed some of those events. */ + DEBUG(3, ("We've missed some kernel ifs events!\n")); + + /* Alert higher level to the problem so it returns catch-all + * response to the client */ + ne.path = NULL; + ne.action = 0; + wc->callback(wc->ctx, wc->private_data, &ne); + } + + if (e->lin == wc->watch_lin) { + /* Windows doesn't report notifications on root + * watched directory */ + /* TODO: This should be abstracted out to the general layer + * instead of being handled in every notify provider */ + DEBUG(5, ("Skipping notification on root of the watched " + "path.\n")); + return; + } + + /* Retrieve the full path for the ifs event name */ + if(!get_ifs_event_path(wc, e, &path)) { + DEBUG(3, ("Failed to convert the ifs_event lins to a path. " + "Skipping this event\n")); + return; + } + + if (!strncmp(path, ".ifsvar", 7)) { + /* Skip notifications on file if its in ifs configuration + * directory */ + goto clean; + } + + ne.path = path; + + /* Convert ifs event mask to an smb action mask */ + ne.action = onefs_notify_ifs_filter_to_smb_action(wc->smb_filter, + e->events); + + DEBUG(5, ("Converted smb_filter=%#x, ifs_events=%#x, to " + "ne.action = %d, for ne.path = %s\n", + wc->smb_filter, e->events, ne.action, ne.path)); + + if (!ne.action) + goto clean; + + /* Return notify_event to higher level */ + wc->callback(wc->ctx, wc->private_data, &ne); + + /* SMB expects a file rename/move to generate three actions, a + * rename_from/delete on the from file, a rename_to/create on the to + * file, and a modify for the rename_to file. If we have two separate + * notifications registered for ATTRIBUTES and FILENAME, this case will + * be handled by separate ifs_events in + * onefs_notify_ifs_filter_to_smb_action(). If both bits are registered + * in the same notification, we must send an extra MODIFIED action + * here. */ + if ((wc->smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) && + (wc->smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && + (e->events & NOTE_FILE) && (e->events & NOTE_RENAME_TO)) + { + ne.action = NOTIFY_ACTION_MODIFIED; + wc->callback(wc->ctx, wc->private_data, &ne); + } + + /* FALLTHROUGH */ +clean: + talloc_free(path); + return; +} + +/** + * Callback when the kernel has some events for us + * + * Read events off ifs event fd and pass them to our dispatch function + * + * @param ev context of all tevents registered in the smbd + * @param fde tevent struct specific to one ifs event channel + * @param flags tevent flags passed when we added our ifs event channel fd to + * the main loop + * @param private_data onefs_notify_watch_context specific to this ifs event + * channel + * + * @return nothing + */ +static void +onefs_notify_handler(struct event_context *ev, + struct fd_event *fde, + uint16_t flags, + void *private_data) +{ + struct onefs_notify_watch_context *wc = NULL; + struct ifs_event ifs_events[ONEFS_IFS_EVENT_MAX_NUM]; + ssize_t nread = 0; + int count = 0; + int i = 0; + + wc = talloc_get_type(private_data, struct onefs_notify_watch_context); + + /* Read as many ifs events from the notify channel as we can */ + nread = sys_read(wc->ifs_event_fd, &ifs_events, + ONEFS_IFS_EVENT_MAX_BYTES); + if (nread == 0) { + DEBUG(0,("No data found while reading ifs event fd?!\n")); + return; + } + if (nread < 0) { + DEBUG(0,("Failed to read ifs event data: %s\n", + strerror(errno))); + return; + } + + count = nread / sizeof(struct ifs_event); + + DEBUG(5, ("Got %d notification events in %d bytes.\n", count, nread)); + + /* Dispatch ifs_events one-at-a-time to higher level */ + for (i=0; i < count; i++) { + onefs_notify_dispatch(wc, &ifs_events[i]); + } +} + +/** + * Destroy the ifs event channel + * + * This is called from talloc_free() when the generic Samba notify layer frees + * the onefs_notify_watch_context. + * + * @param[in] wc pointer to watch context which is being destroyed + * + * return 0 on success +*/ +static int +onefs_watch_destructor(struct onefs_notify_watch_context *wc) +{ + /* The ifs_event_fd will re de-registered from the event loop by + * another destructor triggered from the freeing of this wc */ + close(wc->ifs_event_fd); + return 0; +} + +/** + * Register a single change notify watch request. + * + * Open an event listener on a directory to watch for modifications. This + * channel is closed by a destructor when the caller calls talloc_free() + * on *handle. + * + * @param[in] vfs_handle handle given to most VFS operations + * @param[in] ctx context (conn and tevent) for this connection + * @param[in] e filter and path of client's notify request + * @param[in] callback function to call when file notification event is received + * from the kernel, passing that event up to Samba's + * generalized change notify layer + * @param[in] private_data opaque data given to us by the general change notify + * layer which must be returned in the callback function + * @param[out] handle_p handle returned to generalized change notify layer used + * to close the event channel when notification is + * cancelled + * + * @return NT_STATUS_OK unless error + */ +NTSTATUS +onefs_notify_watch(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_p) +{ + int ifs_event_fd = -1; + uint32_t ifs_filter = 0; + uint32_t smb_filter = e->filter; + bool watch_tree = !!e->subdir_filter; + struct onefs_notify_watch_context *wc = NULL; + void **handle = (void **)handle_p; + SMB_STRUCT_STAT sbuf; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + + /* Fallback to default Samba implementation if kernel CN is disabled */ + if (!lp_kernel_change_notify(vfs_handle->conn->params)) { + (*handle) = NULL; + return NT_STATUS_OK; + } + + /* The OneFS open path should always give us a valid fd on a directory*/ + SMB_ASSERT(e->dir_fd >= 0); + + /* Always set e->filter to 0 so we don't fallback on the default change + * notify backend. It's not cluster coherent or cross-protocol so we + * can't guarantee correctness using it. */ + e->filter = 0; + e->subdir_filter = 0; + + /* Snapshots do not currently allow event listeners. See Isilon + * bug 33476 for an example of .snapshot debug spew that can occur. */ + if (e->dir_id.extid != HEAD_SNAPID) + return NT_STATUS_INVALID_PARAMETER; + + /* Convert Completion Filter mask to IFS Event mask */ + ifs_filter = onefs_notify_smb_filter_to_ifs_filter(smb_filter); + + if (smb_filter & ONEFS_NOTIFY_UNSUPPORTED) { + /* One or more of the filter bits could not be fully handled by + * the ifs_event system. To be correct, if we cannot service a + * bit in the completion filter we should return + * NT_STATUS_NOT_IMPLEMENTED to let the client know that they + * won't be receiving all the notify events that they asked for. + * Unfortunately, WinXP clients cache this error message, stop + * trying to send any notify requests at all, and instead return + * NOT_IMPLEMENTED to all requesting apps without ever sending a + * message to us. Thus we lie, and say we can service all bits, + * but simply don't return actions for the filter bits we can't + * detect or fully implement. */ + DEBUG(3,("One or more of the Windows completion filter bits " + "for \"%s\" could not be fully handled by the " + "ifs_event system. The failed bits are " + "smb_filter=%#x\n", + e->path, smb_filter & ONEFS_NOTIFY_UNSUPPORTED)); + } + + if (ifs_filter == 0) { + /* None of the filter bits given are supported by the ifs_event + * system. Don't create a kernel notify channel, but mock + * up a fake handle for the caller. */ + DEBUG(3,("No bits in the Windows completion filter could be " + "translated to ifs_event mask for \"%s\", " + "smb_filter=%#x\n", e->path, smb_filter)); + (*handle) = NULL; + return NT_STATUS_OK; + } + + /* Register an ifs event channel for this watch request */ + ifs_event_fd = ifs_create_listener(watch_tree ? + EVENT_RECURSIVE : + EVENT_CHILDREN, + ifs_filter, + e->dir_fd); + if (ifs_event_fd < 0) { + DEBUG(0,("Failed to create listener for %s with \"%s\". " + "smb_filter=0x%x, ifs_filter=0x%x, watch_tree=%u\n", + strerror(errno), e->path, smb_filter, ifs_filter, + watch_tree)); + return map_nt_error_from_unix(errno); + } + + /* Create a watch context to track this change notify request */ + wc = talloc(ctx, struct onefs_notify_watch_context); + if (wc == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err; + } + + /* Get LIN for directory */ + if (sys_fstat(e->dir_fd, &sbuf)) { + DEBUG(0, ("stat on directory fd failed: %s\n", + strerror(errno))); + status = map_nt_error_from_unix(errno); + goto err; + } + + if (sbuf.st_ino == 0) { + DEBUG(0, ("0 LIN found!\n")); + goto err; + } + + wc->ctx = ctx; + wc->watch_fd = e->dir_fd; + wc->watch_lin = sbuf.st_ino; + wc->ifs_event_fd = ifs_event_fd; + wc->ifs_filter = ifs_filter; + wc->smb_filter = smb_filter; + wc->callback = callback; + wc->private_data = private_data; + wc->path = talloc_strdup(wc, e->path); + if (wc->path == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err; + } + + (*handle) = wc; + + /* The caller frees the handle to stop watching */ + talloc_set_destructor(wc, onefs_watch_destructor); + + /* Add a tevent waiting for the ifs event fd to be readable */ + event_add_fd(ctx->ev, wc, wc->ifs_event_fd, EVENT_FD_READ, + onefs_notify_handler, wc); + + DEBUG(10, ("Watching for changes on \"%s\" smb_filter=0x%x, " + "ifs_filter=0x%x, watch_tree=%d, ifs_event_fd=%d, " + "dir_fd=%d, dir_lin=0x%llx\n", + e->path, smb_filter, ifs_filter, watch_tree, + ifs_event_fd, e->dir_fd, sbuf.st_ino)); + + return NT_STATUS_OK; + +err: + talloc_free(wc); + SMB_ASSERT(ifs_event_fd >= 0); + close(ifs_event_fd); + return status; +} diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index 522b94399d..f0c6a9d8bb 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -368,6 +368,8 @@ static vfs_op_tuple onefs_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_brl_cancel_windows), SMB_VFS_OP_BRL_CANCEL_WINDOWS, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(onefs_notify_watch), SMB_VFS_OP_NOTIFY_WATCH, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, -- cgit From 5300dc62888dfd36479353f4a6ea5cb52728c754 Mon Sep 17 00:00:00 2001 From: Zack Kirsch Date: Fri, 20 Feb 2009 15:20:39 -0800 Subject: s3 OneFS: Add debugging for createfile_flags --- source3/modules/onefs_system.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c index 6f93d9ff97..3a86b4b815 100644 --- a/source3/modules/onefs_system.c +++ b/source3/modules/onefs_system.c @@ -123,17 +123,29 @@ int onefs_sys_create_file(connection_struct *conn, /* Convert samba dos flags to UF_DOS_* attributes. */ onefs_dos_attributes = dos_attributes_to_stat_dos_flags(dos_flags); + /** + * Deal with kernel creating Default ACLs. (Isilon bug 47447.) + * + * 1) "nt acl support = no", default_acl = no + * 2) "inherit permissions = yes", default_acl = no + */ + if (lp_nt_acl_support(SNUM(conn)) && !lp_inherit_perms(SNUM(conn))) + cf_flags = cf_flags_or(cf_flags, CF_FLAGS_DEFAULT_ACL); + DEBUG(10,("onefs_sys_create_file: base_fd = %d, " - "open_access_mask = 0x%x, flags = 0x%x, mode = 0x%x, " + "open_access_mask = 0x%x, flags = 0x%x, mode = 0%o, " "desired_oplock = %s, id = 0x%x, secinfo = 0x%x, sd = %p, " - "dos_attributes = 0x%x, path = %s\n", base_fd, + "dos_attributes = 0x%x, path = %s, " + "default_acl=%s\n", base_fd, (unsigned int)open_access_mask, (unsigned int)flags, (unsigned int)mode, onefs_oplock_str(onefs_oplock), (unsigned int)id, (unsigned int)secinfo, sd, - (unsigned int)onefs_dos_attributes, path)); + (unsigned int)onefs_dos_attributes, path, + cf_flags_and_bool(cf_flags, CF_FLAGS_DEFAULT_ACL) ? + "true" : "false")); /* Initialize smlock struct for files/dirs but not internal opens */ if (!(oplock_request & INTERNAL_OPEN_ONLY)) { @@ -144,15 +156,6 @@ int onefs_sys_create_file(connection_struct *conn, smlock_dump(10, psml); - /** - * Deal with kernel creating Default ACLs. (Isilon bug 47447.) - * - * 1) "nt acl support = no", default_acl = no - * 2) "inherit permissions = yes", default_acl = no - */ - if (lp_nt_acl_support(SNUM(conn)) && !lp_inherit_perms(SNUM(conn))) - cf_flags = cf_flags_or(cf_flags, CF_FLAGS_DEFAULT_ACL); - ret_fd = ifs_createfile(base_fd, path, (enum ifs_ace_rights)open_access_mask, flags & ~O_ACCMODE, mode, onefs_oplock, id, psml, secinfo, pifs_sd, onefs_dos_attributes, -- cgit From 8ec9903426ec4e559df8ac8306a8ebcdf0706176 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Fri, 20 Feb 2009 13:27:39 -0800 Subject: s3 OneFS: Add an atomic sendfile implementation --- source3/modules/onefs.h | 10 ++ source3/modules/onefs_system.c | 257 +++++++++++++++++++++++++++++++++++++++++ source3/modules/vfs_onefs.c | 15 +++ 3 files changed, 282 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index ea452a454d..a70664bbf3 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -47,6 +47,8 @@ enum onefs_acl_wire_format #define PARM_ATIME_STATIC_DEFAULT NULL #define PARM_ATIME_SLOP "atime now slop" #define PARM_ATIME_SLOP_DEFAULT 0 +#define PARM_ATOMIC_SENDFILE "atomic sendfile" +#define PARM_ATOMIC_SENDFILE_DEFAULT true #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control" #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true #define PARM_CTIME_NOW "ctime now files" @@ -63,6 +65,10 @@ enum onefs_acl_wire_format #define PARM_MTIME_SLOP_DEFAULT 0 #define PARM_USE_READDIRPLUS "use readdirplus" #define PARM_USE_READDIRPLUS_DEFAULT true +#define PARM_SENDFILE_LARGE_READS "sendfile large reads" +#define PARM_SENDFILE_LARGE_READS_DEFAULT false +#define PARM_SENDFILE_SAFE "sendfile safe" +#define PARM_SENDFILE_SAFE_DEFAULT true #define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE "simple file sharing compatibility mode" #define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false #define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE "unmappable sids deny everyone" @@ -254,6 +260,10 @@ int onefs_sys_create_file(connection_struct *conn, uint32_t ntfs_flags, int *granted_oplock); +ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, + const DATA_BLOB *header, SMB_OFF_T offset, + size_t count); + ssize_t onefs_sys_recvfile(int fromfd, int tofd, SMB_OFF_T offset, size_t count); diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c index 3a86b4b815..10802895cd 100644 --- a/source3/modules/onefs_system.c +++ b/source3/modules/onefs_system.c @@ -177,6 +177,263 @@ int onefs_sys_create_file(connection_struct *conn, return ret_fd; } +/** + * FreeBSD based sendfile implementation that allows for atomic semantics. + */ +static ssize_t onefs_sys_do_sendfile(int tofd, int fromfd, + const DATA_BLOB *header, SMB_OFF_T offset, size_t count, bool atomic) +{ + size_t total=0; + struct sf_hdtr hdr; + struct iovec hdtrl; + size_t hdr_len = 0; + int flags = 0; + + if (atomic) { + flags = SF_ATOMIC; + } + + hdr.headers = &hdtrl; + hdr.hdr_cnt = 1; + hdr.trailers = NULL; + hdr.trl_cnt = 0; + + /* Set up the header iovec. */ + if (header) { + hdtrl.iov_base = header->data; + hdtrl.iov_len = hdr_len = header->length; + } else { + hdtrl.iov_base = NULL; + hdtrl.iov_len = 0; + } + + total = count; + while (total + hdtrl.iov_len) { + SMB_OFF_T nwritten; + int ret; + + /* + * FreeBSD sendfile returns 0 on success, -1 on error. + * Remember, the tofd and fromfd are reversed..... :-). + * nwritten includes the header data sent. + */ + + do { + ret = sendfile(fromfd, tofd, offset, total, &hdr, + &nwritten, flags); + } while (ret == -1 && errno == EINTR); + + /* On error we're done. */ + if (ret == -1) { + return -1; + } + + /* + * If this was an ATOMIC sendfile, nwritten doesn't + * necessarily indicate an error. It could mean count > than + * what sendfile can handle atomically (usually 64K) or that + * there was a short read due to the file being truncated. + */ + if (nwritten == 0) { + return atomic ? 0 : -1; + } + + /* + * An atomic sendfile should never send partial data! + */ + if (atomic && nwritten != total + hdtrl.iov_len) { + DEBUG(0,("Atomic sendfile() sent partial data: " + "%llu of %d\n", nwritten, + total + hdtrl.iov_len)); + return -1; + } + + /* + * If this was a short (signal interrupted) write we may need + * to subtract it from the header data, or null out the header + * data altogether if we wrote more than hdtrl.iov_len bytes. + * We change nwritten to be the number of file bytes written. + */ + + if (hdtrl.iov_base && hdtrl.iov_len) { + if (nwritten >= hdtrl.iov_len) { + nwritten -= hdtrl.iov_len; + hdtrl.iov_base = NULL; + hdtrl.iov_len = 0; + } else { + hdtrl.iov_base = + (caddr_t)hdtrl.iov_base + nwritten; + hdtrl.iov_len -= nwritten; + nwritten = 0; + } + } + total -= nwritten; + offset += nwritten; + } + return count + hdr_len; +} + +/** + * Handles the subtleties of using sendfile with CIFS. + */ +ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, + const DATA_BLOB *header, SMB_OFF_T offset, + size_t count) +{ + bool atomic = false; + ssize_t ret = 0; + + if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_ATOMIC_SENDFILE, + PARM_ATOMIC_SENDFILE_DEFAULT)) { + atomic = true; + } + + /* Try the sendfile */ + ret = onefs_sys_do_sendfile(tofd, fromfd, header, offset, count, + atomic); + + /* If the sendfile wasn't atomic, we're done. */ + if (!atomic) { + DEBUG(10, ("non-atomic sendfile read %ul bytes", ret)); + return ret; + } + + /* + * Atomic sendfile takes care to not write anything to the socket + * until all of the requested bytes have been read from the file. + * There are two atomic cases that need to be handled. + * + * 1. The file was truncated causing less data to be read than was + * requested. In this case, we return back to the caller to + * indicate 0 bytes were written to the socket. This should + * prompt the caller to fallback to the standard read path: read + * the data, create a header that indicates how many bytes were + * actually read, and send the header/data back to the client. + * + * This saves us from standard sendfile behavior of sending a + * header promising more data then will actually be sent. The + * only two options are to close the socket and kill the client + * connection, or write a bunch of 0s. Closing the client + * connection is bad because there could actually be multiple + * sessions multiplexed from the same client that are all dropped + * because of a truncate. Writing the remaining data as 0s also + * isn't good, because the client will have an incorrect version + * of the file. If the file is written back to the server, the 0s + * will be written back. Fortunately, atomic sendfile allows us + * to avoid making this choice in most cases. + * + * 2. One downside of atomic sendfile, is that there is a limit on + * the number of bytes that can be sent atomically. The kernel + * has a limited amount of mbuf space that it can read file data + * into without exhausting the system's mbufs, so a buffer of + * length xfsize is used. The xfsize at the time of writing this + * is 64K. xfsize bytes are read from the file, and subsequently + * written to the socket. This makes it impossible to do the + * sendfile atomically for a byte count > xfsize. + * + * To cope with large requests, atomic sendfile returns -1 with + * errno set to E2BIG. Since windows maxes out at 64K writes, + * this is currently only a concern with non-windows clients. + * Posix extensions allow the full 24bit bytecount field to be + * used in ReadAndX, and clients such as smbclient and the linux + * cifs client can request up to 16MB reads! There are a few + * options for handling large sendfile requests. + * + * a. Fall back to the standard read path. This is unacceptable + * because it would require prohibitively large mallocs. + * + * b. Fall back to using samba's fake_send_file which emulates + * the kernel sendfile in userspace. This still has the same + * problem of sending the header before all of the data has + * been read, so it doesn't buy us anything, and has worse + * performance than the kernel's zero-copy sendfile. + * + * c. Use non-atomic sendfile syscall to attempt a zero copy + * read, and hope that there isn't a short read due to + * truncation. In the case of a short read, there are two + * options: + * + * 1. Kill the client connection + * + * 2. Write zeros to the socket for the remaining bytes + * promised in the header. + * + * It is safer from a data corruption perspective to kill the + * client connection, so this is our default behavior, but if + * this causes problems this can be configured to write zeros + * via smb.conf. + */ + + /* Handle case 1: short read -> truncated file. */ + if (ret == 0) { + return ret; + } + + /* Handle case 2: large read. */ + if (ret == -1 && errno == E2BIG) { + + if (!lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_SENDFILE_LARGE_READS, + PARM_SENDFILE_LARGE_READS_DEFAULT)) { + DEBUG(3, ("Not attempting non-atomic large sendfile: " + "%lu bytes\n", count)); + return 0; + } + + if (count < 0x10000) { + DEBUG(0, ("Count < 2^16 and E2BIG was returned! %lu", + count)); + } + + DEBUG(10, ("attempting non-atomic large sendfile: %lu bytes\n", + count)); + + /* Try a non-atomic sendfile. */ + ret = onefs_sys_do_sendfile(tofd, fromfd, header, offset, + count, false); + /* Real error: kill the client connection. */ + if (ret == -1) { + DEBUG(1, ("error on non-atomic large sendfile " + "(%lu bytes): %s\n", count, + strerror(errno))); + return ret; + } + + /* Short read: kill the client connection. */ + if (ret != count + header->length) { + DEBUG(1, ("short read on non-atomic large sendfile " + "(%lu of %lu bytes): %s\n", ret, count, + strerror(errno))); + + /* + * Returning ret here would cause us to drop into the + * codepath that calls sendfile_short_send, which + * sends the client a bunch of zeros instead. + * Returning -1 kills the connection. + */ + if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_SENDFILE_SAFE, + PARM_SENDFILE_SAFE_DEFAULT)) { + return -1; + } + + return ret; + } + + DEBUG(10, ("non-atomic large sendfile successful\n")); + } + + /* There was error in the atomic sendfile. */ + if (ret == -1) { + DEBUG(1, ("error on %s sendfile (%lu bytes): %s\n", + atomic ? "atomic" : "non-atomic", + count, strerror(errno))); + } + + return ret; +} + /** * Only talloc the spill buffer once (reallocing when necessary). */ diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index f0c6a9d8bb..60c2c977a4 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -156,6 +156,19 @@ static int onefs_open(vfs_handle_struct *handle, const char *fname, return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); } +static ssize_t onefs_sendfile(vfs_handle_struct *handle, int tofd, + files_struct *fromfsp, const DATA_BLOB *header, + SMB_OFF_T offset, size_t count) +{ + ssize_t result; + + START_PROFILE_BYTES(syscall_sendfile, count); + result = onefs_sys_sendfile(handle->conn, tofd, fromfsp->fh->fd, + header, offset, count); + END_PROFILE(syscall_sendfile); + return result; +} + static ssize_t onefs_recvfile(vfs_handle_struct *handle, int fromfd, files_struct *tofsp, SMB_OFF_T offset, size_t count) @@ -340,6 +353,8 @@ static vfs_op_tuple onefs_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_sendfile), SMB_VFS_OP_SENDFILE, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_recvfile), SMB_VFS_OP_RECVFILE, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_rename), SMB_VFS_OP_RENAME, -- cgit From 0b62cdbed0867d0712821953700062727f668c65 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 23 Feb 2009 15:03:29 -0800 Subject: Quieten down a boatload of shadowed variable warnings on Solaris. Makes real problems easier to spot. Jeremy. --- source3/modules/nfs4_acls.c | 84 ++++++++++++++++++++++----------------------- source3/modules/nfs4_acls.h | 10 +++--- 2 files changed, 47 insertions(+), 47 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index ba038479af..7756f8f3ab 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -44,10 +44,10 @@ typedef struct _SMB_ACL4_INT_T SMB_ACE4_INT_T *last; } SMB_ACL4_INT_T; -static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *acl) +static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl) { - SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)acl; - if (acl==NULL) + SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl; + if (theacl==NULL) { DEBUG(2, ("acl is NULL\n")); errno = EINVAL; @@ -83,21 +83,21 @@ static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace) SMB4ACL_T *smb_create_smb4acl(void) { TALLOC_CTX *mem_ctx = talloc_tos(); - SMB_ACL4_INT_T *acl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T)); - if (acl==NULL) + SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T)); + if (theacl==NULL) { DEBUG(0, ("TALLOC_SIZE failed\n")); errno = ENOMEM; return NULL; } - acl->magic = SMB_ACL4_INT_MAGIC; - /* acl->first, last = NULL not needed */ - return (SMB4ACL_T *)acl; + theacl->magic = SMB_ACL4_INT_MAGIC; + /* theacl->first, last = NULL not needed */ + return (SMB4ACL_T *)theacl; } -SMB4ACE_T *smb_add_ace4(SMB4ACL_T *acl, SMB_ACE4PROP_T *prop) +SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop) { - SMB_ACL4_INT_T *aclint = get_validated_aclint(acl); + SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl); TALLOC_CTX *mem_ctx = talloc_tos(); SMB_ACE4_INT_T *ace; @@ -143,18 +143,18 @@ SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace) return (SMB4ACE_T *)aceint->next; } -SMB4ACE_T *smb_first_ace4(SMB4ACL_T *acl) +SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl) { - SMB_ACL4_INT_T *aclint = get_validated_aclint(acl); + SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl); if (aclint==NULL) return NULL; return (SMB4ACE_T *)aclint->first; } -uint32 smb_get_naces(SMB4ACL_T *acl) +uint32 smb_get_naces(SMB4ACL_T *theacl) { - SMB_ACL4_INT_T *aclint = get_validated_aclint(acl); + SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl); if (aclint==NULL) return 0; @@ -195,7 +195,7 @@ static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf) return 0; } -static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */ +static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */ DOM_SID *psid_owner, /* in */ DOM_SID *psid_group, /* in */ bool is_directory, /* in */ @@ -203,15 +203,15 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */ int *pgood_aces /* out */ ) { - SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)acl; + SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl; SMB_ACE4_INT_T *aceint; SEC_ACE *nt_ace_list = NULL; int good_aces = 0; DEBUG(10, ("smbacl_nfs42win entered")); - aclint = get_validated_aclint(acl); - /* We do not check for naces being 0 or acl being NULL here because it is done upstream */ + aclint = get_validated_aclint(theacl); + /* We do not check for naces being 0 or theacl being NULL here because it is done upstream */ /* in smb_get_nt_acl_nfs4(). */ nt_ace_list = (SEC_ACE *)TALLOC_ZERO_SIZE(mem_ctx, aclint->naces * sizeof(SEC_ACE)); if (nt_ace_list==NULL) @@ -275,7 +275,7 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf, uint32 security_info, - SEC_DESC **ppdesc, SMB4ACL_T *acl) + SEC_DESC **ppdesc, SMB4ACL_T *theacl) { int good_aces = 0; DOM_SID sid_owner, sid_group; @@ -284,7 +284,7 @@ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf, SEC_ACL *psa = NULL; TALLOC_CTX *mem_ctx = talloc_tos(); - if (acl==NULL || smb_get_naces(acl)==0) + if (theacl==NULL || smb_get_naces(theacl)==0) return NT_STATUS_ACCESS_DENIED; /* special because we * shouldn't alloc 0 for * win */ @@ -292,7 +292,7 @@ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf, uid_to_sid(&sid_owner, sbuf->st_uid); gid_to_sid(&sid_group, sbuf->st_gid); - if (smbacl4_nfs42win(mem_ctx, acl, &sid_owner, &sid_group, S_ISDIR(sbuf->st_mode), + if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group, S_ISDIR(sbuf->st_mode), &nt_ace_list, &good_aces)==False) { DEBUG(8,("smbacl4_nfs42win failed\n")); return map_nt_error_from_unix(errno); @@ -322,7 +322,7 @@ static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf, NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp, uint32 security_info, - SEC_DESC **ppdesc, SMB4ACL_T *acl) + SEC_DESC **ppdesc, SMB4ACL_T *theacl) { SMB_STRUCT_STAT sbuf; @@ -332,13 +332,13 @@ NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp, return map_nt_error_from_unix(errno); } - return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl); + return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl); } NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn, const char *name, uint32 security_info, - SEC_DESC **ppdesc, SMB4ACL_T *acl) + SEC_DESC **ppdesc, SMB4ACL_T *theacl) { SMB_STRUCT_STAT sbuf; @@ -348,7 +348,7 @@ NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn, return map_nt_error_from_unix(errno); } - return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl); + return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl); } enum smbacl4_mode_enum {e_simple=0, e_special=1}; @@ -399,9 +399,9 @@ static int smbacl4_get_vfs_params( return 0; } -static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *acl) +static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl) { - SMB_ACL4_INT_T *aclint = get_validated_aclint(acl); + SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl); SMB_ACE4_INT_T *aceint; DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces)); @@ -423,10 +423,10 @@ static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *acl) * return ace if found matching; otherwise NULL */ static SMB_ACE4PROP_T *smbacl4_find_equal_special( - SMB4ACL_T *acl, + SMB4ACL_T *theacl, SMB_ACE4PROP_T *aceNew) { - SMB_ACL4_INT_T *aclint = get_validated_aclint(acl); + SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl); SMB_ACE4_INT_T *aceint; for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) { @@ -618,14 +618,14 @@ static bool smbacl4_fill_ace4( static int smbacl4_MergeIgnoreReject( enum smbacl4_acedup_enum acedup, - SMB4ACL_T *acl, /* may modify it */ + SMB4ACL_T *theacl, /* may modify it */ SMB_ACE4PROP_T *ace, /* the "new" ACE */ bool *paddNewACE, int i ) { int result = 0; - SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(acl, ace); + SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace); if (ace4found) { switch(acedup) @@ -658,14 +658,14 @@ static SMB4ACL_T *smbacl4_win2nfs4( gid_t ownerGID ) { - SMB4ACL_T *acl; + SMB4ACL_T *theacl; uint32 i; TALLOC_CTX *mem_ctx = talloc_tos(); DEBUG(10, ("smbacl4_win2nfs4 invoked\n")); - acl = smb_create_smb4acl(); - if (acl==NULL) + theacl = smb_create_smb4acl(); + if (theacl==NULL) return NULL; for(i=0; inum_aces; i++) { @@ -682,16 +682,16 @@ static SMB4ACL_T *smbacl4_win2nfs4( } if (pparams->acedup!=e_dontcare) { - if (smbacl4_MergeIgnoreReject(pparams->acedup, acl, + if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl, &ace_v4, &addNewACE, i)) return NULL; } if (addNewACE) - smb_add_ace4(acl, &ace_v4); + smb_add_ace4(theacl, &ace_v4); } - return acl; + return theacl; } NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, @@ -700,7 +700,7 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, set_nfs4acl_native_fn_t set_nfs4_native) { smbacl4_vfs_params params; - SMB4ACL_T *acl = NULL; + SMB4ACL_T *theacl = NULL; bool result; SMB_STRUCT_STAT sbuf; @@ -759,16 +759,16 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp, return NT_STATUS_OK; } - acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, ¶ms, sbuf.st_uid, sbuf.st_gid); - if (!acl) + theacl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, ¶ms, sbuf.st_uid, sbuf.st_gid); + if (!theacl) return map_nt_error_from_unix(errno); - smbacl4_dump_nfs4acl(10, acl); + smbacl4_dump_nfs4acl(10, theacl); if (set_acl_as_root) { become_root(); } - result = set_nfs4_native(fsp, acl); + result = set_nfs4_native(fsp, theacl); saved_errno = errno; if (set_acl_as_root) { unbecome_root(); diff --git a/source3/modules/nfs4_acls.h b/source3/modules/nfs4_acls.h index a227c6e0fc..b2d1196b26 100644 --- a/source3/modules/nfs4_acls.h +++ b/source3/modules/nfs4_acls.h @@ -117,26 +117,26 @@ SMB4ACL_T *smb_create_smb4acl(void); /* prop's contents are copied */ /* it doesn't change the order, appends */ -SMB4ACE_T *smb_add_ace4(SMB4ACL_T *acl, SMB_ACE4PROP_T *prop); +SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop); SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace); /* Returns NULL if none - or error */ -SMB4ACE_T *smb_first_ace4(SMB4ACL_T *acl); +SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl); /* Returns NULL in the end - or error */ SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace); -uint32 smb_get_naces(SMB4ACL_T *acl); +uint32 smb_get_naces(SMB4ACL_T *theacl); NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp, uint32 security_info, - SEC_DESC **ppdesc, SMB4ACL_T *acl); + SEC_DESC **ppdesc, SMB4ACL_T *theacl); NTSTATUS smb_get_nt_acl_nfs4(connection_struct *conn, const char *name, uint32 security_info, - SEC_DESC **ppdesc, SMB4ACL_T *acl); + SEC_DESC **ppdesc, SMB4ACL_T *theacl); /* Callback function needed to set the native acl * when applicable */ -- cgit From 2033b44c3f0872d98d8144a9fbf6d09fbde196e5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 23 Feb 2009 15:44:34 -0800 Subject: More warning fixes for Solaris. Jeremy. --- source3/modules/vfs_solarisacl.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_solarisacl.c b/source3/modules/vfs_solarisacl.c index 7bdfe8465b..cafb077555 100644 --- a/source3/modules/vfs_solarisacl.c +++ b/source3/modules/vfs_solarisacl.c @@ -51,11 +51,12 @@ static bool solaris_add_to_acl(SOLARIS_ACL_T *solaris_acl, int *count, static bool solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solarisacl, int *count); static bool solaris_acl_get_fd(int fd, SOLARIS_ACL_T *solarisacl, int *count); -static bool solaris_acl_sort(SOLARIS_ACL_T acl, int count); +static bool solaris_acl_sort(SOLARIS_ACL_T theacl, int count); static SMB_ACL_PERM_T solaris_perm_to_smb_perm(const SOLARIS_PERM_T perm); static SOLARIS_PERM_T smb_perm_to_solaris_perm(const SMB_ACL_PERM_T perm); +#if 0 static bool solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count); - +#endif /* public functions - the api */ @@ -347,7 +348,6 @@ static bool smb_acl_to_solaris_acl(SMB_ACL_T smb_acl, { bool ret = False; int i; - int check_which, check_rc; DEBUG(10, ("entering smb_acl_to_solaris_acl\n")); @@ -717,6 +717,7 @@ static bool solaris_acl_sort(SOLARIS_ACL_T solaris_acl, int count) return True; } +#if 0 /* * acl check function: * unused at the moment but could be used to get more @@ -746,7 +747,7 @@ static bool solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count) } return True; } - +#endif /* VFS operations structure */ -- cgit From faa1100d229aef56da5d48f5c19ec901e520f8ef Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 23 Feb 2009 16:22:43 -0800 Subject: More warning fixes for Solaris. Jeremy. --- source3/modules/vfs_extd_audit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_extd_audit.c b/source3/modules/vfs_extd_audit.c index d7c9d39c5e..b59a780f52 100644 --- a/source3/modules/vfs_extd_audit.c +++ b/source3/modules/vfs_extd_audit.c @@ -310,7 +310,7 @@ static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode) (result < 0) ? strerror(errno) : ""); } DEBUG(1, ("vfs_extd_audit: chmod %s mode 0x%x %s %s\n", - path, mode, + path, (unsigned int)mode, (result < 0) ? "failed: " : "", (result < 0) ? strerror(errno) : "")); @@ -330,7 +330,7 @@ static int audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t m (result < 0) ? strerror(errno) : ""); } DEBUG(1, ("vfs_extd_audit: chmod_acl %s mode 0x%x %s %s\n", - path, mode, + path, (unsigned int)mode, (result < 0) ? "failed: " : "", (result < 0) ? strerror(errno) : "")); @@ -350,7 +350,7 @@ static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mod (result < 0) ? strerror(errno) : ""); } DEBUG(1, ("vfs_extd_audit: fchmod %s mode 0x%x %s %s", - fsp->fsp_name, mode, + fsp->fsp_name, (unsigned int)mode, (result < 0) ? "failed: " : "", (result < 0) ? strerror(errno) : "")); @@ -370,7 +370,7 @@ static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t (result < 0) ? strerror(errno) : ""); } DEBUG(1, ("vfs_extd_audit: fchmod_acl %s mode 0x%x %s %s", - fsp->fsp_name, mode, + fsp->fsp_name, (unsigned int)mode, (result < 0) ? "failed: " : "", (result < 0) ? strerror(errno) : "")); -- cgit From 7bcaaf14fbf22805d88b945256b6bd31121c7c66 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Sun, 22 Feb 2009 20:50:30 -0800 Subject: s3 OneFS: Add a parameter that unconditionally allows execute access --- source3/modules/onefs.h | 2 ++ source3/modules/onefs_system.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index a70664bbf3..418e13d9d2 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -41,6 +41,8 @@ enum onefs_acl_wire_format #define PARM_ONEFS_TYPE "onefs" #define PARM_ACL_WIRE_FORMAT "acl wire format" #define PARM_ACL_WIRE_FORMAT_DEFAULT ACL_FORMAT_WINDOWS_SD +#define PARM_ALLOW_EXECUTE_ALWAYS "allow execute always" +#define PARM_ALLOW_EXECUTE_ALWAYS_DEFAULT false #define PARM_ATIME_NOW "atime now files" #define PARM_ATIME_NOW_DEFAULT NULL #define PARM_ATIME_STATIC "atime static files" diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c index 10802895cd..76df006d82 100644 --- a/source3/modules/onefs_system.c +++ b/source3/modules/onefs_system.c @@ -132,6 +132,30 @@ int onefs_sys_create_file(connection_struct *conn, if (lp_nt_acl_support(SNUM(conn)) && !lp_inherit_perms(SNUM(conn))) cf_flags = cf_flags_or(cf_flags, CF_FLAGS_DEFAULT_ACL); + /* + * Some customer workflows require the execute bit to be ignored. + */ + if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_ALLOW_EXECUTE_ALWAYS, + PARM_ALLOW_EXECUTE_ALWAYS_DEFAULT) && + (open_access_mask & FILE_EXECUTE)) { + + DEBUG(3, ("Stripping execute bit from %s: (0x%x)\n", path, + open_access_mask)); + + /* Strip execute. */ + open_access_mask &= ~FILE_EXECUTE; + + /* + * Add READ_DATA, so we're not left with desired_access=0. An + * execute call should imply the client will read the data. + */ + open_access_mask |= FILE_READ_DATA; + + DEBUGADD(3, ("New stripped access mask: 0x%x\n", + open_access_mask)); + } + DEBUG(10,("onefs_sys_create_file: base_fd = %d, " "open_access_mask = 0x%x, flags = 0x%x, mode = 0%o, " "desired_oplock = %s, id = 0x%x, secinfo = 0x%x, sd = %p, " -- cgit From 95bf60b39d003bea6f9f5ad2bc63d5f2a8b8b2af Mon Sep 17 00:00:00 2001 From: todd stecher Date: Mon, 23 Feb 2009 10:24:33 -0800 Subject: S3: Add in profile counters for new vfs and syscall entries. --- source3/modules/onefs_acl.c | 11 ++++++++++- source3/modules/onefs_cbrl.c | 26 ++++++++++++++++++++++++-- source3/modules/onefs_streams.c | 16 +++++++++++++--- source3/modules/onefs_system.c | 18 ++++++++++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c index 7bc4a1728f..b463722e61 100644 --- a/source3/modules/onefs_acl.c +++ b/source3/modules/onefs_acl.c @@ -614,6 +614,8 @@ onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, bool fopened = false; NTSTATUS status = NT_STATUS_OK; + START_PROFILE(syscall_get_sd); + *ppdesc = NULL; DEBUG(5, ("Getting sd for file %s. security_info=%u\n", @@ -753,6 +755,9 @@ onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, DEBUG(5, ("Finished retrieving/canonicalizing SD!\n")); /* FALLTHROUGH */ out: + + END_PROFILE(syscall_get_sd); + if (alloced && sd) { if (new_aces_alloced && sd->dacl->aces) SAFE_FREE(sd->dacl->aces); @@ -892,6 +897,8 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, bool fopened = false; NTSTATUS status; + START_PROFILE(syscall_set_sd); + DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name )); status = onefs_samba_sd_to_sd(security_info_sent, psd, &sd, @@ -899,7 +906,7 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("SD initialization failure: %s", nt_errstr(status))); - return status; + goto out; } fd = fsp->fh->fd; @@ -938,6 +945,8 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, /* FALLTHROUGH */ out: + END_PROFILE(syscall_set_sd); + if (fopened) close(fd); diff --git a/source3/modules/onefs_cbrl.c b/source3/modules/onefs_cbrl.c index a860023764..2c5e39c359 100644 --- a/source3/modules/onefs_cbrl.c +++ b/source3/modules/onefs_cbrl.c @@ -255,6 +255,8 @@ NTSTATUS onefs_brl_lock_windows(vfs_handle_struct *handle, struct onefs_cbrl_blr_state *bs; NTSTATUS status; + START_PROFILE(syscall_brl_lock); + SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK); SMB_ASSERT(plock->lock_type != UNLOCK_LOCK); @@ -301,10 +303,13 @@ NTSTATUS onefs_brl_lock_windows(vfs_handle_struct *handle, /* ASYNC still in progress: The process_* calls will keep * calling even if we haven't gotten the lock. Keep erroring * without calling ifs_cbrl, or getting/setting an id. */ - if (bs->state == ONEFS_CBRL_ASYNC) + if (bs->state == ONEFS_CBRL_ASYNC) { goto failure; - else if (bs->state == ONEFS_CBRL_ERROR) + } + else if (bs->state == ONEFS_CBRL_ERROR) { + END_PROFILE(syscall_brl_lock); return NT_STATUS_NO_MEMORY; + } SMB_ASSERT(bs->state == ONEFS_CBRL_NONE); async = true; @@ -343,6 +348,9 @@ NTSTATUS onefs_brl_lock_windows(vfs_handle_struct *handle, } failure: + + END_PROFILE(syscall_brl_lock); + /* Failure - error or async. */ plock->context.smbpid = (uint32) ONEFS_BLOCKING_PID; @@ -355,6 +363,9 @@ failure: return status; success: + + END_PROFILE(syscall_brl_lock); + /* Success. */ onefs_cbrl_enumerate_blq("onefs_brl_unlock_windows"); DEBUG(10, ("returning NT_STATUS_OK.\n")); @@ -371,6 +382,8 @@ bool onefs_brl_unlock_windows(vfs_handle_struct *handle, int error; int fd = br_lck->fsp->fh->fd; + START_PROFILE(syscall_brl_unlock); + SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK); SMB_ASSERT(plock->lock_type == UNLOCK_LOCK); @@ -378,6 +391,9 @@ bool onefs_brl_unlock_windows(vfs_handle_struct *handle, error = ifs_cbrl(fd, CBRL_OP_UNLOCK, CBRL_NOTYPE, plock->start, plock->size, CBRL_NOTYPE, 0, plock->context.smbpid, plock->context.tid, plock->fnum); + + END_PROFILE(syscall_brl_unlock); + if (error) { DEBUG(10, ("returning false.\n")); return false; @@ -404,6 +420,8 @@ bool onefs_brl_cancel_windows(vfs_handle_struct *handle, int fd = br_lck->fsp->fh->fd; struct onefs_cbrl_blr_state *bs; + START_PROFILE(syscall_brl_cancel); + SMB_ASSERT(plock); SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK); SMB_ASSERT(blr); @@ -416,6 +434,7 @@ bool onefs_brl_cancel_windows(vfs_handle_struct *handle, if (bs->state == ONEFS_CBRL_DONE) { /* No-op. */ DEBUG(10, ("State=DONE, returning true\n")); + END_PROFILE(syscall_brl_cancel); return true; } @@ -427,6 +446,9 @@ bool onefs_brl_cancel_windows(vfs_handle_struct *handle, error = ifs_cbrl(fd, CBRL_OP_CANCEL, CBRL_NOTYPE, plock->start, plock->size, CBRL_NOTYPE, bs->id, plock->context.smbpid, plock->context.tid, plock->fnum); + + END_PROFILE(syscall_brl_cancel); + if (error) { DEBUG(10, ("returning false\n")); bs->state = ONEFS_CBRL_ERROR; diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c index 9616ca48d5..2dcd8891eb 100644 --- a/source3/modules/onefs_streams.c +++ b/source3/modules/onefs_streams.c @@ -160,18 +160,26 @@ int onefs_rename(vfs_handle_struct *handle, const char *oldname, char *nbase = NULL; char *nsname = NULL; + START_PROFILE(syscall_rename_at); + frame = talloc_stackframe(); ret = onefs_is_stream(oldname, &obase, &osname, &old_is_stream); - if (ret) + if (ret) { + END_PROFILE(syscall_rename_at); return ret; + } ret = onefs_is_stream(newname, &nbase, &nsname, &new_is_stream); - if (ret) + if (ret) { + END_PROFILE(syscall_rename_at); return ret; + } if (!old_is_stream && !new_is_stream) { - return SMB_VFS_NEXT_RENAME(handle, oldname, newname); + ret = SMB_VFS_NEXT_RENAME(handle, oldname, newname); + END_PROFILE(syscall_rename_at); + return ret; } dir_fd = get_stream_dir_fd(handle->conn, obase, NULL); @@ -192,6 +200,8 @@ int onefs_rename(vfs_handle_struct *handle, const char *oldname, } done: + END_PROFILE(syscall_rename_at); + saved_errno = errno; if (dir_fd >= 0) { close(dir_fd); diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c index 76df006d82..518a398154 100644 --- a/source3/modules/onefs_system.c +++ b/source3/modules/onefs_system.c @@ -95,6 +95,8 @@ int onefs_sys_create_file(connection_struct *conn, uint32_t onefs_dos_attributes; struct ifs_createfile_flags cf_flags = CF_FLAGS_NONE; + START_PROFILE(syscall_createfile); + /* Setup security descriptor and get secinfo. */ if (sd != NULL) { NTSTATUS status; @@ -196,6 +198,7 @@ int onefs_sys_create_file(connection_struct *conn, } out: + END_PROFILE(syscall_createfile); aclu_free_sd(pifs_sd, false); return ret_fd; @@ -307,6 +310,8 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, bool atomic = false; ssize_t ret = 0; + START_PROFILE_BYTES(syscall_sendfile, count); + if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, PARM_ATOMIC_SENDFILE, PARM_ATOMIC_SENDFILE_DEFAULT)) { @@ -320,6 +325,7 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, /* If the sendfile wasn't atomic, we're done. */ if (!atomic) { DEBUG(10, ("non-atomic sendfile read %ul bytes", ret)); + END_PROFILE(syscall_sendfile); return ret; } @@ -391,6 +397,7 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, /* Handle case 1: short read -> truncated file. */ if (ret == 0) { + END_PROFILE(syscall_sendfile); return ret; } @@ -402,6 +409,7 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, PARM_SENDFILE_LARGE_READS_DEFAULT)) { DEBUG(3, ("Not attempting non-atomic large sendfile: " "%lu bytes\n", count)); + END_PROFILE(syscall_sendfile); return 0; } @@ -421,6 +429,7 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, DEBUG(1, ("error on non-atomic large sendfile " "(%lu bytes): %s\n", count, strerror(errno))); + END_PROFILE(syscall_sendfile); return ret; } @@ -439,9 +448,11 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, PARM_SENDFILE_SAFE, PARM_SENDFILE_SAFE_DEFAULT)) { + END_PROFILE(syscall_sendfile); return -1; } + END_PROFILE(syscall_sendfile); return ret; } @@ -455,6 +466,7 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, count, strerror(errno))); } + END_PROFILE(syscall_sendfile); return ret; } @@ -509,10 +521,13 @@ ssize_t onefs_sys_recvfile(int fromfd, int tofd, SMB_OFF_T offset, off_t rbytes; off_t wbytes; + START_PROFILE_BYTES(syscall_recvfile, count); + DEBUG(10,("onefs_recvfile: from = %d, to = %d, offset=%llu, count = " "%lu\n", fromfd, tofd, offset, count)); if (count == 0) { + END_PROFILE(syscall_recvfile); return 0; } @@ -624,6 +639,9 @@ ssize_t onefs_sys_recvfile(int fromfd, int tofd, SMB_OFF_T offset, ret = total_wbytes; out: + + END_PROFILE(syscall_recvfile); + /* Make sure we always try to drain the socket. */ if (!socket_drained && count - total_rbytes) { int saved_errno = errno; -- cgit From 4e024b3f87ee1ccb0d7c83dfc6a4b5a6b2c47c13 Mon Sep 17 00:00:00 2001 From: Dan Sledz Date: Tue, 24 Feb 2009 14:12:48 -0800 Subject: s3: onefs_acl.c cleanup Remove some duplicate code. Add a \n to a debugging statement --- source3/modules/onefs_acl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c index b463722e61..b8097b6455 100644 --- a/source3/modules/onefs_acl.c +++ b/source3/modules/onefs_acl.c @@ -273,9 +273,6 @@ onefs_samba_acl_to_acl(SEC_ACL *samba_acl, struct ifs_security_acl **acl, if (aclu_initialize_acl(acl, aces, num_aces)) goto err_free; - if (aclu_initialize_acl(acl, aces, num_aces)) - goto err_free; - /* Currently aclu_initialize_acl should copy the aces over, allowing * us to immediately free */ free(aces); @@ -905,7 +902,7 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, SNUM(handle->conn)); if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("SD initialization failure: %s", nt_errstr(status))); + DEBUG(3, ("SD initialization failure: %s\n", nt_errstr(status))); goto out; } -- cgit From afc7e45a4ccf8505e4c598334e339e79ba036057 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Tue, 24 Feb 2009 21:53:30 -0800 Subject: s3 OneFS: Fix uninitialized variable --- source3/modules/onefs_acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/modules') diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c index b8097b6455..a1bfa6e121 100644 --- a/source3/modules/onefs_acl.c +++ b/source3/modules/onefs_acl.c @@ -890,7 +890,7 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) { struct ifs_security_descriptor sd = {}; - int fd; + int fd = -1; bool fopened = false; NTSTATUS status; -- cgit From 76ca297ecfd1086b38487ac8f53a8392a4a38ad6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 25 Feb 2009 13:46:21 -0800 Subject: Fix use of streams modules with CIFSFS client. Jeremy. --- source3/modules/vfs_streams_depot.c | 14 ++++++++++++-- source3/modules/vfs_streams_xattr.c | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index 9329be7a9c..023d2b9ec0 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -494,7 +494,13 @@ static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname) * We potentially need to delete the per-inode streams directory */ - if (SMB_VFS_NEXT_STAT(handle, fname, &sbuf) == -1) { + if (lp_posix_pathnames()) { + ret = SMB_VFS_NEXT_LSTAT(handle, fname, &sbuf); + } else { + ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf); + } + + if (ret == -1) { return -1; } @@ -678,7 +684,11 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, if (is_ntfs_stream_name(fname)) { return NT_STATUS_INVALID_PARAMETER; } - ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf); + if (lp_posix_pathnames()) { + ret = SMB_VFS_NEXT_LSTAT(handle, fname, &sbuf); + } else { + ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf); + } } if (ret == -1) { diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index 77ffff5fb5..3d5478d7a2 100644 --- a/source3/modules/vfs_streams_xattr.c +++ b/source3/modules/vfs_streams_xattr.c @@ -135,6 +135,7 @@ static bool streams_xattr_recheck(struct stream_io *sio) static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) { + int ret = -1; struct stream_io *io = (struct stream_io *) VFS_FETCH_FSP_EXTENSION(handle, fsp); @@ -148,7 +149,13 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp, return -1; } - if (SMB_VFS_STAT(handle->conn, io->base, sbuf) == -1) { + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, io->base, sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, io->base, sbuf); + } + + if (ret == -1) { return -1; } @@ -719,7 +726,11 @@ static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle, if (is_ntfs_stream_name(fname)) { return NT_STATUS_INVALID_PARAMETER; } - ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + } } if (ret == -1) { -- cgit From 01493737c88c0056ca3da5faf43b7bc9b9a2fbcb Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Mon, 23 Feb 2009 14:51:17 -0800 Subject: s3 OneFS: Add .snapshot directory configuration handling --- source3/modules/onefs.h | 32 ++++++++- source3/modules/onefs_streams.c | 2 +- source3/modules/onefs_system.c | 50 ++++++++++++++ source3/modules/vfs_onefs.c | 144 +++++++++++++++++++++++++++++++++------- 4 files changed, 201 insertions(+), 27 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index 418e13d9d2..a0f4fe37de 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -57,6 +57,16 @@ enum onefs_acl_wire_format #define PARM_CTIME_NOW_DEFAULT NULL #define PARM_CTIME_SLOP "ctime now slop" #define PARM_CTIME_SLOP_DEFAULT 0 +#define PARM_DOT_SNAP_CHILD_ACCESSIBLE "dot snap child accessible" +#define PARM_DOT_SNAP_CHILD_ACCESSIBLE_DEFAULT true +#define PARM_DOT_SNAP_CHILD_VISIBLE "dot snap child visible" +#define PARM_DOT_SNAP_CHILD_VISIBLE_DEFAULT false +#define PARM_DOT_SNAP_ROOT_ACCESSIBLE "dot snap root accessible" +#define PARM_DOT_SNAP_ROOT_ACCESSIBLE_DEFAULT true +#define PARM_DOT_SNAP_ROOT_VISIBLE "dot snap root visible" +#define PARM_DOT_SNAP_ROOT_VISIBLE_DEFAULT true +#define PARM_DOT_SNAP_TILDE "dot snap tilde" +#define PARM_DOT_SNAP_TILDE_DEFAULT true #define PARM_IGNORE_SACLS "ignore sacls" #define PARM_IGNORE_SACLS_DEFAULT false #define PARM_MTIME_NOW "mtime now files" @@ -99,9 +109,9 @@ enum onefs_acl_wire_format #define ONEFS_VFS_CONFIG_FAKETIMESTAMPS 0x00000001 -struct onefs_vfs_config +struct onefs_vfs_share_config { - int32 init_flags; + uint32_t init_flags; /* data for fake timestamps */ int atime_slop; @@ -127,6 +137,18 @@ struct onefs_vfs_config name_compare_entry *atime_static_list; }; +struct onefs_vfs_global_config +{ + uint32_t init_flags; + + /* Snapshot options */ + bool dot_snap_child_accessible; + bool dot_snap_child_visible; + bool dot_snap_root_accessible; + bool dot_snap_root_visible; + bool dot_snap_tilde; +}; + /* * vfs interface handlers */ @@ -240,7 +262,7 @@ NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname, char **pbase, char **pstream); bool onefs_get_config(int snum, int config_type, - struct onefs_vfs_config *cfg); + struct onefs_vfs_share_config *cfg); int onefs_rdp_add_dir_state(connection_struct *conn, SMB_STRUCT_DIR *dirp); @@ -269,4 +291,8 @@ ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, ssize_t onefs_sys_recvfile(int fromfd, int tofd, SMB_OFF_T offset, size_t count); +void onefs_sys_config_enc(void); +void onefs_sys_config_snap_opt(struct onefs_vfs_global_config *global_config); +void onefs_sys_config_tilde(struct onefs_vfs_global_config *global_config); + #endif /* _ONEFS_H */ diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c index 2dcd8891eb..6e2794399d 100644 --- a/source3/modules/onefs_streams.c +++ b/source3/modules/onefs_streams.c @@ -230,7 +230,7 @@ static void merge_stat(SMB_STRUCT_STAT *stream_sbuf, static void onefs_adjust_stat_time(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf) { - struct onefs_vfs_config cfg; + struct onefs_vfs_share_config cfg; struct timeval tv_now = {0, 0}; bool static_mtime = False; bool static_atime = False; diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c index 518a398154..43ebed8d44 100644 --- a/source3/modules/onefs_system.c +++ b/source3/modules/onefs_system.c @@ -656,3 +656,53 @@ out: return ret; } + +/** + * Set the per-process encoding, ignoring errors. + */ +void onefs_sys_config_enc(void) +{ + int ret; + + ret = enc_set_proc(ENC_UTF8); + if (ret) { + DEBUG(0, ("Setting process encoding failed: %s", + strerror(errno))); + } +} + +/** + * Set the per-process .snpashot directory options, ignoring errors. + */ +void onefs_sys_config_snap_opt(struct onefs_vfs_global_config *global_config) +{ + struct ifs_dotsnap_options dso; + int ret; + + dso.per_proc = 1; + dso.sub_accessible = global_config->dot_snap_child_accessible; + dso.sub_visible = global_config->dot_snap_child_visible; + dso.root_accessible = global_config->dot_snap_root_accessible; + dso.root_visible = global_config->dot_snap_root_visible; + + ret = ifs_set_dotsnap_options(&dso); + if (ret) { + DEBUG(0, ("Setting snapshot visibility/accessibility " + "failed: %s", strerror(errno))); + } +} + +/** + * Set the per-process flag saying whether or not to accept ~snapshot + * as an alternative name for .snapshot directories. + */ +void onefs_sys_config_tilde(struct onefs_vfs_global_config *global_config) +{ + int ret; + + ret = ifs_tilde_snapshot(global_config->dot_snap_tilde); + if (ret) { + DEBUG(0, ("Setting snapshot tilde failed: %s", + strerror(errno))); + } +} diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index 60c2c977a4..f81134909f 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -26,14 +26,14 @@ #define ONEFS_DATA_FASTBUF 10 -struct onefs_vfs_config share_config[ONEFS_DATA_FASTBUF]; -struct onefs_vfs_config *pshare_config; +struct onefs_vfs_share_config vfs_share_config[ONEFS_DATA_FASTBUF]; +struct onefs_vfs_share_config *pvfs_share_config; -static void onefs_load_faketimestamp_config(struct vfs_handle_struct *handle, - struct onefs_vfs_config *cfg) +static void onefs_load_faketimestamp_config(struct connection_struct *conn, + struct onefs_vfs_share_config *cfg) { const char **parm; - int snum = SNUM(handle->conn); + int snum = SNUM(conn); parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_ATIME_NOW, PARM_ATIME_NOW_DEFAULT); @@ -83,46 +83,141 @@ static void onefs_load_faketimestamp_config(struct vfs_handle_struct *handle, PARM_MTIME_SLOP_DEFAULT); } +/** + * Set onefs-specific vfs global config parameters. + * + * Since changes in these parameters require calling syscalls, we only want to + * call them when the configuration actually changes. + */ +static void onefs_load_global_config(connection_struct *conn) +{ + static struct onefs_vfs_global_config global_config; + bool dot_snap_child_accessible; + bool dot_snap_child_visible; + bool dot_snap_root_accessible; + bool dot_snap_root_visible; + bool dot_snap_tilde; + bool reconfig_dso = false; + bool reconfig_tilde = false; + + /* Check if this is the first time setting the config options. */ + if (!(global_config.init_flags & ONEFS_VFS_CONFIG_INITIALIZED)) { + global_config.init_flags |= ONEFS_VFS_CONFIG_INITIALIZED; + + /* Set process encoding */ + onefs_sys_config_enc(); + + reconfig_dso = true; + reconfig_tilde = true; + } -static int onefs_load_config(struct vfs_handle_struct *handle) + /* Get the dot snap options from the conf. */ + dot_snap_child_accessible = + lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_DOT_SNAP_CHILD_ACCESSIBLE, + PARM_DOT_SNAP_CHILD_ACCESSIBLE_DEFAULT); + dot_snap_child_visible = + lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_DOT_SNAP_CHILD_VISIBLE, + PARM_DOT_SNAP_CHILD_VISIBLE_DEFAULT); + dot_snap_root_accessible = + lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_DOT_SNAP_ROOT_ACCESSIBLE, + PARM_DOT_SNAP_ROOT_ACCESSIBLE_DEFAULT); + dot_snap_root_visible = + lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_DOT_SNAP_ROOT_VISIBLE, + PARM_DOT_SNAP_ROOT_VISIBLE_DEFAULT); + dot_snap_tilde = + lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_DOT_SNAP_TILDE, + PARM_DOT_SNAP_TILDE_DEFAULT); + + /* Check if any of the dot snap options need updating. */ + if (dot_snap_child_accessible != + global_config.dot_snap_child_accessible) { + global_config.dot_snap_child_accessible = + dot_snap_child_accessible; + reconfig_dso = true; + } + if (dot_snap_child_visible != + global_config.dot_snap_child_visible) { + global_config.dot_snap_child_visible = + dot_snap_child_visible; + reconfig_dso = true; + } + if (dot_snap_root_accessible != + global_config.dot_snap_root_accessible) { + global_config.dot_snap_root_accessible = + dot_snap_root_accessible; + reconfig_dso = true; + } + if (dot_snap_root_visible != + global_config.dot_snap_root_visible) { + global_config.dot_snap_root_visible = + dot_snap_root_visible; + reconfig_dso = true; + } + if (dot_snap_tilde != global_config.dot_snap_tilde) { + global_config.dot_snap_tilde = dot_snap_tilde; + reconfig_tilde = true; + } + + /* If a dot snap option has changed update the process. */ + if (reconfig_dso) { + onefs_sys_config_snap_opt(&global_config); + } + + /* If the dot snap tilde option has changed update the process. */ + if (reconfig_tilde) { + onefs_sys_config_tilde(&global_config); + } +} + +static int onefs_load_config(connection_struct *conn) { - int snum = SNUM(handle->conn); + int snum = SNUM(conn); int share_count = lp_numservices(); - if (!pshare_config) { + /* Share config */ + if (!pvfs_share_config) { if (share_count <= ONEFS_DATA_FASTBUF) - pshare_config = share_config; + pvfs_share_config = vfs_share_config; else { - pshare_config = - SMB_MALLOC_ARRAY(struct onefs_vfs_config, + pvfs_share_config = + SMB_MALLOC_ARRAY(struct onefs_vfs_share_config, share_count); - if (!pshare_config) { + if (!pvfs_share_config) { errno = ENOMEM; return -1; } - memset(pshare_config, 0, - (sizeof(struct onefs_vfs_config) * share_count)); + memset(pvfs_share_config, 0, + (sizeof(struct onefs_vfs_share_config) * + share_count)); } } - if ((pshare_config[snum].init_flags & + if ((pvfs_share_config[snum].init_flags & ONEFS_VFS_CONFIG_INITIALIZED) == 0) { - pshare_config[snum].init_flags = + pvfs_share_config[snum].init_flags = ONEFS_VFS_CONFIG_INITIALIZED; - onefs_load_faketimestamp_config(handle, - &pshare_config[snum]); + onefs_load_faketimestamp_config(conn, + &pvfs_share_config[snum]); } + /* Global config */ + onefs_load_global_config(conn); + return 0; } bool onefs_get_config(int snum, int config_type, - struct onefs_vfs_config *cfg) + struct onefs_vfs_share_config *cfg) { - if (share_config[snum].init_flags & config_type) - *cfg = share_config[snum]; + if (vfs_share_config[snum].init_flags & config_type) + *cfg = vfs_share_config[snum]; else return false; @@ -132,10 +227,13 @@ bool onefs_get_config(int snum, int config_type, static int onefs_connect(struct vfs_handle_struct *handle, const char *service, const char *user) { - int ret = onefs_load_config(handle); + int ret; - if (ret) + ret = onefs_load_config(handle->conn); + if (ret) { + DEBUG(3, ("Load config failed: %s\n", strerror(errno))); return ret; + } return SMB_VFS_NEXT_CONNECT(handle, service, user); } -- cgit From 9b8bb1ad957f9c2d91e55ac6a27657cd8f6d4a14 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 25 Feb 2009 14:12:51 -0800 Subject: Ensure ACL modules work with POSIX paths. Jeremy. --- source3/modules/vfs_acl_tdb.c | 89 ++++++++++++++++++++++++++++++++--------- source3/modules/vfs_acl_xattr.c | 12 +++++- 2 files changed, 79 insertions(+), 22 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c index 909de9d7c8..5cd3e21594 100644 --- a/source3/modules/vfs_acl_tdb.c +++ b/source3/modules/vfs_acl_tdb.c @@ -186,20 +186,26 @@ static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, TDB_DATA data; struct file_id id; struct db_context *db; + int ret = -1; SMB_STRUCT_STAT sbuf; SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return NT_STATUS_INTERNAL_DB_CORRUPTION); if (fsp && fsp->fh->fd != -1) { - if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { - return map_nt_error_from_unix(errno); - } + ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - if (SMB_VFS_STAT(handle->conn, name, &sbuf) == -1) { - return map_nt_error_from_unix(errno); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, name, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, name, &sbuf); } } + + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); /* For backwards compatibility only store the dev/inode. */ @@ -270,6 +276,7 @@ static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle, TDB_DATA data; struct db_context *db; struct db_record *rec; + int ret = -1; DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n", (unsigned int)pblob->length, fsp->fsp_name)); @@ -278,14 +285,19 @@ static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle, return NT_STATUS_INTERNAL_DB_CORRUPTION); if (fsp->fh->fd != -1) { - if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { - return map_nt_error_from_unix(errno); - } + ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - if (SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf) == -1) { - return map_nt_error_from_unix(errno); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, fsp->fsp_name, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf); } } + + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); /* For backwards compatibility only store the dev/inode. */ @@ -316,6 +328,7 @@ static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle, SMB_STRUCT_STAT sbuf; struct db_context *db; struct db_record *rec; + int ret = -1; DEBUG(10,("store_acl_blob_pathname: storing blob " "length %u on file %s\n", @@ -324,7 +337,13 @@ static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return NT_STATUS_INTERNAL_DB_CORRUPTION); - if (SMB_VFS_STAT(handle->conn, fname, &sbuf) == -1) { + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + } + + if (ret == -1) { return map_nt_error_from_unix(errno); } @@ -494,7 +513,11 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, if (fsp && !fsp->is_directory && fsp->fh->fd != -1) { ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); + } } if (ret == -1) { return map_nt_error_from_unix(errno); @@ -583,11 +606,17 @@ static int unlink_acl_tdb(vfs_handle_struct *handle, const char *path) { SMB_STRUCT_STAT sbuf; struct db_context *db; - int ret; + int ret = -1; SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, path, &sbuf); + } + + if (ret == -1) { return -1; } @@ -626,11 +655,17 @@ static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path) SMB_STRUCT_STAT sbuf; struct db_context *db; - int ret; + int ret = -1; SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, path, &sbuf); + } + + if (ret == -1) { return -1; } @@ -728,7 +763,11 @@ static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp, return NT_STATUS_OK; } if (fsp->is_directory || fsp->fh->fd == -1) { - ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); + } else { + ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); } @@ -813,11 +852,17 @@ static int sys_acl_set_file_tdb(vfs_handle_struct *handle, { SMB_STRUCT_STAT sbuf; struct db_context *db; - int ret; + int ret = -1; SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); - if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn, path, &sbuf); + } + + if (ret == -1) { return -1; } @@ -848,7 +893,11 @@ static int sys_acl_set_fd_tdb(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); if (fsp->is_directory || fsp->fh->fd == -1) { - ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); + } else { + ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); } diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index 7c78b506f0..f46e4683aa 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -381,7 +381,11 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, if (fsp && !fsp->is_directory && fsp->fh->fd != -1) { ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); + } } if (ret == -1) { return map_nt_error_from_unix(errno); @@ -559,7 +563,11 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, return NT_STATUS_OK; } if (fsp->is_directory || fsp->fh->fd == -1) { - ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + if (lp_posix_pathnames()) { + ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); + } else { + ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); } -- cgit From a6d0a93fc27729b63ae3fd4994059f3854a63845 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 25 Feb 2009 14:50:19 -0800 Subject: Use fsp->posix_open in preference if we have it. Jeremy. --- source3/modules/vfs_acl_tdb.c | 10 +++++----- source3/modules/vfs_acl_xattr.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c index 5cd3e21594..73dbca4809 100644 --- a/source3/modules/vfs_acl_tdb.c +++ b/source3/modules/vfs_acl_tdb.c @@ -195,7 +195,7 @@ static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, if (fsp && fsp->fh->fd != -1) { ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - if (lp_posix_pathnames()) { + if (fsp->posix_open) { ret = SMB_VFS_LSTAT(handle->conn, name, &sbuf); } else { ret = SMB_VFS_STAT(handle->conn, name, &sbuf); @@ -287,7 +287,7 @@ static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle, if (fsp->fh->fd != -1) { ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - if (lp_posix_pathnames()) { + if (fsp->posix_open) { ret = SMB_VFS_LSTAT(handle->conn, fsp->fsp_name, &sbuf); } else { ret = SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf); @@ -513,7 +513,7 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, if (fsp && !fsp->is_directory && fsp->fh->fd != -1) { ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - if (lp_posix_pathnames()) { + if (fsp->posix_open) { ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf); } else { ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); @@ -763,7 +763,7 @@ static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp, return NT_STATUS_OK; } if (fsp->is_directory || fsp->fh->fd == -1) { - if (lp_posix_pathnames()) { + if (fsp->posix_open) { ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); } else { ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); @@ -893,7 +893,7 @@ static int sys_acl_set_fd_tdb(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); if (fsp->is_directory || fsp->fh->fd == -1) { - if (lp_posix_pathnames()) { + if (fsp->posix_open) { ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); } else { ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index f46e4683aa..039e469426 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -381,7 +381,7 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, if (fsp && !fsp->is_directory && fsp->fh->fd != -1) { ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { - if (lp_posix_pathnames()) { + if (fsp->posix_open) { ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf); } else { ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); @@ -563,7 +563,7 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, return NT_STATUS_OK; } if (fsp->is_directory || fsp->fh->fd == -1) { - if (lp_posix_pathnames()) { + if (fsp->posix_open) { ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); } else { ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); -- cgit