*/
/*
- * This is a second implemetation of a shadow copy module for exposing
+ * This is a second implementation of a shadow copy module for exposing
* file system snapshots to windows clients as shadow copies.
*
* See the manual page for documentation.
time_t fetch_time; /* snaplist update time */
};
-
/*
* shadow_copy2 private structure. This structure will be
* used to keep module specific information
bool labels);
/**
- *This function will create a new snapshot list entry and
+ * This function will create a new snapshot list entry and
* return to the caller. This entry will also be added to
* the global snapshot list.
*
}
/**
- *This function will delete the entire snaplist and reset
+ * This function will delete the entire snaplist and reset
* priv->snaps->snaplist to NULL.
*
* @param[in] priv shadow_copye specific data structure
config->snapdir, snaptime_string);
}
if (result == NULL) {
- DEBUG(1, (__location__ " talloc_asprintf failed\n"));
+ DBG_WARNING("talloc_asprintf failed\n");
}
return result;
result = talloc_asprintf(mem_ctx, "%s/%s",
priv->config->snapshot_basepath, snaptime_string);
if (result == NULL) {
- DEBUG(1, (__location__ " talloc_asprintf failed\n"));
+ DBG_WARNING("talloc_asprintf failed\n");
}
return result;
* This function does two things.
*
* 1). Checks if an incoming filename is already a
- * snapshot converted pathname.
+ * snapshot converted pathname.
* If so, it returns the pathname truncated
* at the snapshot point which will be used
* as the connectpath, and then does an early return.
*
* 2). Checks if an incoming filename contains an
- * SMB-layer @GMT- style timestamp.
+ * SMB-layer @GMT- style timestamp.
* If so, it strips the timestamp, and returns
* both the timestamp and the stripped path
* (making it cwd-relative).
goto fail;
}
- ZERO_STRUCT(converted_fname);
- converted_fname.base_name = converted;
+ converted_fname = (struct smb_filename) {
+ .base_name = converted,
+ };
ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
insertlen = talloc_get_size(insert)-1;
/*
- * Note: We deliberatly don't expensively initialize the
+ * Note: We deliberately 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
memcpy(converted, path, pathlen+1);
converted[pathlen+insertlen] = '\0';
- ZERO_STRUCT(converted_fname);
- converted_fname.base_name = converted;
+ converted_fname = (struct smb_filename) {
+ .base_name = converted,
+ };
for (i = num_slashes-1; i>=0; i--) {
int ret;
return ret;
}
-static int shadow_copy2_openat(vfs_handle_struct *handle,
- const struct files_struct *dirfsp,
- const struct smb_filename *smb_fname_in,
- struct files_struct *fsp,
- int flags,
- mode_t mode)
+static int shadow_copy2_fstatat(
+ struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname_in,
+ SMB_STRUCT_STAT *sbuf,
+ int flags)
{
+ struct shadow_copy2_private *priv = NULL;
struct smb_filename *smb_fname = NULL;
time_t timestamp = 0;
char *stripped = NULL;
- bool is_converted = false;
- int saved_errno = 0;
+ char *abspath = NULL;
+ bool converted = false;
int ret;
bool ok;
+ SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+ return -1);
+
smb_fname = full_path_from_dirfsp_atname(talloc_tos(),
dirfsp,
smb_fname_in);
smb_fname,
×tamp,
&stripped,
- &is_converted);
+ &converted);
if (!ok) {
return -1;
}
if (timestamp == 0) {
- if (is_converted) {
+ TALLOC_FREE(stripped);
+ ret = SMB_VFS_NEXT_FSTATAT(
+ handle, dirfsp, smb_fname_in, sbuf, flags);
+ if (ret != 0) {
+ return ret;
+ }
+ if (!converted) {
+ return 0;
+ }
+
+ abspath = make_path_absolute(
+ talloc_tos(), priv, smb_fname->base_name);
+ if (abspath == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ convert_sbuf(handle, abspath, sbuf);
+ TALLOC_FREE(abspath);
+ return 0;
+ }
+
+ smb_fname->base_name = shadow_copy2_convert(
+ smb_fname, handle, stripped, timestamp);
+ TALLOC_FREE(stripped);
+ if (smb_fname->base_name == NULL) {
+ TALLOC_FREE(smb_fname);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_FSTATAT(handle,
+ dirfsp,
+ smb_fname,
+ sbuf,
+ flags);
+ if (ret != 0) {
+ int saved_errno = errno;
+ TALLOC_FREE(smb_fname);
+ errno = saved_errno;
+ return -1;
+ }
+
+ abspath = make_path_absolute(
+ talloc_tos(), priv, smb_fname->base_name);
+ if (abspath == NULL) {
+ TALLOC_FREE(smb_fname);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ convert_sbuf(handle, abspath, sbuf);
+ TALLOC_FREE(abspath);
+
+ TALLOC_FREE(smb_fname);
+
+ return 0;
+}
+
+static struct smb_filename *shadow_copy2_openat_name(
+ TALLOC_CTX *mem_ctx,
+ const struct files_struct *dirfsp,
+ const struct files_struct *fsp,
+ const struct smb_filename *smb_fname_in)
+{
+ struct smb_filename *result = NULL;
+
+ if (fsp->base_fsp != NULL) {
+ struct smb_filename *base_fname = fsp->base_fsp->fsp_name;
+
+ if (smb_fname_in->base_name[0] == '/') {
/*
- * Just pave over the user requested mode and use
- * O_RDONLY. Later attempts by the client to write on
- * the handle will fail in the pwrite() syscall with
- * EINVAL which we carefully map to EROFS. In sum, this
- * matches Windows behaviour.
+ * Special-case stream names from streams_depot
*/
- flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
+ result = cp_smb_filename(mem_ctx, smb_fname_in);
+ } else {
+
+ SMB_ASSERT(is_named_stream(smb_fname_in));
+
+ result = synthetic_smb_fname(mem_ctx,
+ base_fname->base_name,
+ smb_fname_in->stream_name,
+ &smb_fname_in->st,
+ smb_fname_in->twrp,
+ smb_fname_in->flags);
}
+ } else {
+ result = full_path_from_dirfsp_atname(
+ mem_ctx, dirfsp, smb_fname_in);
+ }
+
+ return result;
+}
+
+static int shadow_copy2_openat(vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname_in,
+ struct files_struct *fsp,
+ const struct vfs_open_how *_how)
+{
+ struct vfs_open_how how = *_how;
+ struct smb_filename *smb_fname = NULL;
+ time_t timestamp = 0;
+ char *stripped = NULL;
+ int saved_errno = 0;
+ int ret;
+ bool ok;
+
+ if (how.resolve != 0) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ smb_fname = shadow_copy2_openat_name(
+ talloc_tos(), dirfsp, fsp, smb_fname_in);
+ if (smb_fname == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ok = shadow_copy2_strip_snapshot(talloc_tos(),
+ handle,
+ smb_fname,
+ ×tamp,
+ &stripped);
+ if (!ok) {
+ TALLOC_FREE(smb_fname);
+ return -1;
+ }
+ if (timestamp == 0) {
+ TALLOC_FREE(stripped);
+ TALLOC_FREE(smb_fname);
return SMB_VFS_NEXT_OPENAT(handle,
dirfsp,
smb_fname_in,
fsp,
- flags,
- mode);
+ &how);
}
smb_fname->base_name = shadow_copy2_convert(smb_fname,
handle,
stripped,
timestamp);
- TALLOC_FREE(stripped);
if (smb_fname->base_name == NULL) {
+ int err = errno;
+ TALLOC_FREE(stripped);
TALLOC_FREE(smb_fname);
- errno = ENOMEM;
+ errno = err;
return -1;
}
-
- /*
- * Just pave over the user requested mode and use O_RDONLY. Later
- * attempts by the client to write on the handle will fail in the
- * pwrite() syscall with EINVAL which we carefully map to EROFS. In sum,
- * this matches Windows behaviour.
- */
- flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
+ TALLOC_FREE(stripped);
ret = SMB_VFS_NEXT_OPENAT(handle,
dirfsp,
smb_fname,
fsp,
- flags,
- mode);
+ &how);
if (ret == -1) {
saved_errno = errno;
}
* otherwise return NULL.
*/
static char *have_snapdir(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
const char *path)
{
struct smb_filename smb_fname;
SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
return NULL);
- ZERO_STRUCT(smb_fname);
- smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
- path, priv->config->snapdir);
+ smb_fname = (struct smb_filename) {
+ .base_name = talloc_asprintf(
+ mem_ctx, "%s/%s", path, priv->config->snapdir),
+ };
if (smb_fname.base_name == NULL) {
return NULL;
}
config = priv->config;
/*
- * If the non-snapdisrseverywhere mode, we should not search!
+ * If the non-snapdirseverywhere mode, we should not search!
*/
if (!config->snapdirseverywhere) {
return config->snapshot_basepath;
return NULL;
}
- snapdir = have_snapdir(handle, path);
+ snapdir = have_snapdir(handle, talloc_tos(), path);
if (snapdir != NULL) {
TALLOC_FREE(path);
return snapdir;
p[0] = '\0';
- snapdir = have_snapdir(handle, path);
+ snapdir = have_snapdir(handle, talloc_tos(), path);
if (snapdir != NULL) {
TALLOC_FREE(path);
return snapdir;
const char *name,
char *gmt, size_t gmt_len)
{
- struct tm timestamp;
+ struct tm timestamp = { .tm_sec = 0, };
time_t timestamp_t;
unsigned long int timestamp_long;
const char *fmt;
}
}
- ZERO_STRUCT(timestamp);
if (config->use_sscanf) {
if (sscanf(name, fmt, ×tamp_long) != 1) {
DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
}
DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
fmt, name));
-
+
if (config->use_localtime) {
timestamp.tm_isdst = -1;
timestamp_t = mktime(×tamp);
struct shadow_copy2_private *priv = NULL;
struct shadow_copy2_snapentry *tmpentry = NULL;
bool get_snaplist = false;
- int open_flags = O_RDONLY;
+ struct vfs_open_how how = {
+ .flags = O_RDONLY, .mode = 0,
+ };
int fd;
int ret = -1;
NTSTATUS status;
}
#ifdef O_DIRECTORY
- open_flags |= O_DIRECTORY;
+ how.flags |= O_DIRECTORY;
#endif
fd = SMB_VFS_NEXT_OPENAT(handle,
fspcwd,
snapdir_smb_fname,
dirfsp,
- open_flags,
- 0);
+ &how);
if (fd == -1) {
DBG_WARNING("SMB_VFS_NEXT_OPEN failed for '%s'"
" - %s\n", snapdir, strerror(errno));
time(&(priv->snaps->fetch_time));
}
- while ((d = SMB_VFS_NEXT_READDIR(handle, dirfsp, p, NULL))) {
+ while ((d = SMB_VFS_NEXT_READDIR(handle, dirfsp, p))) {
char snapshot[GMT_NAME_LEN+1];
SHADOW_COPY_LABEL *tlabels;
full_fname,
×tamp,
NULL)) {
+ TALLOC_FREE(full_fname);
return -1;
}
TALLOC_FREE(full_fname);
return status;
}
-static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
- const struct smb_filename *fname,
- const char *name,
- TALLOC_CTX *mem_ctx,
- char **found_name)
-{
- struct shadow_copy2_private *priv = NULL;
- struct shadow_copy2_config *config = NULL;
- time_t timestamp = 0;
- char *stripped = NULL;
- ssize_t ret;
- int saved_errno = 0;
- char *conv;
- struct smb_filename conv_fname;
-
- SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
- return -1);
- config = priv->config;
-
- DBG_DEBUG("Path=[%s] name=[%s]\n", smb_fname_str_dbg(fname), name);
-
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
- ×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, fname, name,
- mem_ctx, found_name);
- }
-
- /*
- * Note that stripped may be an empty string "" if path was ".". As
- * shadow_copy2_convert() combines "" with the shadow-copy tree connect
- * root fullpath and get_real_filename_full_scan() has an explicit check
- * for "" this works.
- */
- DBG_DEBUG("stripped [%s]\n", stripped);
-
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- if (conv == NULL) {
- if (!config->snapdirseverywhere) {
- DBG_DEBUG("shadow_copy2_convert [%s] failed\n", stripped);
- return -1;
- }
-
- /*
- * We're called in the path traversal loop in unix_convert()
- * walking down the directory hierarchy. shadow_copy2_convert()
- * will fail if the snapshot directory is futher down in the
- * hierachy. Set conv to the original stripped path and try to
- * look it up in the filesystem with
- * SMB_VFS_NEXT_GET_REAL_FILENAME() or
- * get_real_filename_full_scan().
- */
- DBG_DEBUG("Use stripped [%s] as conv\n", stripped);
- conv = talloc_strdup(talloc_tos(), stripped);
- if (conv == NULL) {
- TALLOC_FREE(stripped);
- return -1;
- }
- }
-
- conv_fname = (struct smb_filename) {
- .base_name = conv,
- };
-
- 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_fname, name,
- mem_ctx, found_name);
- DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
- if (ret == 0) {
- return 0;
- }
- if (errno != EOPNOTSUPP) {
- TALLOC_FREE(conv);
- errno = EOPNOTSUPP;
- return -1;
- }
-
- ret = get_real_filename_full_scan(handle->conn,
- conv,
- name,
- false,
- mem_ctx,
- found_name);
- if (ret != 0) {
- saved_errno = errno;
- DBG_DEBUG("Scan [%s] for [%s] failed\n",
- conv, name);
- errno = saved_errno;
- return -1;
- }
-
- DBG_DEBUG("Scan [%s] for [%s] returned [%s]\n",
- conv, name, *found_name);
-
- TALLOC_FREE(conv);
- return 0;
-}
-
-static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname_in)
+static const char *shadow_copy2_connectpath(
+ struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname_in)
{
time_t timestamp = 0;
char *stripped = NULL;
char *tmp = NULL;
const char *fname = smb_fname_in->base_name;
+ const struct smb_filename *full = NULL;
struct smb_filename smb_fname = {0};
struct smb_filename *result_fname = NULL;
char *result = NULL;
return priv->shadow_connectpath;
}
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, smb_fname_in,
+ full = full_path_from_dirfsp_atname(
+ talloc_tos(), dirfsp, smb_fname_in);
+ if (full == NULL) {
+ return NULL;
+ }
+
+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, full,
×tamp, &stripped)) {
goto done;
}
if (timestamp == 0) {
- return SMB_VFS_NEXT_CONNECTPATH(handle, smb_fname_in);
+ return SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname_in);
}
tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
const char *snapsharepath = NULL;
const char *mount_point;
- DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
- (unsigned)handle->conn->cnum,
- handle->conn->connectpath));
+ DBG_DEBUG("cnum[%" PRIu32 "], connectpath[%s]\n",
+ handle->conn->cnum,
+ handle->conn->connectpath);
ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
if (ret < 0) {
"shadow", "mountpoint", NULL);
if (mount_point != NULL) {
if (mount_point[0] != '/') {
- DEBUG(1, (__location__ " Warning: 'mountpoint' is "
- "relative ('%s'), but it has to be an "
- "absolute path. Ignoring provided value.\n",
- mount_point));
+ DBG_WARNING("Warning: 'mountpoint' is relative "
+ "('%s'), but it has to be an absolute "
+ "path. Ignoring provided value.\n",
+ mount_point);
mount_point = NULL;
} else {
char *p;
if (mount_point != NULL) {
config->mount_point = talloc_strdup(config, mount_point);
if (config->mount_point == NULL) {
- DEBUG(0, (__location__ " talloc_strdup() failed\n"));
+ DBG_ERR("talloc_strdup() failed\n");
return -1;
}
} else {
if (basedir != NULL) {
if (basedir[0] != '/') {
- DEBUG(1, (__location__ " Warning: 'basedir' is "
- "relative ('%s'), but it has to be an "
- "absolute path. Disabling basedir.\n",
- basedir));
+ DBG_WARNING("Warning: 'basedir' is "
+ "relative ('%s'), but it has to be an "
+ "absolute path. Disabling basedir.\n",
+ basedir);
basedir = NULL;
} else {
char *p;
}
if (config->snapdirseverywhere && basedir != NULL) {
- DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
- "with 'snapdirseverywhere'. Disabling basedir.\n"));
+ DBG_WARNING("Warning: 'basedir' is incompatible "
+ "with 'snapdirseverywhere'. Disabling basedir.\n");
basedir = NULL;
}
if (config->snapdir[0] == '/') {
config->snapdir_absolute = true;
- if (config->snapdirseverywhere == true) {
- DEBUG(1, (__location__ " Warning: An absolute snapdir "
- "is incompatible with 'snapdirseverywhere', "
- "setting 'snapdirseverywhere' to false.\n"));
+ if (config->snapdirseverywhere) {
+ DBG_WARNING("Warning: An absolute snapdir is "
+ "incompatible with 'snapdirseverywhere', "
+ "setting 'snapdirseverywhere' to "
+ "false.\n");
config->snapdirseverywhere = false;
}
- if (config->crossmountpoints == true) {
- DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
- "is not supported with an absolute snapdir. "
- "Disabling it.\n"));
+ if (config->crossmountpoints) {
+ DBG_WARNING("Warning: 'crossmountpoints' is not "
+ "supported with an absolute snapdir. "
+ "Disabling it.\n");
config->crossmountpoints = false;
}
.stat_fn = shadow_copy2_stat,
.lstat_fn = shadow_copy2_lstat,
.fstat_fn = shadow_copy2_fstat,
+ .fstatat_fn = shadow_copy2_fstatat,
.openat_fn = shadow_copy2_openat,
.unlinkat_fn = shadow_copy2_unlinkat,
.fchmod_fn = shadow_copy2_fchmod,
.realpath_fn = shadow_copy2_realpath,
.get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
.mkdirat_fn = shadow_copy2_mkdirat,
- .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
- .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
.fsetxattr_fn = shadow_copy2_fsetxattr,
.fchflags_fn = shadow_copy2_fchflags,
- .get_real_filename_fn = shadow_copy2_get_real_filename,
.pwrite_fn = shadow_copy2_pwrite,
.pwrite_send_fn = shadow_copy2_pwrite_send,
.pwrite_recv_fn = shadow_copy2_pwrite_recv,