X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fmodules%2Fvfs_shadow_copy2.c;h=7ea7d352b2adc8ab137ffe9368f751ba4e40e8a6;hb=a0dcac44e4432bd533673712ae76546471533e54;hp=ade8c28a12e03006d0864b79933bfe6176b6ae0a;hpb=3d053b1ab3e0b918509e06086a54834a9ae9cdb7;p=obnox%2Fsamba%2Fsamba-obnox.git diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index ade8c28a12e..7ea7d352b2a 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1,10 +1,11 @@ /* - * Third attempt at a shadow copy module + * shadow_copy2: a shadow copy module (second implementation) * * Copyright (C) Andrew Tridgell 2007 (portions taken from shadow_copy2) * Copyright (C) Ed Plese 2009 * Copyright (C) Volker Lendecke 2011 * Copyright (C) Christian Ambach 2011 + * Copyright (C) Michael Adam 2013 * * 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 @@ -22,89 +23,16 @@ */ /* - - This is a 3rd implemetation of a shadow copy module for exposing - snapshots to windows clients as shadow copies. This version has the - following features: - - 1) you don't need to populate your shares with symlinks to the - snapshots. This can be very important when you have thousands of - shares, or use [homes] - - 2) the inode number of the files is altered so it is different - from the original. This allows the 'restore' button to work - without a sharing violation - - 3) shadow copy results can be sorted before being sent to the - client. This is beneficial for filesystems that don't read - directories alphabetically (the default unix). - - 4) vanity naming for snapshots. Snapshots can be named in any - format compatible with str[fp]time conversions. - - 5) time stamps in snapshot names can be represented in localtime - rather than UTC. - - Module options: - - shadow:snapdir = - - This is the directory containing the @GMT-* snapshot directories. If it is an absolute - path it is used as-is. If it is a relative path, then it is taken relative to the mount - point of the filesystem that the root of this share is on - - shadow:basedir = - - This is an optional parameter that specifies the directory that - the snapshots are relative to. It defaults to the filesystem - mount point - - shadow:fixinodes = yes/no - - If you enable shadow:fixinodes then this module will modify the - apparent inode number of files in the snapshot directories using - a hash of the files path. This is needed for snapshot systems - where the snapshots have the same device:inode number as the - original files (such as happens with GPFS snapshots). If you - don't set this option then the 'restore' button in the shadow - copy UI will fail with a sharing violation. - - shadow:sort = asc/desc, or not specified for unsorted (default) - - This is an optional parameter that specifies that the shadow - copy directories should be sorted before sending them to the - client. This can be beneficial as unix filesystems are usually - not listed alphabetically sorted. If enabled, you typically - want to specify descending order. - - shadow:format = - - This is an optional parameter that specifies the format - specification for the naming of snapshots. The format must - be compatible with the conversion specifications recognized - by str[fp]time. The default value is "@GMT-%Y.%m.%d-%H.%M.%S". - - shadow:sscanf = yes/no (default is no) - - The time is the unsigned long integer (%lu) in the format string - rather than a time strptime() can parse. The result must be a unix time_t - time. - - shadow:localtime = yes/no (default is no) - - This is an optional parameter that indicates whether the - snapshot names are in UTC/GMT or the local time. - - - The following command would generate a correctly formatted directory name - for use with the default parameters: - date -u +@GMT-%Y.%m.%d-%H.%M.%S + * This is a second implemetation of a shadow copy module for exposing + * file system snapshots to windows clients as shadow copies. + * + * See the manual page for documentation. */ #include "includes.h" +#include "smbd/smbd.h" #include "system/filesys.h" #include "include/ntioctl.h" -#include #include "util_tdb.h" struct shadow_copy2_config { @@ -117,9 +45,8 @@ struct shadow_copy2_config { bool fixinodes; char *sort_order; bool snapdir_absolute; - char *basedir; char *mount_point; - char *rel_connectpath; /* share root, relative to the basedir */ + char *rel_connectpath; /* share root, relative to a snapshot root */ char *snapshot_basepath; /* the absolute version of snapdir */ }; @@ -158,7 +85,7 @@ static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, } /** - * Given a timstamp, build the posix level GTM-tag string + * Given a timestamp, build the posix level GMT-tag string * based on the configurable format. */ static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle, @@ -208,7 +135,7 @@ static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle, } /** - * Given a timstamp, build the string to insert into a path + * Given a timestamp, build the string to insert into a path * as a path component for creating the local path to the * snapshot at the given timestamp of the input path. * @@ -290,7 +217,7 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx, } /** - * Strip a snapshot component from an filename as + * Strip a snapshot component from a filename as * handed in via the smb layer. * Returns the parsed timestamp and the stripped filename. */ @@ -307,31 +234,71 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, char *stripped; size_t rest_len, dst_len; struct shadow_copy2_config *config; + const char *snapdir; + ssize_t snapdirlen; + ptrdiff_t len_before_gmt; SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, return false); + DEBUG(10, (__location__ ": enter path '%s'\n", name)); + p = strstr_m(name, "@GMT-"); if (p == NULL) { + DEBUG(11, ("@GMT not found\n")); goto no_snapshot; } if ((p > name) && (p[-1] != '/')) { /* the GMT-token does not start a path-component */ + DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n", + p, name, (int)p[-1])); goto no_snapshot; } + + /* + * Figure out whether we got an already converted string. One + * case where this happens is in a smb2 create call with the + * mxac create blob set. We do the get_acl call on + * fsp->fsp_name, which is already converted. We are converted + * if we got a file name of the form ".snapshots/@GMT-", + * i.e. ".snapshots/" precedes "p". + */ + + snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", + ".snapshots"); + snapdirlen = strlen(snapdir); + len_before_gmt = p - name; + + if ((len_before_gmt >= (snapdirlen + 1)) && (p[-1] == '/')) { + const char *parent_snapdir = p - (snapdirlen+1); + + DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir)); + + if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) { + DEBUG(10, ("name=%s is already converted\n", name)); + goto no_snapshot; + } + } q = strptime(p, GMT_FORMAT, &tm); if (q == NULL) { + DEBUG(10, ("strptime failed\n")); goto no_snapshot; } tm.tm_isdst = -1; timestamp = timegm(&tm); if (timestamp == (time_t)-1) { + DEBUG(10, ("timestamp==-1\n")); goto no_snapshot; } - if ((p == name) && (q[0] == '\0')) { - /* the name consists of only the GMT token */ + if (q[0] == '\0') { + /* + * The name consists of only the GMT token or the GMT + * token is at the end of the path. XP seems to send + * @GMT- at the end under certain circumstances even + * with a path prefix. + */ if (pstripped != NULL) { - stripped = talloc_strdup(mem_ctx, ""); + stripped = talloc_strndup(mem_ctx, name, p - name); if (stripped == NULL) { return false; } @@ -342,13 +309,10 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, } if (q[0] != '/') { /* - * The GMT token is either at the end of the path - * or it is not a complete path component, i.e. the - * path component continues after the gmt-token. - * - * TODO: Is this correct? Or would the GMT tag as the - * last component be a valid input? + * It is not a complete path component, i.e. the path + * component continues after the gmt-token. */ + DEBUG(10, ("q[0] = %d\n", (int)q[0])); goto no_snapshot; } q += 1; @@ -366,11 +330,51 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, return false; } + DEBUG(10, (__location__ ": snapdirseverywhere mode.\n" + "path '%s'.\n" + "insert string '%s'\n", name, insert)); + have_insert = (strstr(name, insert+1) != NULL); - TALLOC_FREE(insert); + DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n", + (int)have_insert, name, insert+1)); if (have_insert) { + DEBUG(10, (__location__ ": insert string '%s' found in " + "path '%s' found in snapdirseverywhere mode " + "==> already converted\n", insert, name)); + TALLOC_FREE(insert); + goto no_snapshot; + } + TALLOC_FREE(insert); + } else { + char *snapshot_path; + char *s; + + snapshot_path = shadow_copy2_snapshot_path(talloc_tos(), + handle, + timestamp); + if (snapshot_path == NULL) { + errno = ENOMEM; + return false; + } + + DEBUG(10, (__location__ " path: '%s'.\n" + "snapshot path: '%s'\n", name, snapshot_path)); + + s = strstr(name, snapshot_path); + if (s == name) { + /* + * this starts with "snapshot_basepath/GMT-Token" + * so it is already a converted absolute + * path. Don't process further. + */ + DEBUG(10, (__location__ ": path '%s' starts with " + "snapshot path '%s' (not in " + "snapdirseverywhere mode) ==> " + "already converted\n", name, snapshot_path)); + talloc_free(snapshot_path); goto no_snapshot; } + talloc_free(snapshot_path); } if (pstripped != NULL) { @@ -429,10 +433,13 @@ static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx, * Convert from a name as handed in via the SMB layer * and a timestamp into the local path of the snapshot * of the provided file at the provided time. + * Also return the path in the snapshot corresponding + * to the file's share root. */ -static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, - struct vfs_handle_struct *handle, - const char *name, time_t timestamp) +static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx, + struct vfs_handle_struct *handle, + const char *name, time_t timestamp, + size_t *snaproot_len) { struct smb_filename converted_fname; char *result = NULL; @@ -442,33 +449,100 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, size_t pathlen; char *insert = NULL; char *converted = NULL; - size_t insertlen; + size_t insertlen, connectlen = 0; int i, saved_errno; size_t min_offset; struct shadow_copy2_config *config; + size_t in_share_offset = 0; SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, return NULL); - path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath, - name); + DEBUG(10, ("converting '%s'\n", name)); + + if (!config->snapdirseverywhere) { + int ret; + char *snapshot_path; + + snapshot_path = shadow_copy2_snapshot_path(talloc_tos(), + handle, + timestamp); + if (snapshot_path == NULL) { + goto fail; + } + + if (config->rel_connectpath == NULL) { + converted = talloc_asprintf(mem_ctx, "%s/%s", + snapshot_path, name); + } else { + converted = talloc_asprintf(mem_ctx, "%s/%s/%s", + snapshot_path, + config->rel_connectpath, + name); + } + if (converted == NULL) { + goto fail; + } + + ZERO_STRUCT(converted_fname); + converted_fname.base_name = converted; + + ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname); + DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n", + converted, + ret, ret == 0 ? "ok" : strerror(errno))); + if (ret == 0) { + DEBUG(10, ("Found %s\n", converted)); + result = converted; + converted = NULL; + if (snaproot_len != NULL) { + *snaproot_len = strlen(snapshot_path); + if (config->rel_connectpath != NULL) { + *snaproot_len += + strlen(config->rel_connectpath) + 1; + } + } + goto fail; + } else { + errno = ENOENT; + goto fail; + } + /* never reached ... */ + } + + connectlen = strlen(handle->conn->connectpath); + if (name[0] == 0) { + path = talloc_strdup(mem_ctx, handle->conn->connectpath); + } else { + 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_copy2_find_slashes(talloc_tos(), path, &slashes, &num_slashes)) { goto fail; } + insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp); if (insert == NULL) { goto fail; } insertlen = talloc_get_size(insert)-1; + + /* + * Note: We deliberatly don't expensively initialize the + * array with talloc_zero here: Putting zero into + * converted[pathlen+insertlen] below is sufficient, because + * in the following for loop, the insert string is inserted + * at various slash places. So the memory up to position + * pathlen+insertlen will always be initialized when the + * converted string is used. + */ converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1); if (converted == NULL) { goto fail; @@ -492,15 +566,7 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, min_offset = 0; if (!config->crossmountpoints) { - char *mount_point; - - mount_point = shadow_copy2_find_mount_point(talloc_tos(), - handle); - if (mount_point == NULL) { - goto fail; - } - min_offset = strlen(mount_point); - TALLOC_FREE(mount_point); + min_offset = strlen(config->mount_point); } memcpy(converted, path, pathlen+1); @@ -520,6 +586,10 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, goto fail; } + if (offset >= connectlen) { + in_share_offset = offset; + } + memcpy(converted+offset, insert, insertlen); offset += insertlen; @@ -528,10 +598,14 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname); - DEBUG(10, ("Trying %s: %d (%s)\n", converted, + DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n", + converted, ret, ret == 0 ? "ok" : strerror(errno))); if (ret == 0) { /* success */ + if (snaproot_len != NULL) { + *snaproot_len = in_share_offset + insertlen; + } break; } if (errno == ENOTDIR) { @@ -568,6 +642,18 @@ fail: return result; } +/** + * Convert from a name as handed in via the SMB layer + * and a timestamp into the local path of the snapshot + * of the provided file at the provided time. + */ +static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, + struct vfs_handle_struct *handle, + const char *name, time_t timestamp) +{ + return shadow_copy2_do_convert(mem_ctx, handle, name, timestamp, NULL); +} + /* modify a sbuf return to ensure that inodes in the shadow directory are different from those in the main directory @@ -591,9 +677,11 @@ static void convert_sbuf(vfs_handle_struct *handle, const char *fname, number collision, but I can't see a better approach without significant VFS changes */ + TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname), + .dsize = strlen(fname) }; uint32_t shash; - shash = hash(fname, strlen(fname), 0) & 0xFF000000; + shash = tdb_jenkins_hash(&key) & 0xFF000000; if (shash == 0) { shash = 1; } @@ -604,7 +692,7 @@ static void convert_sbuf(vfs_handle_struct *handle, const char *fname, static DIR *shadow_copy2_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, - uint32 attr) + uint32_t attr) { time_t timestamp; char *stripped; @@ -1045,8 +1133,6 @@ static char *shadow_copy2_realpath(vfs_handle_struct *handle, char *stripped = NULL; char *tmp = NULL; char *result = NULL; - char *inserted = NULL; - char *inserted_to, *inserted_end; int saved_errno; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -1063,29 +1149,9 @@ static char *shadow_copy2_realpath(vfs_handle_struct *handle, } 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_copy2_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; @@ -1123,6 +1189,42 @@ static char *have_snapdir(struct vfs_handle_struct *handle, return NULL; } +static bool check_access_snapdir(struct vfs_handle_struct *handle, + const char *path) +{ + struct smb_filename smb_fname; + int ret; + NTSTATUS status; + + ZERO_STRUCT(smb_fname); + smb_fname.base_name = talloc_asprintf(talloc_tos(), + "%s", + path); + if (smb_fname.base_name == NULL) { + return false; + } + + ret = SMB_VFS_NEXT_STAT(handle, &smb_fname); + if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) { + TALLOC_FREE(smb_fname.base_name); + return false; + } + + status = smbd_check_access_rights(handle->conn, + &smb_fname, + false, + SEC_DIR_LIST); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("user does not have list permission " + "on snapdir %s\n", + smb_fname.base_name)); + TALLOC_FREE(smb_fname.base_name); + return false; + } + TALLOC_FREE(smb_fname.base_name); + return true; +} + /** * Find the snapshot directory (if any) for the given * filename (which is relative to the share). @@ -1272,6 +1374,7 @@ static int shadow_copy2_get_shadow_copy_data( const char *snapdir; struct dirent *d; TALLOC_CTX *tmp_ctx = talloc_stackframe(); + bool ret; snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name); if (snapdir == NULL) { @@ -1281,6 +1384,13 @@ static int shadow_copy2_get_shadow_copy_data( talloc_free(tmp_ctx); return -1; } + ret = check_access_snapdir(handle, snapdir); + if (!ret) { + DEBUG(0,("access denied on listing snapdir %s\n", snapdir)); + errno = EACCES; + talloc_free(tmp_ctx); + return -1; + } p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0); @@ -1348,7 +1458,7 @@ static int shadow_copy2_get_shadow_copy_data( static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle, struct files_struct *fsp, - uint32 security_info, + uint32_t security_info, TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc) { @@ -1380,7 +1490,7 @@ static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle, static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle, const char *fname, - uint32 security_info, + uint32_t security_info, TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc) { @@ -1645,39 +1755,84 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, int saved_errno; char *conv; + DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], " + "name=[%s]\n", path, name)); + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, ×tamp, &stripped)) { + DEBUG(10, ("shadow_copy2_strip_snapshot failed\n")); return -1; } if (timestamp == 0) { + DEBUG(10, ("timestamp == 0\n")); return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name, mem_ctx, found_name); } - if (stripped[0] == '\0') { - *found_name = talloc_strdup(mem_ctx, name); - if (*found_name == NULL) { - errno = ENOMEM; - return -1; - } - return 0; - } conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp); TALLOC_FREE(stripped); if (conv == NULL) { + DEBUG(10, ("shadow_copy2_convert failed\n")); return -1; } + DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], " + "name=[%s]\n", conv, name)); ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name, mem_ctx, found_name); + DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret)); saved_errno = errno; TALLOC_FREE(conv); errno = saved_errno; return ret; } +static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, + const char *fname) +{ + time_t timestamp; + char *stripped = NULL; + char *tmp = NULL; + char *result = NULL; + int saved_errno; + size_t rootpath_len = 0; + + DBG_DEBUG("Calc connect path for [%s]\n", fname); + + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, + ×tamp, &stripped)) { + goto done; + } + if (timestamp == 0) { + return SMB_VFS_NEXT_CONNECTPATH(handle, fname); + } + + tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp, + &rootpath_len); + if (tmp == NULL) { + goto done; + } + + DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp, + (int)rootpath_len, tmp); + + tmp[rootpath_len] = '\0'; + result = SMB_VFS_NEXT_REALPATH(handle, tmp); + if (result == NULL) { + goto done; + } + + DBG_DEBUG("connect path is [%s]\n", result); + +done: + saved_errno = errno; + TALLOC_FREE(tmp); + TALLOC_FREE(stripped); + errno = saved_errno; + return result; +} + static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, - const char *path, bool small_query, - uint64_t *bsize, uint64_t *dfree, - uint64_t *dsize) + const char *path, uint64_t *bsize, + uint64_t *dfree, uint64_t *dsize) { time_t timestamp; char *stripped; @@ -1690,7 +1845,7 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, return -1; } if (timestamp == 0) { - return SMB_VFS_NEXT_DISK_FREE(handle, path, small_query, + return SMB_VFS_NEXT_DISK_FREE(handle, path, bsize, dfree, dsize); } @@ -1700,8 +1855,7 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, return -1; } - ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, small_query, bsize, dfree, - dsize); + ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize); saved_errno = errno; TALLOC_FREE(conv); @@ -1718,7 +1872,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, const char *snapdir; const char *gmt_format; const char *sort_order; - const char *basedir; + const char *basedir = NULL; const char *mount_point; DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n", @@ -1799,11 +1953,12 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, char *p; p = strstr(handle->conn->connectpath, mount_point); if (p != handle->conn->connectpath) { - DEBUG(1, ("Warning: mount_point (%s) is not a " - "subdirectory of the share root " - "(%s). Ignoring provided value.\n", - mount_point, - handle->conn->connectpath)); + DBG_WARNING("Warning: the share root (%s) is " + "not a subdirectory of the " + "specified mountpoint (%s). " + "Ignoring provided value.\n", + handle->conn->connectpath, + mount_point); mount_point = NULL; } } @@ -1819,8 +1974,9 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, config->mount_point = shadow_copy2_find_mount_point(config, handle); if (config->mount_point == NULL) { - DEBUG(0, (__location__ ": shadow_copy2_find_mount_point" - " failed: %s\n", strerror(errno))); + DBG_WARNING("shadow_copy2_find_mount_point " + "of the share root '%s' failed: %s\n", + handle->conn->connectpath, strerror(errno)); return -1; } } @@ -1834,6 +1990,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, "relative ('%s'), but it has to be an " "absolute path. Disabling basedir.\n", basedir)); + basedir = NULL; } else { char *p; p = strstr(basedir, config->mount_point); @@ -1843,37 +2000,30 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, "mount point (%s). " "Disabling basedir\n", basedir, config->mount_point)); - } else { - config->basedir = talloc_strdup(config, - basedir); - if (config->basedir == NULL) { - DEBUG(0, ("talloc_strdup() failed\n")); - errno = ENOMEM; - return -1; - } + basedir = NULL; } } } - if (config->snapdirseverywhere && config->basedir != NULL) { + if (config->snapdirseverywhere && basedir != NULL) { DEBUG(1, (__location__ " Warning: 'basedir' is incompatible " "with 'snapdirseverywhere'. Disabling basedir.\n")); - TALLOC_FREE(config->basedir); + basedir = NULL; } - if (config->crossmountpoints && config->basedir != NULL) { + if (config->crossmountpoints && basedir != NULL) { DEBUG(1, (__location__ " Warning: 'basedir' is incompatible " "with 'crossmountpoints'. Disabling basedir.\n")); - TALLOC_FREE(config->basedir); + basedir = NULL; } - if (config->basedir == NULL) { - config->basedir = config->mount_point; + if (basedir == NULL) { + basedir = config->mount_point; } - if (strlen(config->basedir) != strlen(handle->conn->connectpath)) { + if (strlen(basedir) != strlen(handle->conn->connectpath)) { config->rel_connectpath = talloc_strdup(config, - handle->conn->connectpath + strlen(config->basedir)); + handle->conn->connectpath + strlen(basedir)); if (config->rel_connectpath == NULL) { DEBUG(0, ("talloc_strdup() failed\n")); errno = ENOMEM; @@ -1911,7 +2061,6 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, DEBUG(10, ("shadow_copy2_connect: configuration:\n" " share root: '%s'\n" - " basedir: '%s'\n" " mountpoint: '%s'\n" " rel share root: '%s'\n" " snapdir: '%s'\n" @@ -1924,7 +2073,6 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, " sort order: %s\n" "", handle->conn->connectpath, - config->basedir, config->mount_point, config->rel_connectpath, config->snapdir, @@ -1976,6 +2124,7 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = { .chmod_acl_fn = shadow_copy2_chmod_acl, .chflags_fn = shadow_copy2_chflags, .get_real_filename_fn = shadow_copy2_get_real_filename, + .connectpath_fn = shadow_copy2_connectpath, }; NTSTATUS vfs_shadow_copy2_init(void);