The Samba-Bugzilla – Attachment 6422 Details for
Bug 7913
shadow_copy2 module with non-default format parameter requires wide links enabled to work
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
shadow_copy3
0001-s3-vfs_shadow_copy3.patch (text/plain), 37.88 KB, created by
Volker Lendecke
on 2011-04-20 17:11:23 UTC
(
hide
)
Description:
shadow_copy3
Filename:
MIME Type:
Creator:
Volker Lendecke
Created:
2011-04-20 17:11:23 UTC
Size:
37.88 KB
patch
obsolete
>From 360b08c6567603cc3a14fe6cbb53692187110eef Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 4 Apr 2011 13:21:40 +0200 >Subject: [PATCH] s3: vfs_shadow_copy3 > >--- > source3/Makefile.in | 5 + > source3/configure.in | 2 + > source3/modules/vfs_shadow_copy3.c | 1454 ++++++++++++++++++++++++++++++++++++ > 3 files changed, 1461 insertions(+), 0 deletions(-) > create mode 100644 source3/modules/vfs_shadow_copy3.c > >diff --git a/source3/Makefile.in b/source3/Makefile.in >index 39d15a9..e8c798c 100644 >--- a/source3/Makefile.in >+++ b/source3/Makefile.in >@@ -802,6 +802,7 @@ VFS_CAP_OBJ = modules/vfs_cap.o > VFS_EXPAND_MSDFS_OBJ = modules/vfs_expand_msdfs.o > VFS_SHADOW_COPY_OBJ = modules/vfs_shadow_copy.o > VFS_SHADOW_COPY2_OBJ = modules/vfs_shadow_copy2.o >+VFS_SHADOW_COPY3_OBJ = modules/vfs_shadow_copy3.o > VFS_AFSACL_OBJ = modules/vfs_afsacl.o > VFS_XATTR_TDB_OBJ = modules/vfs_xattr_tdb.o > VFS_POSIXACL_OBJ = modules/vfs_posixacl.o >@@ -2877,6 +2878,10 @@ bin/shadow_copy2.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SHADOW_COPY2_OBJ) > @echo "Building plugin $@" > @$(SHLD_MODULE) $(VFS_SHADOW_COPY2_OBJ) > >+bin/shadow_copy3.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SHADOW_COPY3_OBJ) >+ @echo "Building plugin $@" >+ @$(SHLD_MODULE) $(VFS_SHADOW_COPY3_OBJ) >+ > bin/syncops.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SYNCOPS_OBJ) > @echo "Building plugin $@" > @$(SHLD_MODULE) $(VFS_SYNCOPS_OBJ) >diff --git a/source3/configure.in b/source3/configure.in >index d89c1b2..a66d5df 100644 >--- a/source3/configure.in >+++ b/source3/configure.in >@@ -437,6 +437,7 @@ default_shared_modules="$default_shared_modules vfs_cap" > default_shared_modules="$default_shared_modules vfs_expand_msdfs" > default_shared_modules="$default_shared_modules vfs_shadow_copy" > default_shared_modules="$default_shared_modules vfs_shadow_copy2" >+default_shared_modules="$default_shared_modules vfs_shadow_copy3" > default_shared_modules="$default_shared_modules charset_CP850" > default_shared_modules="$default_shared_modules charset_CP437" > default_shared_modules="$default_shared_modules auth_script" >@@ -6843,6 +6844,7 @@ SMB_MODULE(vfs_cap, \$(VFS_CAP_OBJ), "bin/cap.$SHLIBEXT", VFS) > SMB_MODULE(vfs_expand_msdfs, \$(VFS_EXPAND_MSDFS_OBJ), "bin/expand_msdfs.$SHLIBEXT", VFS) > SMB_MODULE(vfs_shadow_copy, \$(VFS_SHADOW_COPY_OBJ), "bin/shadow_copy.$SHLIBEXT", VFS) > SMB_MODULE(vfs_shadow_copy2, \$(VFS_SHADOW_COPY2_OBJ), "bin/shadow_copy2.$SHLIBEXT", VFS) >+SMB_MODULE(vfs_shadow_copy3, \$(VFS_SHADOW_COPY2_OBJ), "bin/shadow_copy3.$SHLIBEXT", VFS) > SMB_MODULE(vfs_afsacl, \$(VFS_AFSACL_OBJ), "bin/afsacl.$SHLIBEXT", VFS) > SMB_MODULE(vfs_xattr_tdb, \$(VFS_XATTR_TDB_OBJ), "bin/xattr_tdb.$SHLIBEXT", VFS) > SMB_MODULE(vfs_posixacl, \$(VFS_POSIXACL_OBJ), "bin/posixacl.$SHLIBEXT", VFS) >diff --git a/source3/modules/vfs_shadow_copy3.c b/source3/modules/vfs_shadow_copy3.c >new file mode 100644 >index 0000000..9a7391a >--- /dev/null >+++ b/source3/modules/vfs_shadow_copy3.c >@@ -0,0 +1,1454 @@ >+/* >+ * Third attempt at a shadow copy module >+ * >+ * Copyright (C) Andrew Tridgell 2007 (portions taken from shadow_copy2) >+ * Copyright (C) Ed Plese 2009 >+ * Copyright (C) Volker Lendecke 2011 >+ * >+ * 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 "system/filesys.h" >+#include "include/ntioctl.h" >+#include "smbd/proto.h" >+ >+#define GMT_NAME_LEN 24 /* length of a @GMT- name */ >+#define GMT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S" >+ >+static bool shadow_copy3_find_slashes(TALLOC_CTX *mem_ctx, const char *str, >+ size_t **poffsets, >+ unsigned *pnum_offsets) >+{ >+ unsigned num_offsets; >+ size_t *offsets; >+ const char *p; >+ >+ num_offsets = 0; >+ >+ p = str; >+ while ((p = strchr(p, '/')) != NULL) { >+ num_offsets += 1; >+ p += 1; >+ } >+ >+ offsets = talloc_array(mem_ctx, size_t, num_offsets); >+ if (offsets == NULL) { >+ return false; >+ } >+ >+ p = str; >+ num_offsets = 0; >+ while ((p = strchr(p, '/')) != NULL) { >+ offsets[num_offsets] = p-str; >+ num_offsets += 1; >+ p += 1; >+ } >+ >+ *poffsets = offsets; >+ *pnum_offsets = num_offsets; >+ return true; >+} >+ >+static char *shadow_copy3_insert_string(TALLOC_CTX *mem_ctx, >+ struct vfs_handle_struct *handle, >+ time_t snapshot) >+{ >+ struct tm snap_tm; >+ char gmt[NAME_MAX+1]; >+ size_t gmt_len; >+ >+ if (localtime_r(&snapshot, &snap_tm) == 0) { >+ DEBUG(10, ("gmtime_r failed\n")); >+ return NULL; >+ } >+ gmt_len = strftime(gmt, sizeof(gmt), >+ lp_parm_const_string(SNUM(handle->conn), "shadow", >+ "format", GMT_FORMAT), >+ &snap_tm); >+ if (gmt_len == 0) { >+ DEBUG(10, ("strftime failed\n")); >+ return NULL; >+ } >+ return talloc_asprintf(talloc_tos(), "/%s/%s", >+ lp_parm_const_string( >+ SNUM(handle->conn), "shadow", "snapdir", >+ ".snapshots"), >+ gmt); >+} >+ >+static bool shadow_copy3_strip_snapshot(TALLOC_CTX *mem_ctx, >+ struct vfs_handle_struct *handle, >+ const char *name, >+ time_t *ptimestamp, >+ char **pstripped) >+{ >+ struct tm tm; >+ time_t timestamp; >+ const char *p; >+ char *q; >+ char *stripped; >+ size_t rest_len, dst_len; >+ >+ p = strstr_m(name, "@GMT-"); >+ if (p == NULL) { >+ goto no_snapshot; >+ } >+ if ((p > name) && (p[-1] != '/')) { >+ goto no_snapshot; >+ } >+ q = strptime(p, GMT_FORMAT, &tm); >+ if (q == NULL) { >+ goto no_snapshot; >+ } >+ tm.tm_isdst = -1; >+ timestamp = mktime(&tm); >+ if (timestamp == (time_t)-1) { >+ goto no_snapshot; >+ } >+ if ((p == name) && (q[0] == '\0')) { >+ if (pstripped != NULL) { >+ stripped = talloc_strdup(mem_ctx, ""); >+ if (stripped == NULL) { >+ return false; >+ } >+ *pstripped = stripped; >+ } >+ *ptimestamp = timestamp; >+ return true; >+ } >+ if (q[0] != '/') { >+ goto no_snapshot; >+ } >+ q += 1; >+ >+ rest_len = strlen(q); >+ dst_len = (p-name) + rest_len; >+ >+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "snapdirseverywhere", >+ false)) { >+ char *insert; >+ bool have_insert; >+ insert = shadow_copy3_insert_string(talloc_tos(), handle, >+ timestamp); >+ if (insert == NULL) { >+ errno = ENOMEM; >+ return false; >+ } >+ >+ have_insert = (strstr(name, insert+1) != NULL); >+ TALLOC_FREE(insert); >+ if (have_insert) { >+ goto no_snapshot; >+ } >+ >+ } >+ >+ if (pstripped != NULL) { >+ stripped = talloc_array(mem_ctx, char, dst_len+1); >+ if (stripped == NULL) { >+ errno = ENOMEM; >+ return false; >+ } >+ if (p > name) { >+ memcpy(stripped, name, p-name); >+ } >+ if (rest_len > 0) { >+ memcpy(stripped + (p-name), q, rest_len); >+ } >+ stripped[dst_len] = '\0'; >+ *pstripped = stripped; >+ } >+ *ptimestamp = timestamp; >+ return true; >+no_snapshot: >+ *ptimestamp = 0; >+ return true; >+} >+ >+static char *shadow_copy3_find_mount_point(TALLOC_CTX *mem_ctx, >+ vfs_handle_struct *handle) >+{ >+ char *path = talloc_strdup(mem_ctx, handle->conn->connectpath); >+ dev_t dev; >+ struct stat st; >+ char *p; >+ >+ if (stat(path, &st) != 0) { >+ talloc_free(path); >+ return NULL; >+ } >+ >+ dev = st.st_dev; >+ >+ while ((p = strrchr(path, '/')) && p > path) { >+ *p = 0; >+ if (stat(path, &st) != 0) { >+ talloc_free(path); >+ return NULL; >+ } >+ if (st.st_dev != dev) { >+ *p = '/'; >+ break; >+ } >+ } >+ >+ return path; >+} >+ >+static char *shadow_copy3_convert(TALLOC_CTX *mem_ctx, >+ struct vfs_handle_struct *handle, >+ const char *name, time_t timestamp) >+{ >+ struct smb_filename converted_fname; >+ char *result = NULL; >+ size_t *slashes = NULL; >+ unsigned num_slashes; >+ char *path = NULL; >+ size_t pathlen; >+ char *insert = NULL; >+ char *converted = NULL; >+ size_t insertlen; >+ int i, saved_errno; >+ size_t min_offset; >+ >+ path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath, >+ name); >+ if (path == NULL) { >+ errno = ENOMEM; >+ goto fail; >+ } >+ pathlen = talloc_get_size(path)-1; >+ >+ DEBUG(10, ("converting %s\n", path)); >+ >+ if (!shadow_copy3_find_slashes(talloc_tos(), path, >+ &slashes, &num_slashes)) { >+ goto fail; >+ } >+ insert = shadow_copy3_insert_string(talloc_tos(), handle, timestamp); >+ if (insert == NULL) { >+ goto fail; >+ } >+ insertlen = talloc_get_size(insert)-1; >+ converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1); >+ if (converted == NULL) { >+ goto fail; >+ } >+ >+ if (path[pathlen-1] != '/') { >+ /* >+ * Append a fake slash to find the snapshot root >+ */ >+ size_t *tmp; >+ tmp = talloc_realloc(talloc_tos(), slashes, >+ size_t, num_slashes+1); >+ if (tmp == NULL) { >+ goto fail; >+ } >+ slashes = tmp; >+ slashes[num_slashes] = pathlen; >+ num_slashes += 1; >+ } >+ >+ min_offset = 0; >+ >+ if (!lp_parm_bool(SNUM(handle->conn), "shadow", "crossmountpoints", >+ false)) { >+ char *mount_point; >+ >+ mount_point = shadow_copy3_find_mount_point(talloc_tos(), >+ handle); >+ if (mount_point == NULL) { >+ goto fail; >+ } >+ min_offset = strlen(mount_point); >+ TALLOC_FREE(mount_point); >+ } >+ >+ memcpy(converted, path, pathlen+1); >+ converted[pathlen+insertlen] = '\0'; >+ >+ ZERO_STRUCT(converted_fname); >+ converted_fname.base_name = converted; >+ >+ for (i = num_slashes-1; i>=0; i--) { >+ int ret; >+ size_t offset; >+ >+ offset = slashes[i]; >+ >+ if (offset < min_offset) { >+ errno = ENOENT; >+ goto fail; >+ } >+ >+ memcpy(converted+offset, insert, insertlen); >+ >+ offset += insertlen; >+ memcpy(converted+offset, path + slashes[i], >+ pathlen - slashes[i]); >+ >+ ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname); >+ >+ DEBUG(10, ("Trying %s: %d (%s)\n", converted, >+ ret, ret == 0 ? "ok" : strerror(errno))); >+ if (ret == 0) { >+ /* success */ >+ break; >+ } >+ if (errno == ENOTDIR) { >+ /* >+ * This is a valid condition: We appended the >+ * .snaphots/@GMT.. to a file name. Just try >+ * with the upper levels. >+ */ >+ continue; >+ } >+ if (errno != ENOENT) { >+ /* Other problem than "not found" */ >+ goto fail; >+ } >+ } >+ >+ if (i >= 0) { >+ /* >+ * Found something >+ */ >+ DEBUG(10, ("Found %s\n", converted)); >+ result = converted; >+ converted = NULL; >+ } else { >+ errno = ENOENT; >+ } >+fail: >+ saved_errno = errno; >+ TALLOC_FREE(converted); >+ TALLOC_FREE(insert); >+ TALLOC_FREE(slashes); >+ TALLOC_FREE(path); >+ errno = saved_errno; >+ return result; >+} >+ >+/* >+ modify a sbuf return to ensure that inodes in the shadow directory >+ are different from those in the main directory >+ */ >+static void convert_sbuf(vfs_handle_struct *handle, const char *fname, >+ SMB_STRUCT_STAT *sbuf) >+{ >+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) { >+ /* some snapshot systems, like GPFS, return the name >+ device:inode for the snapshot files as the current >+ files. That breaks the 'restore' button in the shadow copy >+ GUI, as the client gets a sharing violation. >+ >+ This is a crude way of allowing both files to be >+ open at once. It has a slight chance of inode >+ number collision, but I can't see a better approach >+ without significant VFS changes >+ */ >+ uint32_t shash; >+ TDB_DATA data = string_tdb_data(fname); >+ >+ shash = tdb_jenkins_hash(&data) & 0xFF000000; >+ if (shash == 0) { >+ shash = 1; >+ } >+ sbuf->st_ex_ino ^= shash; >+ } >+} >+ >+static SMB_STRUCT_DIR *shadow_copy3_opendir(vfs_handle_struct *handle, >+ const char *fname, >+ const char *mask, >+ uint32 attr) >+{ >+ time_t timestamp; >+ char *stripped; >+ SMB_STRUCT_DIR *ret; >+ int saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return NULL; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return NULL; >+ } >+ ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_rename(vfs_handle_struct *handle, >+ const struct smb_filename *smb_fname_src, >+ const struct smb_filename *smb_fname_dst) >+{ >+ time_t timestamp_src, timestamp_dst; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ smb_fname_src->base_name, >+ ×tamp_src, NULL)) { >+ return -1; >+ } >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ smb_fname_dst->base_name, >+ ×tamp_dst, NULL)) { >+ return -1; >+ } >+ if (timestamp_src != 0) { >+ errno = EXDEV; >+ return -1; >+ } >+ if (timestamp_dst != 0) { >+ errno = EROFS; >+ return -1; >+ } >+ return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst); >+} >+ >+static int shadow_copy3_symlink(vfs_handle_struct *handle, >+ const char *oldname, const char *newname) >+{ >+ time_t timestamp_old, timestamp_new; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, oldname, >+ ×tamp_old, NULL)) { >+ return -1; >+ } >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, newname, >+ ×tamp_new, NULL)) { >+ return -1; >+ } >+ if ((timestamp_old != 0) || (timestamp_new != 0)) { >+ errno = EROFS; >+ return -1; >+ } >+ return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname); >+} >+ >+static int shadow_copy3_link(vfs_handle_struct *handle, >+ const char *oldname, const char *newname) >+{ >+ time_t timestamp_old, timestamp_new; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, oldname, >+ ×tamp_old, NULL)) { >+ return -1; >+ } >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, newname, >+ ×tamp_new, NULL)) { >+ return -1; >+ } >+ if ((timestamp_old != 0) || (timestamp_new != 0)) { >+ errno = EROFS; >+ return -1; >+ } >+ return SMB_VFS_NEXT_LINK(handle, oldname, newname); >+} >+ >+static int shadow_copy3_stat(vfs_handle_struct *handle, >+ struct smb_filename *smb_fname) >+{ >+ time_t timestamp; >+ char *stripped, *tmp; >+ int ret, saved_errno; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ smb_fname->base_name, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_STAT(handle, smb_fname); >+ } >+ >+ tmp = smb_fname->base_name; >+ smb_fname->base_name = shadow_copy3_convert( >+ talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ >+ if (smb_fname->base_name == NULL) { >+ smb_fname->base_name = tmp; >+ return -1; >+ } >+ >+ ret = SMB_VFS_NEXT_STAT(handle, smb_fname); >+ saved_errno = errno; >+ >+ TALLOC_FREE(smb_fname->base_name); >+ smb_fname->base_name = tmp; >+ >+ if (ret == 0) { >+ convert_sbuf(handle, smb_fname->base_name, &smb_fname->st); >+ } >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_lstat(vfs_handle_struct *handle, >+ struct smb_filename *smb_fname) >+{ >+ time_t timestamp; >+ char *stripped, *tmp; >+ int ret, saved_errno; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ smb_fname->base_name, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_LSTAT(handle, smb_fname); >+ } >+ >+ tmp = smb_fname->base_name; >+ smb_fname->base_name = shadow_copy3_convert( >+ talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ >+ if (smb_fname->base_name == NULL) { >+ smb_fname->base_name = tmp; >+ return -1; >+ } >+ >+ ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); >+ saved_errno = errno; >+ >+ TALLOC_FREE(smb_fname->base_name); >+ smb_fname->base_name = tmp; >+ >+ if (ret == 0) { >+ convert_sbuf(handle, smb_fname->base_name, &smb_fname->st); >+ } >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_fstat(vfs_handle_struct *handle, files_struct *fsp, >+ SMB_STRUCT_STAT *sbuf) >+{ >+ time_t timestamp; >+ int ret; >+ >+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); >+ if (ret == -1) { >+ return ret; >+ } >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ fsp->fsp_name->base_name, >+ ×tamp, NULL)) { >+ return 0; >+ } >+ if (timestamp != 0) { >+ convert_sbuf(handle, fsp->fsp_name->base_name, sbuf); >+ } >+ return 0; >+} >+ >+static int shadow_copy3_open(vfs_handle_struct *handle, >+ struct smb_filename *smb_fname, files_struct *fsp, >+ int flags, mode_t mode) >+{ >+ time_t timestamp; >+ char *stripped, *tmp; >+ int ret, saved_errno; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ smb_fname->base_name, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); >+ } >+ >+ tmp = smb_fname->base_name; >+ smb_fname->base_name = shadow_copy3_convert( >+ talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ >+ if (smb_fname->base_name == NULL) { >+ smb_fname->base_name = tmp; >+ return -1; >+ } >+ >+ ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); >+ saved_errno = errno; >+ >+ TALLOC_FREE(smb_fname->base_name); >+ smb_fname->base_name = tmp; >+ >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_unlink(vfs_handle_struct *handle, >+ const struct smb_filename *smb_fname) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ struct smb_filename *conv; >+ NTSTATUS status; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ smb_fname->base_name, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_UNLINK(handle, smb_fname); >+ } >+ status = copy_smb_filename(talloc_tos(), smb_fname, &conv); >+ if (!NT_STATUS_IS_OK(status)) { >+ errno = ENOMEM; >+ return -1; >+ } >+ conv->base_name = shadow_copy3_convert( >+ conv, handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv->base_name == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_UNLINK(handle, conv); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_chmod(vfs_handle_struct *handle, const char *fname, >+ mode_t mode) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_CHMOD(handle, fname, mode); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_chown(vfs_handle_struct *handle, const char *fname, >+ uid_t uid, gid_t gid) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_chdir(vfs_handle_struct *handle, >+ const char *fname) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_CHDIR(handle, fname); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_CHDIR(handle, conv); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_ntimes(vfs_handle_struct *handle, >+ const struct smb_filename *smb_fname, >+ struct smb_file_time *ft) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ struct smb_filename *conv; >+ NTSTATUS status; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, >+ smb_fname->base_name, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft); >+ } >+ status = copy_smb_filename(talloc_tos(), smb_fname, &conv); >+ if (!NT_STATUS_IS_OK(status)) { >+ errno = ENOMEM; >+ return -1; >+ } >+ conv->base_name = shadow_copy3_convert( >+ conv, handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv->base_name == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_readlink(vfs_handle_struct *handle, >+ const char *fname, char *buf, size_t bufsiz) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_mknod(vfs_handle_struct *handle, >+ const char *fname, mode_t mode, SMB_DEV_T dev) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static char *shadow_copy3_realpath(vfs_handle_struct *handle, >+ const char *fname) >+{ >+ time_t timestamp; >+ char *stripped = NULL; >+ char *tmp = NULL; >+ char *result = NULL; >+ char *inserted = NULL; >+ char *inserted_to, *inserted_end; >+ int saved_errno; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ goto done; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_REALPATH(handle, fname); >+ } >+ >+ tmp = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ if (tmp == NULL) { >+ goto done; >+ } >+ >+ result = SMB_VFS_NEXT_REALPATH(handle, tmp); >+ if (result == NULL) { >+ goto done; >+ } >+ >+ /* >+ * Take away what we've inserted. This removes the @GMT-thingy >+ * completely, but will give a path under the share root. >+ */ >+ inserted = shadow_copy3_insert_string(talloc_tos(), handle, timestamp); >+ if (inserted == NULL) { >+ goto done; >+ } >+ inserted_to = strstr_m(result, inserted); >+ if (inserted_to == NULL) { >+ DEBUG(2, ("SMB_VFS_NEXT_REALPATH removed %s\n", inserted)); >+ goto done; >+ } >+ inserted_end = inserted_to + talloc_get_size(inserted) - 1; >+ memmove(inserted_to, inserted_end, strlen(inserted_end)+1); >+ >+done: >+ saved_errno = errno; >+ TALLOC_FREE(inserted); >+ TALLOC_FREE(tmp); >+ TALLOC_FREE(stripped); >+ errno = saved_errno; >+ return result; >+} >+ >+static char *have_snapdir(struct vfs_handle_struct *handle, >+ const char *path) >+{ >+ struct smb_filename smb_fname; >+ int ret; >+ >+ ZERO_STRUCT(smb_fname); >+ smb_fname.base_name = talloc_asprintf( >+ talloc_tos(), "%s/%s", path, >+ lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", >+ ".snapshots")); >+ if (smb_fname.base_name == NULL) { >+ return NULL; >+ } >+ >+ ret = SMB_VFS_NEXT_STAT(handle, &smb_fname); >+ if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) { >+ return smb_fname.base_name; >+ } >+ TALLOC_FREE(smb_fname.base_name); >+ return NULL; >+} >+ >+static char *shadow_copy3_find_snapdir(TALLOC_CTX *mem_ctx, >+ struct vfs_handle_struct *handle, >+ struct smb_filename *smb_fname) >+{ >+ char *path, *p; >+ >+ path = talloc_asprintf(mem_ctx, "%s/%s", >+ handle->conn->connectpath, >+ smb_fname->base_name); >+ if (path == NULL) { >+ return NULL; >+ } >+ >+ while ((p = strrchr(path, '/')) && (p > path)) { >+ char *snapdir; >+ >+ p[0] = '\0'; >+ >+ snapdir = have_snapdir(handle, path); >+ if (snapdir != NULL) { >+ TALLOC_FREE(path); >+ return snapdir; >+ } >+ } >+ TALLOC_FREE(path); >+ return NULL; >+} >+ >+static bool shadow_copy3_snapshot_to_gmt(TALLOC_CTX *mem_ctx, >+ vfs_handle_struct *handle, >+ const char *name, >+ char *gmt, size_t gmt_len) >+{ >+ struct tm timestamp; >+ time_t timestamp_t; >+ const char *fmt; >+ >+ fmt = lp_parm_const_string(SNUM(handle->conn), "shadow", >+ "format", GMT_FORMAT); >+ >+ ZERO_STRUCT(timestamp); >+ if (strptime(name, fmt, ×tamp) == NULL) { >+ DEBUG(10, ("shadow_copy2_snapshot_to_gmt: no match %s: %s\n", >+ fmt, name)); >+ return false; >+ } >+ >+ DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n", fmt, name)); >+ >+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime", false)) { >+ timestamp.tm_isdst = -1; >+ timestamp_t = mktime(×tamp); >+ gmtime_r(×tamp_t, ×tamp); >+ } >+ strftime(gmt, gmt_len, GMT_FORMAT, ×tamp); >+ return true; >+} >+ >+static int shadow_copy3_get_shadow_copy_data( >+ vfs_handle_struct *handle, files_struct *fsp, >+ struct shadow_copy_data *shadow_copy3_data, >+ bool labels) >+{ >+ SMB_STRUCT_DIR *p; >+ const char *snapdir; >+ SMB_STRUCT_DIRENT *d; >+ TALLOC_CTX *tmp_ctx = talloc_stackframe(); >+ >+ snapdir = shadow_copy3_find_snapdir(tmp_ctx, handle, fsp->fsp_name); >+ if (snapdir == NULL) { >+ DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n", >+ handle->conn->connectpath)); >+ errno = EINVAL; >+ talloc_free(tmp_ctx); >+ return -1; >+ } >+ >+ p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0); >+ >+ if (!p) { >+ DEBUG(2,("shadow_copy3: SMB_VFS_NEXT_OPENDIR() failed for '%s'" >+ " - %s\n", snapdir, strerror(errno))); >+ talloc_free(tmp_ctx); >+ errno = ENOSYS; >+ return -1; >+ } >+ >+ shadow_copy3_data->num_volumes = 0; >+ shadow_copy3_data->labels = NULL; >+ >+ while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) { >+ char snapshot[GMT_NAME_LEN+1]; >+ SHADOW_COPY_LABEL *tlabels; >+ >+ /* >+ * ignore names not of the right form in the snapshot >+ * directory >+ */ >+ if (!shadow_copy3_snapshot_to_gmt( >+ tmp_ctx, handle, d->d_name, >+ snapshot, sizeof(snapshot))) { >+ >+ DEBUG(6, ("shadow_copy3_get_shadow_copy_data: " >+ "ignoring %s\n", d->d_name)); >+ continue; >+ } >+ DEBUG(6,("shadow_copy3_get_shadow_copy_data: %s -> %s\n", >+ d->d_name, snapshot)); >+ >+ if (!labels) { >+ /* the caller doesn't want the labels */ >+ shadow_copy3_data->num_volumes++; >+ continue; >+ } >+ >+ tlabels = talloc_realloc(shadow_copy3_data->mem_ctx, >+ shadow_copy3_data->labels, >+ SHADOW_COPY_LABEL, >+ shadow_copy3_data->num_volumes+1); >+ if (tlabels == NULL) { >+ DEBUG(0,("shadow_copy3: out of memory\n")); >+ SMB_VFS_NEXT_CLOSEDIR(handle, p); >+ talloc_free(tmp_ctx); >+ return -1; >+ } >+ >+ strlcpy(tlabels[shadow_copy3_data->num_volumes], snapshot, >+ sizeof(*tlabels)); >+ >+ shadow_copy3_data->num_volumes++; >+ shadow_copy3_data->labels = tlabels; >+ } >+ >+ SMB_VFS_NEXT_CLOSEDIR(handle,p); >+ >+ talloc_free(tmp_ctx); >+ return 0; >+} >+ >+static NTSTATUS shadow_copy3_get_nt_acl(vfs_handle_struct *handle, >+ const char *fname, >+ uint32 security_info, >+ struct security_descriptor **ppdesc) >+{ >+ time_t timestamp; >+ char *stripped; >+ NTSTATUS status; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return map_nt_error_from_unix(errno); >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info, >+ ppdesc); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return map_nt_error_from_unix(errno); >+ } >+ status = SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info, ppdesc); >+ TALLOC_FREE(conv); >+ return status; >+} >+ >+static int shadow_copy3_mkdir(vfs_handle_struct *handle, >+ const char *fname, mode_t mode) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_MKDIR(handle, fname, mode); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_rmdir(vfs_handle_struct *handle, const char *fname) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_RMDIR(handle, fname); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_RMDIR(handle, conv); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_chflags(vfs_handle_struct *handle, const char *fname, >+ unsigned int flags) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static ssize_t shadow_copy3_getxattr(vfs_handle_struct *handle, >+ const char *fname, const char *aname, >+ void *value, size_t size) >+{ >+ time_t timestamp; >+ char *stripped; >+ ssize_t ret; >+ int saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value, >+ size); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static ssize_t shadow_copy3_lgetxattr(vfs_handle_struct *handle, >+ const char *fname, const char *aname, >+ void *value, size_t size) >+{ >+ time_t timestamp; >+ char *stripped; >+ ssize_t ret; >+ int saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_LGETXATTR(handle, fname, aname, value, >+ size); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_LGETXATTR(handle, conv, aname, value, size); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static ssize_t shadow_copy3_listxattr(struct vfs_handle_struct *handle, >+ const char *fname, >+ char *list, size_t size) >+{ >+ time_t timestamp; >+ char *stripped; >+ ssize_t ret; >+ int saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_removexattr(vfs_handle_struct *handle, >+ const char *fname, const char *aname) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_lremovexattr(vfs_handle_struct *handle, >+ const char *fname, const char *aname) >+{ >+ time_t timestamp; >+ char *stripped; >+ int ret, saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_LREMOVEXATTR(handle, fname, aname); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_LREMOVEXATTR(handle, conv, aname); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_setxattr(struct vfs_handle_struct *handle, >+ const char *fname, >+ const char *aname, const void *value, >+ size_t size, int flags) >+{ >+ time_t timestamp; >+ char *stripped; >+ ssize_t ret; >+ int saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size, >+ flags); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_lsetxattr(struct vfs_handle_struct *handle, >+ const char *fname, >+ const char *aname, const void *value, >+ size_t size, int flags) >+{ >+ time_t timestamp; >+ char *stripped; >+ ssize_t ret; >+ int saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_LSETXATTR(handle, fname, aname, value, >+ size, flags); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_LSETXATTR(handle, conv, aname, value, size, flags); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_chmod_acl(vfs_handle_struct *handle, >+ const char *fname, mode_t mode) >+{ >+ time_t timestamp; >+ char *stripped; >+ ssize_t ret; >+ int saved_errno; >+ char *conv; >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, fname, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+static int shadow_copy3_get_real_filename(struct vfs_handle_struct *handle, >+ const char *path, >+ const char *name, >+ TALLOC_CTX *mem_ctx, >+ char **found_name) >+{ >+ time_t timestamp; >+ char *stripped; >+ ssize_t ret; >+ int saved_errno; >+ char *conv; >+ >+ if (shadow_copy3_strip_snapshot(talloc_tos(), handle, name, >+ ×tamp, &stripped) >+ && (stripped[0] == '\0')) { >+ *found_name = talloc_strdup(mem_ctx, name); >+ if (*found_name == NULL) { >+ errno = ENOMEM; >+ return -1; >+ } >+ return 0; >+ } >+ >+ if (!shadow_copy3_strip_snapshot(talloc_tos(), handle, path, >+ ×tamp, &stripped)) { >+ return -1; >+ } >+ if (timestamp == 0) { >+ return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name, >+ mem_ctx, found_name); >+ } >+ conv = shadow_copy3_convert(talloc_tos(), handle, stripped, timestamp); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name, >+ mem_ctx, found_name); >+ saved_errno = errno; >+ TALLOC_FREE(conv); >+ errno = saved_errno; >+ return ret; >+} >+ >+ >+static struct vfs_fn_pointers vfs_shadow_copy3_fns = { >+ .opendir = shadow_copy3_opendir, >+ .rename = shadow_copy3_rename, >+ .link = shadow_copy3_link, >+ .symlink = shadow_copy3_symlink, >+ .stat = shadow_copy3_stat, >+ .lstat = shadow_copy3_lstat, >+ .fstat = shadow_copy3_fstat, >+ .open = shadow_copy3_open, >+ .unlink = shadow_copy3_unlink, >+ .chmod = shadow_copy3_chmod, >+ .chown = shadow_copy3_chown, >+ .chdir = shadow_copy3_chdir, >+ .ntimes = shadow_copy3_ntimes, >+ .vfs_readlink = shadow_copy3_readlink, >+ .mknod = shadow_copy3_mknod, >+ .realpath = shadow_copy3_realpath, >+ .get_nt_acl = shadow_copy3_get_nt_acl, >+ .get_shadow_copy_data = shadow_copy3_get_shadow_copy_data, >+ .mkdir = shadow_copy3_mkdir, >+ .rmdir = shadow_copy3_rmdir, >+ .getxattr = shadow_copy3_getxattr, >+ .lgetxattr = shadow_copy3_lgetxattr, >+ .listxattr = shadow_copy3_listxattr, >+ .removexattr = shadow_copy3_removexattr, >+ .lremovexattr = shadow_copy3_lremovexattr, >+ .setxattr = shadow_copy3_setxattr, >+ .lsetxattr = shadow_copy3_lsetxattr, >+ .chmod_acl = shadow_copy3_chmod_acl, >+ .chflags = shadow_copy3_chflags, >+ .get_real_filename = shadow_copy3_get_real_filename, >+}; >+ >+NTSTATUS vfs_shadow_copy3_init(void); >+NTSTATUS vfs_shadow_copy3_init(void) >+{ >+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, >+ "shadow_copy3", &vfs_shadow_copy3_fns); >+} >-- >1.7.0.4 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 7913
:
6418
| 6422 |
6905