*/
/*
- * 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.
#include "include/ntioctl.h"
#include "util_tdb.h"
#include "lib/util_path.h"
+#include "libcli/security/security.h"
+#include "lib/util/tevent_unix.h"
struct shadow_copy2_config {
char *gmt_format;
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
* snapshot at the given timestamp of the input path.
*
* In the case of a parallel snapdir (specified with an
- * absolute path), this is the inital portion of the
+ * absolute path), this is the initial portion of the
* local path of any snapshot file. The complete path is
* obtained by appending the portion of the file's path
* below the share root's mountpoint.
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).
*/
-static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
+static bool _shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
struct vfs_handle_struct *handle,
- const char *orig_name,
+ const struct smb_filename *smb_fname,
time_t *ptimestamp,
char **pstripped,
- char **psnappath)
+ char **psnappath,
+ bool *_already_converted,
+ const char *function)
{
- struct tm tm;
- time_t timestamp = 0;
- const char *p;
- char *q;
char *stripped = NULL;
- size_t rest_len, dst_len;
struct shadow_copy2_private *priv;
- ptrdiff_t len_before_gmt;
- const char *name = orig_name;
char *abs_path = NULL;
bool ret = true;
bool already_converted = false;
SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
return false);
- DEBUG(10, (__location__ ": enter path '%s'\n", name));
+ DBG_DEBUG("[from %s()] Path '%s'\n",
+ function, smb_fname_str_dbg(smb_fname));
- abs_path = make_path_absolute(mem_ctx, priv, name);
+ if (_already_converted != NULL) {
+ *_already_converted = false;
+ }
+
+ abs_path = make_path_absolute(mem_ctx, priv, smb_fname->base_name);
if (abs_path == NULL) {
ret = false;
goto out;
}
- name = abs_path;
- DEBUG(10, (__location__ ": abs path '%s'\n", name));
+ DBG_DEBUG("abs path '%s'\n", abs_path);
err = check_for_converted_path(mem_ctx,
handle,
}
if (already_converted) {
+ if (_already_converted != NULL) {
+ *_already_converted = true;
+ }
goto out;
}
- /*
- * From here we're only looking to strip an
- * SMB-layer @GMT- token.
- */
-
- p = strstr_m(name, "@GMT-");
- if (p == NULL) {
- DEBUG(11, ("@GMT not found\n"));
- goto out;
- }
- 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]));
+ if (smb_fname->twrp == 0) {
goto out;
}
- len_before_gmt = p - name;
-
- q = strptime(p, GMT_FORMAT, &tm);
- if (q == NULL) {
- DEBUG(10, ("strptime failed\n"));
- goto out;
- }
- tm.tm_isdst = -1;
- timestamp = timegm(&tm);
- if (timestamp == (time_t)-1) {
- DEBUG(10, ("timestamp==-1\n"));
- goto out;
- }
- 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) {
- if (len_before_gmt > 1) {
- /*
- * There is a path (and not only a slash)
- * before the @GMT-. Remove the trailing
- * slash character.
- */
- len_before_gmt -= 1;
- }
- stripped = talloc_strndup(mem_ctx, name,
- len_before_gmt);
- if (stripped == NULL) {
- ret = false;
- goto out;
- }
- if (orig_name[0] != '/') {
- if (make_relative_path(priv->shadow_cwd,
- stripped) == false) {
- DEBUG(10, (__location__ ": path '%s' "
- "doesn't start with cwd '%s'\n",
- stripped, priv->shadow_cwd));
- ret = false;
- errno = ENOENT;
- goto out;
- }
- }
- *pstripped = stripped;
- }
- *ptimestamp = timestamp;
- goto out;
- }
- if (q[0] != '/') {
- /*
- * 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 out;
+ if (ptimestamp != NULL) {
+ *ptimestamp = nt_time_to_unix(smb_fname->twrp);
}
- q += 1;
-
- rest_len = strlen(q);
- dst_len = len_before_gmt + rest_len;
if (pstripped != NULL) {
- stripped = talloc_array(mem_ctx, char, dst_len+1);
+ stripped = talloc_strdup(mem_ctx, abs_path);
if (stripped == NULL) {
ret = false;
goto out;
}
- if (p > name) {
- memcpy(stripped, name, len_before_gmt);
- }
- if (rest_len > 0) {
- memcpy(stripped + len_before_gmt, q, rest_len);
- }
- stripped[dst_len] = '\0';
- if (orig_name[0] != '/') {
- if (make_relative_path(priv->shadow_cwd,
- stripped) == false) {
- DEBUG(10, (__location__ ": path '%s' "
+
+ if (smb_fname->base_name[0] != '/') {
+ ret = make_relative_path(priv->shadow_cwd, stripped);
+ if (!ret) {
+ DBG_DEBUG("Path '%s' "
"doesn't start with cwd '%s'\n",
- stripped, priv->shadow_cwd));
+ stripped, priv->shadow_cwd);
ret = false;
errno = ENOENT;
goto out;
}
*pstripped = stripped;
}
- *ptimestamp = timestamp;
+
ret = true;
out:
return ret;
}
-static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
+#define shadow_copy2_strip_snapshot_internal(mem_ctx, handle, orig_name, \
+ ptimestamp, pstripped, psnappath, _already_converted) \
+ _shadow_copy2_strip_snapshot_internal((mem_ctx), (handle), (orig_name), \
+ (ptimestamp), (pstripped), (psnappath), (_already_converted), \
+ __FUNCTION__)
+
+static bool _shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
+ struct vfs_handle_struct *handle,
+ const struct smb_filename *orig_name,
+ time_t *ptimestamp,
+ char **pstripped,
+ const char *function)
+{
+ return _shadow_copy2_strip_snapshot_internal(mem_ctx,
+ handle,
+ orig_name,
+ ptimestamp,
+ pstripped,
+ NULL,
+ NULL,
+ function);
+}
+
+#define shadow_copy2_strip_snapshot(mem_ctx, handle, orig_name, \
+ ptimestamp, pstripped) \
+ _shadow_copy2_strip_snapshot((mem_ctx), (handle), (orig_name), \
+ (ptimestamp), (pstripped), __FUNCTION__)
+
+static bool _shadow_copy2_strip_snapshot_converted(TALLOC_CTX *mem_ctx,
struct vfs_handle_struct *handle,
- const char *orig_name,
+ const struct smb_filename *orig_name,
time_t *ptimestamp,
- char **pstripped)
+ char **pstripped,
+ bool *is_converted,
+ const char *function)
{
- return shadow_copy2_strip_snapshot_internal(mem_ctx,
+ return _shadow_copy2_strip_snapshot_internal(mem_ctx,
handle,
orig_name,
ptimestamp,
pstripped,
- NULL);
+ NULL,
+ is_converted,
+ function);
}
+#define shadow_copy2_strip_snapshot_converted(mem_ctx, handle, orig_name, \
+ ptimestamp, pstripped, is_converted) \
+ _shadow_copy2_strip_snapshot_converted((mem_ctx), (handle), (orig_name), \
+ (ptimestamp), (pstripped), (is_converted), __FUNCTION__)
+
static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
vfs_handle_struct *handle)
{
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;
if (errno == ENOTDIR) {
/*
* This is a valid condition: We appended the
- * .snaphots/@GMT.. to a file name. Just try
+ * .snapshots/@GMT.. to a file name. Just try
* with the upper levels.
*/
continue;
return);
if (priv->config->fixinodes) {
- /* some snapshot systems, like GPFS, return the name
+ /* some snapshot systems, like GPFS, return the same
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.
}
}
-static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- const char *mask,
- uint32_t attr)
-{
- time_t timestamp = 0;
- char *stripped = NULL;
- DIR *ret;
- int saved_errno = 0;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
-
- if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return NULL;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_OPENDIR(handle, smb_fname, mask, attr);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
- return NULL;
- }
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- return NULL;
- }
- ret = SMB_VFS_NEXT_OPENDIR(handle, conv_smb_fname, mask, attr);
- if (ret == NULL) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv);
- TALLOC_FREE(conv_smb_fname);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
-}
-
-static int shadow_copy2_rename(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname_src,
- const struct smb_filename *smb_fname_dst)
+static int shadow_copy2_renameat(vfs_handle_struct *handle,
+ files_struct *srcfsp,
+ const struct smb_filename *smb_fname_src,
+ files_struct *dstfsp,
+ const struct smb_filename *smb_fname_dst)
{
time_t timestamp_src = 0;
time_t timestamp_dst = 0;
char *snappath_dst = NULL;
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
- smb_fname_src->base_name,
- ×tamp_src, NULL, &snappath_src)) {
+ smb_fname_src,
+ ×tamp_src, NULL, &snappath_src,
+ NULL)) {
return -1;
}
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
- smb_fname_dst->base_name,
- ×tamp_dst, NULL, &snappath_dst)) {
+ smb_fname_dst,
+ ×tamp_dst, NULL, &snappath_dst,
+ NULL)) {
return -1;
}
if (timestamp_src != 0) {
errno = EROFS;
return -1;
}
- return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
+ return SMB_VFS_NEXT_RENAMEAT(handle,
+ srcfsp,
+ smb_fname_src,
+ dstfsp,
+ smb_fname_dst);
}
-static int shadow_copy2_symlink(vfs_handle_struct *handle,
- const char *link_contents,
+static int shadow_copy2_symlinkat(vfs_handle_struct *handle,
+ const struct smb_filename *link_contents,
+ struct files_struct *dirfsp,
const struct smb_filename *new_smb_fname)
{
time_t timestamp_old = 0;
link_contents,
×tamp_old,
NULL,
- &snappath_old)) {
+ &snappath_old,
+ NULL)) {
return -1;
}
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
handle,
- new_smb_fname->base_name,
+ new_smb_fname,
×tamp_new,
NULL,
- &snappath_new)) {
+ &snappath_new,
+ NULL)) {
return -1;
}
if ((timestamp_old != 0) || (timestamp_new != 0)) {
errno = EROFS;
return -1;
}
- return SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname);
+ return SMB_VFS_NEXT_SYMLINKAT(handle,
+ link_contents,
+ dirfsp,
+ new_smb_fname);
}
-static int shadow_copy2_link(vfs_handle_struct *handle,
+static int shadow_copy2_linkat(vfs_handle_struct *handle,
+ files_struct *srcfsp,
const struct smb_filename *old_smb_fname,
- const struct smb_filename *new_smb_fname)
+ files_struct *dstfsp,
+ const struct smb_filename *new_smb_fname,
+ int flags)
{
time_t timestamp_old = 0;
time_t timestamp_new = 0;
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
handle,
- old_smb_fname->base_name,
+ old_smb_fname,
×tamp_old,
NULL,
- &snappath_old)) {
+ &snappath_old,
+ NULL)) {
return -1;
}
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
handle,
- new_smb_fname->base_name,
+ new_smb_fname,
×tamp_new,
NULL,
- &snappath_new)) {
+ &snappath_new,
+ NULL)) {
return -1;
}
if ((timestamp_old != 0) || (timestamp_new != 0)) {
errno = EROFS;
return -1;
}
- return SMB_VFS_NEXT_LINK(handle, old_smb_fname, new_smb_fname);
+ return SMB_VFS_NEXT_LINKAT(handle,
+ srcfsp,
+ old_smb_fname,
+ dstfsp,
+ new_smb_fname,
+ flags);
}
static int shadow_copy2_stat(vfs_handle_struct *handle,
struct smb_filename *smb_fname)
{
+ struct shadow_copy2_private *priv = NULL;
time_t timestamp = 0;
char *stripped = NULL;
+ bool converted = false;
+ char *abspath = NULL;
char *tmp;
- int saved_errno = 0;
- int ret;
+ int ret = 0;
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- smb_fname->base_name,
- ×tamp, &stripped)) {
+ SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+ return -1);
+
+ if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+ handle,
+ smb_fname,
+ ×tamp,
+ &stripped,
+ &converted)) {
return -1;
}
if (timestamp == 0) {
- return SMB_VFS_NEXT_STAT(handle, smb_fname);
+ TALLOC_FREE(stripped);
+ ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+ if (ret != 0) {
+ return ret;
+ }
+ if (!converted) {
+ return 0;
+ }
+
+ abspath = make_path_absolute(talloc_tos(),
+ priv,
+ smb_fname->base_name);
+ if (abspath == NULL) {
+ return -1;
+ }
+
+ convert_sbuf(handle, abspath, &smb_fname->st);
+ TALLOC_FREE(abspath);
+ return 0;
}
tmp = smb_fname->base_name;
}
ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
- if (ret == -1) {
- saved_errno = errno;
+ if (ret != 0) {
+ goto out;
+ }
+
+ abspath = make_path_absolute(talloc_tos(),
+ priv,
+ smb_fname->base_name);
+ if (abspath == NULL) {
+ ret = -1;
+ goto out;
}
+ convert_sbuf(handle, abspath, &smb_fname->st);
+ TALLOC_FREE(abspath);
+
+out:
TALLOC_FREE(smb_fname->base_name);
smb_fname->base_name = tmp;
- if (ret == 0) {
- convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
- }
- if (saved_errno != 0) {
- errno = saved_errno;
- }
return ret;
}
static int shadow_copy2_lstat(vfs_handle_struct *handle,
struct smb_filename *smb_fname)
{
+ struct shadow_copy2_private *priv = NULL;
time_t timestamp = 0;
char *stripped = NULL;
+ bool converted = false;
+ char *abspath = NULL;
char *tmp;
- int saved_errno = 0;
- int ret;
+ int ret = 0;
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- smb_fname->base_name,
- ×tamp, &stripped)) {
+ SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+ return -1);
+
+ if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+ handle,
+ smb_fname,
+ ×tamp,
+ &stripped,
+ &converted)) {
return -1;
}
if (timestamp == 0) {
- return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+ TALLOC_FREE(stripped);
+ ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+ if (ret != 0) {
+ return ret;
+ }
+ if (!converted) {
+ return 0;
+ }
+
+ abspath = make_path_absolute(talloc_tos(),
+ priv,
+ smb_fname->base_name);
+ if (abspath == NULL) {
+ return -1;
+ }
+
+ convert_sbuf(handle, abspath, &smb_fname->st);
+ TALLOC_FREE(abspath);
+ return 0;
}
tmp = smb_fname->base_name;
}
ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
- if (ret == -1) {
- saved_errno = errno;
+ if (ret != 0) {
+ goto out;
+ }
+
+ abspath = make_path_absolute(talloc_tos(),
+ priv,
+ smb_fname->base_name);
+ if (abspath == NULL) {
+ ret = -1;
+ goto out;
}
+ convert_sbuf(handle, abspath, &smb_fname->st);
+ TALLOC_FREE(abspath);
+
+out:
TALLOC_FREE(smb_fname->base_name);
smb_fname->base_name = tmp;
- if (ret == 0) {
- convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
- }
- if (saved_errno != 0) {
- errno = saved_errno;
- }
return ret;
}
static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
+ struct shadow_copy2_private *priv = NULL;
time_t timestamp = 0;
+ struct smb_filename *orig_smb_fname = NULL;
+ struct smb_filename vss_smb_fname;
+ struct smb_filename *orig_base_smb_fname = NULL;
+ struct smb_filename vss_base_smb_fname;
+ char *stripped = NULL;
+ char *abspath = NULL;
+ bool converted = false;
+ bool ok;
int ret;
- ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
- if (ret == -1) {
- return ret;
+ SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+ return -1);
+
+ ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
+ handle,
+ fsp->fsp_name,
+ ×tamp,
+ &stripped,
+ &converted);
+ if (!ok) {
+ return -1;
}
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- fsp->fsp_name->base_name,
- ×tamp, NULL)) {
+
+ if (timestamp == 0) {
+ TALLOC_FREE(stripped);
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ if (ret != 0) {
+ return ret;
+ }
+ if (!converted) {
+ return 0;
+ }
+
+ abspath = make_path_absolute(talloc_tos(),
+ priv,
+ fsp->fsp_name->base_name);
+ if (abspath == NULL) {
+ return -1;
+ }
+
+ convert_sbuf(handle, abspath, sbuf);
+ TALLOC_FREE(abspath);
return 0;
}
- if (timestamp != 0) {
- convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
+
+ vss_smb_fname = *fsp->fsp_name;
+ vss_smb_fname.base_name = shadow_copy2_convert(talloc_tos(),
+ handle,
+ stripped,
+ timestamp);
+ TALLOC_FREE(stripped);
+ if (vss_smb_fname.base_name == NULL) {
+ return -1;
}
- return 0;
+
+ orig_smb_fname = fsp->fsp_name;
+ fsp->fsp_name = &vss_smb_fname;
+
+ if (fsp_is_alternate_stream(fsp)) {
+ vss_base_smb_fname = *fsp->base_fsp->fsp_name;
+ vss_base_smb_fname.base_name = vss_smb_fname.base_name;
+ orig_base_smb_fname = fsp->base_fsp->fsp_name;
+ fsp->base_fsp->fsp_name = &vss_base_smb_fname;
+ }
+
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ if (ret != 0) {
+ goto out;
+ }
+
+ abspath = make_path_absolute(talloc_tos(),
+ priv,
+ fsp->fsp_name->base_name);
+ if (abspath == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ convert_sbuf(handle, abspath, sbuf);
+ TALLOC_FREE(abspath);
+
+out:
+ fsp->fsp_name = orig_smb_fname;
+ if (fsp_is_alternate_stream(fsp)) {
+ fsp->base_fsp->fsp_name = orig_base_smb_fname;
+ }
+
+ return ret;
}
-static int shadow_copy2_open(vfs_handle_struct *handle,
- struct smb_filename *smb_fname, 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;
- char *tmp;
- int saved_errno = 0;
+ char *abspath = NULL;
+ bool converted = false;
int ret;
+ bool ok;
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- smb_fname->base_name,
- ×tamp, &stripped)) {
+ 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);
+ if (smb_fname == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
+ handle,
+ smb_fname,
+ ×tamp,
+ &stripped,
+ &converted);
+ if (!ok) {
return -1;
}
if (timestamp == 0) {
- return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+ 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;
}
- tmp = smb_fname->base_name;
smb_fname->base_name = shadow_copy2_convert(
- talloc_tos(), handle, stripped, timestamp);
+ smb_fname, handle, stripped, timestamp);
TALLOC_FREE(stripped);
-
if (smb_fname->base_name == NULL) {
- smb_fname->base_name = tmp;
+ TALLOC_FREE(smb_fname);
+ errno = ENOMEM;
return -1;
}
- ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
- if (ret == -1) {
- saved_errno = errno;
+ 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;
}
- TALLOC_FREE(smb_fname->base_name);
- smb_fname->base_name = tmp;
+ abspath = make_path_absolute(
+ talloc_tos(), priv, smb_fname->base_name);
+ if (abspath == NULL) {
+ TALLOC_FREE(smb_fname);
+ errno = ENOMEM;
+ return -1;
+ }
- if (saved_errno != 0) {
- errno = saved_errno;
+ 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] == '/') {
+ /*
+ * Special-case stream names from streams_depot
+ */
+ 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 ret;
+
+ return result;
}
-static int shadow_copy2_unlink(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
+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;
- struct smb_filename *conv;
+ bool ok;
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- smb_fname->base_name,
- ×tamp, &stripped)) {
+ if (how.resolve != 0) {
+ errno = ENOSYS;
return -1;
}
- if (timestamp == 0) {
- return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
- }
- conv = cp_smb_filename(talloc_tos(), smb_fname);
- if (conv == NULL) {
+
+ smb_fname = shadow_copy2_openat_name(
+ talloc_tos(), dirfsp, fsp, smb_fname_in);
+ if (smb_fname == NULL) {
errno = ENOMEM;
return -1;
}
- conv->base_name = shadow_copy2_convert(
- conv, handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv->base_name == NULL) {
+
+ 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,
+ &how);
+ }
+
+ smb_fname->base_name = shadow_copy2_convert(smb_fname,
+ handle,
+ stripped,
+ timestamp);
+ if (smb_fname->base_name == NULL) {
+ int err = errno;
+ TALLOC_FREE(stripped);
+ TALLOC_FREE(smb_fname);
+ errno = err;
return -1;
}
- ret = SMB_VFS_NEXT_UNLINK(handle, conv);
+ TALLOC_FREE(stripped);
+
+ ret = SMB_VFS_NEXT_OPENAT(handle,
+ dirfsp,
+ smb_fname,
+ fsp,
+ &how);
if (ret == -1) {
saved_errno = errno;
}
- TALLOC_FREE(conv);
+
+ TALLOC_FREE(smb_fname);
+
if (saved_errno != 0) {
errno = saved_errno;
}
return ret;
}
-static int shadow_copy2_chmod(vfs_handle_struct *handle,
+static int shadow_copy2_unlinkat(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
const struct smb_filename *smb_fname,
- mode_t mode)
+ int flags)
{
time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- char *conv = NULL;
- struct smb_filename *conv_smb_fname;
- if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- TALLOC_FREE(stripped);
- return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
+ smb_fname,
+ ×tamp, NULL)) {
return -1;
}
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- errno = ENOMEM;
+ if (timestamp != 0) {
+ errno = EROFS;
return -1;
}
-
- ret = SMB_VFS_NEXT_CHMOD(handle, conv_smb_fname, mode);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv);
- TALLOC_FREE(conv_smb_fname);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
+ return SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ flags);
}
-static int shadow_copy2_chown(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- uid_t uid,
- gid_t gid)
+static int shadow_copy2_fchmod(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ mode_t mode)
{
time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- char *conv = NULL;
- struct smb_filename *conv_smb_fname = NULL;
+ const struct smb_filename *smb_fname = NULL;
+ smb_fname = fsp->fsp_name;
if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
+ handle,
+ smb_fname,
+ ×tamp,
+ NULL)) {
return -1;
}
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- errno = ENOMEM;
+ if (timestamp != 0) {
+ errno = EROFS;
return -1;
}
- ret = SMB_VFS_NEXT_CHOWN(handle, conv_smb_fname, uid, gid);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv);
- TALLOC_FREE(conv_smb_fname);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
+ return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
}
static void store_cwd_data(vfs_handle_struct *handle,
}
TALLOC_FREE(priv->shadow_connectpath);
if (connectpath) {
- DBG_DEBUG("shadow conectpath = %s\n", connectpath);
+ DBG_DEBUG("shadow connectpath = %s\n", connectpath);
priv->shadow_connectpath = talloc_strdup(priv, connectpath);
if (priv->shadow_connectpath == NULL) {
smb_panic("talloc failed\n");
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
handle,
- smb_fname->base_name,
+ smb_fname,
×tamp,
&stripped,
- &snappath)) {
+ &snappath,
+ NULL)) {
return -1;
}
if (stripped != NULL) {
conv,
NULL,
NULL,
+ 0,
smb_fname->flags);
} else {
conv_smb_fname = cp_smb_filename(talloc_tos(), smb_fname);
return ret;
}
-static int shadow_copy2_ntimes(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- struct smb_file_time *ft)
+static int shadow_copy2_fntimes(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct smb_file_time *ft)
{
time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- struct smb_filename *conv;
- if (!shadow_copy2_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);
- }
- conv = cp_smb_filename(talloc_tos(), smb_fname);
- if (conv == NULL) {
- errno = ENOMEM;
+ if (!shadow_copy2_strip_snapshot(talloc_tos(),
+ handle,
+ fsp->fsp_name,
+ ×tamp,
+ NULL)) {
return -1;
}
- conv->base_name = shadow_copy2_convert(
- conv, handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv->base_name == NULL) {
+ if (timestamp != 0) {
+ errno = EROFS;
return -1;
}
- ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
+ return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
}
-static int shadow_copy2_readlink(vfs_handle_struct *handle,
+static int shadow_copy2_readlinkat(vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
const struct smb_filename *smb_fname,
char *buf,
size_t bufsiz)
char *stripped = NULL;
int saved_errno = 0;
int ret;
+ struct smb_filename *full_fname = NULL;
struct smb_filename *conv = NULL;
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- smb_fname->base_name,
- ×tamp, &stripped)) {
+ full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ dirfsp,
+ smb_fname);
+ if (full_fname == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (!shadow_copy2_strip_snapshot(talloc_tos(),
+ handle,
+ full_fname,
+ ×tamp,
+ &stripped)) {
+ TALLOC_FREE(full_fname);
return -1;
}
+
if (timestamp == 0) {
- return SMB_VFS_NEXT_READLINK(handle, smb_fname, buf, bufsiz);
+ TALLOC_FREE(full_fname);
+ TALLOC_FREE(stripped);
+ return SMB_VFS_NEXT_READLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ buf,
+ bufsiz);
}
- conv = cp_smb_filename(talloc_tos(), smb_fname);
+ conv = cp_smb_filename(talloc_tos(), full_fname);
if (conv == NULL) {
+ TALLOC_FREE(full_fname);
TALLOC_FREE(stripped);
errno = ENOMEM;
return -1;
}
+ TALLOC_FREE(full_fname);
conv->base_name = shadow_copy2_convert(
conv, handle, stripped, timestamp);
TALLOC_FREE(stripped);
if (conv->base_name == NULL) {
return -1;
}
- ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
+ ret = SMB_VFS_NEXT_READLINKAT(handle,
+ handle->conn->cwd_fsp,
+ conv,
+ buf,
+ bufsiz);
if (ret == -1) {
saved_errno = errno;
}
return ret;
}
-static int shadow_copy2_mknod(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- mode_t mode,
- SMB_DEV_T dev)
+static int shadow_copy2_mknodat(vfs_handle_struct *handle,
+ files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ mode_t mode,
+ SMB_DEV_T dev)
{
time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- struct smb_filename *conv = NULL;
if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- smb_fname->base_name,
- ×tamp, &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_MKNOD(handle, smb_fname, mode, dev);
- }
- conv = cp_smb_filename(talloc_tos(), smb_fname);
- if (conv == NULL) {
- errno = ENOMEM;
+ smb_fname,
+ ×tamp, NULL)) {
return -1;
}
- conv->base_name = shadow_copy2_convert(
- conv, handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv->base_name == NULL) {
+ if (timestamp != 0) {
+ errno = EROFS;
return -1;
}
- ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
+ return SMB_VFS_NEXT_MKNODAT(handle,
+ dirfsp,
+ smb_fname,
+ mode,
+ dev);
}
static struct smb_filename *shadow_copy2_realpath(vfs_handle_struct *handle,
int saved_errno = 0;
if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- smb_fname->base_name,
+ smb_fname,
×tamp, &stripped)) {
goto done;
}
* 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;
}
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).
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_copy_data *shadow_copy2_data,
bool labels)
{
- DIR *p;
+ DIR *p = NULL;
const char *snapdir;
struct smb_filename *snapdir_smb_fname = NULL;
+ struct files_struct *dirfsp = NULL;
+ struct files_struct *fspcwd = NULL;
struct dirent *d;
TALLOC_CTX *tmp_ctx = talloc_stackframe();
struct shadow_copy2_private *priv = NULL;
struct shadow_copy2_snapentry *tmpentry = NULL;
bool get_snaplist = false;
- bool access_granted = false;
+ struct vfs_open_how how = {
+ .flags = O_RDONLY, .mode = 0,
+ };
+ int fd;
int ret = -1;
+ NTSTATUS status;
+ int saved_errno = 0;
snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
if (snapdir == NULL) {
goto done;
}
- access_granted = check_access_snapdir(handle, snapdir);
- if (!access_granted) {
- DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
- errno = EACCES;
- goto done;
- }
-
snapdir_smb_fname = synthetic_smb_fname(talloc_tos(),
snapdir,
NULL,
NULL,
+ 0,
fsp->fsp_name->flags);
if (snapdir_smb_fname == NULL) {
errno = ENOMEM;
goto done;
}
- p = SMB_VFS_NEXT_OPENDIR(handle, snapdir_smb_fname, NULL, 0);
+ status = create_internal_dirfsp(handle->conn,
+ snapdir_smb_fname,
+ &dirfsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("create_internal_dir_fsp() failed for '%s'"
+ " - %s\n", snapdir, nt_errstr(status));
+ errno = ENOSYS;
+ goto done;
+ }
+
+ status = vfs_at_fspcwd(talloc_tos(), handle->conn, &fspcwd);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = ENOMEM;
+ goto done;
+ }
+
+#ifdef O_DIRECTORY
+ how.flags |= O_DIRECTORY;
+#endif
+
+ fd = SMB_VFS_NEXT_OPENAT(handle,
+ fspcwd,
+ snapdir_smb_fname,
+ dirfsp,
+ &how);
+ if (fd == -1) {
+ DBG_WARNING("SMB_VFS_NEXT_OPEN failed for '%s'"
+ " - %s\n", snapdir, strerror(errno));
+ errno = ENOSYS;
+ goto done;
+ }
+ fsp_set_fd(dirfsp, fd);
+
+ /* Now we have the handle, check access here. */
+ status = smbd_check_access_rights_fsp(fspcwd,
+ dirfsp,
+ false,
+ SEC_DIR_LIST);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("user does not have list permission "
+ "on snapdir %s\n",
+ fsp_str_dbg(dirfsp));
+ errno = EACCES;
+ goto done;
+ }
+ p = SMB_VFS_NEXT_FDOPENDIR(handle, dirfsp, NULL, 0);
if (!p) {
- DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
- " - %s\n", snapdir, strerror(errno)));
+ DBG_NOTICE("shadow_copy2: SMB_VFS_NEXT_FDOPENDIR() failed for '%s'"
+ " - %s\n", snapdir, strerror(errno));
errno = ENOSYS;
goto done;
}
time(&(priv->snaps->fetch_time));
}
- while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
+ while ((d = SMB_VFS_NEXT_READDIR(handle, dirfsp, p))) {
char snapshot[GMT_NAME_LEN+1];
SHADOW_COPY_LABEL *tlabels;
shadow_copy2_data->num_volumes+1);
if (tlabels == NULL) {
DEBUG(0,("shadow_copy2: out of memory\n"));
- SMB_VFS_NEXT_CLOSEDIR(handle, p);
goto done;
}
shadow_copy2_data->labels = tlabels;
}
- SMB_VFS_NEXT_CLOSEDIR(handle,p);
-
shadow_copy2_sort_data(handle, shadow_copy2_data);
ret = 0;
done:
+ if (ret != 0) {
+ saved_errno = errno;
+ }
+ TALLOC_FREE(fspcwd );
+ if (p != NULL) {
+ SMB_VFS_NEXT_CLOSEDIR(handle, p);
+ p = NULL;
+ if (dirfsp != NULL) {
+ /*
+ * VFS_CLOSEDIR implicitly
+ * closed the associated fd.
+ */
+ fsp_set_fd(dirfsp, -1);
+ }
+ }
+ if (dirfsp != NULL) {
+ fd_close(dirfsp);
+ file_free(NULL, dirfsp);
+ }
TALLOC_FREE(tmp_ctx);
+ if (saved_errno != 0) {
+ errno = saved_errno;
+ }
return ret;
}
-static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
- struct files_struct *fsp,
- uint32_t security_info,
- TALLOC_CTX *mem_ctx,
- struct security_descriptor **ppdesc)
+static int shadow_copy2_mkdirat(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ mode_t mode)
{
+ struct smb_filename *full_fname = NULL;
time_t timestamp = 0;
- char *stripped = NULL;
- NTSTATUS status;
- char *conv;
- struct smb_filename *smb_fname = NULL;
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- fsp->fsp_name->base_name,
- ×tamp, &stripped)) {
- return map_nt_error_from_unix(errno);
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
- mem_ctx,
- ppdesc);
+ full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ dirfsp,
+ smb_fname);
+ if (full_fname == NULL) {
+ errno = ENOMEM;
+ return -1;
}
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
- return map_nt_error_from_unix(errno);
+
+ if (!shadow_copy2_strip_snapshot(talloc_tos(),
+ handle,
+ full_fname,
+ ×tamp,
+ NULL)) {
+ TALLOC_FREE(full_fname);
+ return -1;
}
- smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- fsp->fsp_name->flags);
- if (smb_fname == NULL) {
- TALLOC_FREE(conv);
- return NT_STATUS_NO_MEMORY;
+ TALLOC_FREE(full_fname);
+ if (timestamp != 0) {
+ errno = EROFS;
+ return -1;
}
-
- status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
- mem_ctx, ppdesc);
- TALLOC_FREE(conv);
- TALLOC_FREE(smb_fname);
- return status;
-}
-
-static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- uint32_t security_info,
- TALLOC_CTX *mem_ctx,
- struct security_descriptor **ppdesc)
-{
- time_t timestamp = 0;
- char *stripped = NULL;
- NTSTATUS status;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
-
- if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return map_nt_error_from_unix(errno);
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
- mem_ctx, ppdesc);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
- return map_nt_error_from_unix(errno);
- }
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- return NT_STATUS_NO_MEMORY;
- }
- status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv_smb_fname, security_info,
- mem_ctx, ppdesc);
- TALLOC_FREE(conv);
- TALLOC_FREE(conv_smb_fname);
- return status;
+ return SMB_VFS_NEXT_MKDIRAT(handle,
+ dirfsp,
+ smb_fname,
+ mode);
}
-static int shadow_copy2_mkdir(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- mode_t mode)
+static int shadow_copy2_fchflags(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ unsigned int flags)
{
time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
if (!shadow_copy2_strip_snapshot(talloc_tos(),
handle,
- smb_fname->base_name,
+ fsp->fsp_name,
×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
+ NULL)) {
return -1;
}
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
+ if (timestamp != 0) {
+ errno = EROFS;
return -1;
}
- ret = SMB_VFS_NEXT_MKDIR(handle, conv_smb_fname, mode);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv);
- TALLOC_FREE(conv_smb_fname);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
+ return SMB_VFS_NEXT_FCHFLAGS(handle, fsp, flags);
}
-static int shadow_copy2_rmdir(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
+static int shadow_copy2_fsetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *aname, const void *value,
+ size_t size, int flags)
{
time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
+ const struct smb_filename *smb_fname = NULL;
+ smb_fname = fsp->fsp_name;
if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
+ handle,
+ smb_fname,
+ ×tamp,
+ NULL)) {
return -1;
}
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
+ if (timestamp != 0) {
+ errno = EROFS;
return -1;
}
- ret = SMB_VFS_NEXT_RMDIR(handle, conv_smb_fname);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv_smb_fname);
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
+ return SMB_VFS_NEXT_FSETXATTR(handle, fsp,
+ aname, value, size, flags);
}
-static int shadow_copy2_chflags(vfs_handle_struct *handle,
+static NTSTATUS shadow_copy2_create_dfs_pathat(struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
const struct smb_filename *smb_fname,
- unsigned int flags)
+ const struct referral *reflist,
+ size_t referral_count)
{
time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
if (!shadow_copy2_strip_snapshot(talloc_tos(),
handle,
- smb_fname->base_name,
+ smb_fname,
×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
- return -1;
- }
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- return -1;
- }
- ret = SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
- if (ret == -1) {
- saved_errno = errno;
+ NULL)) {
+ return NT_STATUS_NO_MEMORY;
}
- TALLOC_FREE(conv_smb_fname);
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
+ if (timestamp != 0) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
- return ret;
+ return SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
+ dirfsp,
+ smb_fname,
+ reflist,
+ referral_count);
}
-static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- const char *aname,
- void *value,
- size_t size)
+static NTSTATUS shadow_copy2_read_dfs_pathat(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct *dirfsp,
+ struct smb_filename *smb_fname,
+ struct referral **ppreflist,
+ size_t *preferral_count)
{
time_t timestamp = 0;
char *stripped = NULL;
- ssize_t ret;
- int saved_errno = 0;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
-
- if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_GETXATTR(handle, smb_fname, aname, value,
- size);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
- return -1;
- }
-
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- return -1;
- }
+ struct smb_filename *full_fname = NULL;
+ struct smb_filename *conv = NULL;
+ NTSTATUS status;
- ret = SMB_VFS_NEXT_GETXATTR(handle, conv_smb_fname, aname, value, size);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv_smb_fname);
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
+ full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ dirfsp,
+ smb_fname);
+ if (full_fname == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- return ret;
-}
-static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- char *list, size_t size)
-{
- time_t timestamp = 0;
- char *stripped = NULL;
- ssize_t ret;
- int saved_errno = 0;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
-
- if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return -1;
+ if (!shadow_copy2_strip_snapshot(mem_ctx,
+ handle,
+ full_fname,
+ ×tamp,
+ &stripped)) {
+ TALLOC_FREE(full_fname);
+ return NT_STATUS_NO_MEMORY;
}
if (timestamp == 0) {
- return SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
- if (conv == NULL) {
- return -1;
- }
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- return -1;
- }
- ret = SMB_VFS_NEXT_LISTXATTR(handle, conv_smb_fname, list, size);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv_smb_fname);
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
+ TALLOC_FREE(full_fname);
+ TALLOC_FREE(stripped);
+ return SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
+ mem_ctx,
+ dirfsp,
+ smb_fname,
+ ppreflist,
+ preferral_count);
}
- return ret;
-}
-
-static int shadow_copy2_removexattr(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- const char *aname)
-{
- time_t timestamp = 0;
- char *stripped = NULL;
- int saved_errno = 0;
- int ret;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
- if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, aname);
- }
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
- TALLOC_FREE(stripped);
+ conv = cp_smb_filename(mem_ctx, full_fname);
if (conv == NULL) {
- return -1;
- }
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
- TALLOC_FREE(conv);
- return -1;
- }
- ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv_smb_fname, aname);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv_smb_fname);
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
-}
-
-static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- const char *aname, const void *value,
- size_t size, int flags)
-{
- time_t timestamp = 0;
- char *stripped = NULL;
- ssize_t ret;
- int saved_errno = 0;
- char *conv;
- struct smb_filename *conv_smb_fname = NULL;
-
- if (!shadow_copy2_strip_snapshot(talloc_tos(),
- handle,
- smb_fname->base_name,
- ×tamp,
- &stripped)) {
- return -1;
- }
- if (timestamp == 0) {
- return SMB_VFS_NEXT_SETXATTR(handle, smb_fname,
- aname, value, size, flags);
+ TALLOC_FREE(full_fname);
+ TALLOC_FREE(stripped);
+ return NT_STATUS_NO_MEMORY;
}
- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
+ TALLOC_FREE(full_fname);
+ conv->base_name = shadow_copy2_convert(conv,
+ handle,
+ stripped,
+ timestamp);
TALLOC_FREE(stripped);
- if (conv == NULL) {
- return -1;
- }
- conv_smb_fname = synthetic_smb_fname(talloc_tos(),
- conv,
- NULL,
- NULL,
- smb_fname->flags);
- if (conv_smb_fname == NULL) {
+ if (conv->base_name == NULL) {
TALLOC_FREE(conv);
- return -1;
- }
- ret = SMB_VFS_NEXT_SETXATTR(handle, conv_smb_fname,
- aname, value, size, flags);
- if (ret == -1) {
- saved_errno = errno;
- }
- TALLOC_FREE(conv_smb_fname);
- TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
+ return NT_STATUS_NO_MEMORY;
}
- return ret;
-}
-static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
- const char *path,
- const char *name,
- TALLOC_CTX *mem_ctx,
- char **found_name)
-{
- time_t timestamp = 0;
- char *stripped = NULL;
- ssize_t ret;
- int saved_errno = 0;
- char *conv;
-
- DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
- "name=[%s]\n", path, name));
+ status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
+ mem_ctx,
+ handle->conn->cwd_fsp,
+ conv,
+ ppreflist,
+ preferral_count);
- 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);
- }
- 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));
- if (ret == -1) {
- saved_errno = errno;
+ if (NT_STATUS_IS_OK(status)) {
+ /* Return any stat(2) info. */
+ smb_fname->st = conv->st;
}
+
TALLOC_FREE(conv);
- if (saved_errno != 0) {
- errno = saved_errno;
- }
- return ret;
+ return status;
}
-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, fname,
+ 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,
return result;
}
+static NTSTATUS shadow_copy2_parent_pathname(vfs_handle_struct *handle,
+ TALLOC_CTX *ctx,
+ const struct smb_filename *smb_fname_in,
+ struct smb_filename **parent_dir_out,
+ struct smb_filename **atname_out)
+{
+ time_t timestamp = 0;
+ char *stripped = NULL;
+ char *converted_name = NULL;
+ struct smb_filename *smb_fname = NULL;
+ struct smb_filename *parent = NULL;
+ struct smb_filename *atname = NULL;
+ struct shadow_copy2_private *priv = NULL;
+ bool ok = false;
+ bool is_converted = false;
+ NTSTATUS status = NT_STATUS_OK;
+ TALLOC_CTX *frame = NULL;
+
+ SMB_VFS_HANDLE_GET_DATA(handle,
+ priv,
+ struct shadow_copy2_private,
+ return NT_STATUS_INTERNAL_ERROR);
+
+ frame = talloc_stackframe();
+
+ smb_fname = cp_smb_filename(frame, smb_fname_in);
+ if (smb_fname == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ /* First, call the default PARENT_PATHNAME. */
+ status = SMB_VFS_NEXT_PARENT_PATHNAME(handle,
+ frame,
+ smb_fname,
+ &parent,
+ &atname);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ if (parent->twrp == 0) {
+ /*
+ * Parent is not a snapshot path, return
+ * the regular result.
+ */
+ status = NT_STATUS_OK;
+ goto out;
+ }
+
+ /* See if we can find a snapshot for the parent. */
+ ok = shadow_copy2_strip_snapshot_converted(frame,
+ handle,
+ parent,
+ ×tamp,
+ &stripped,
+ &is_converted);
+ if (!ok) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ if (is_converted) {
+ /*
+ * Already found snapshot for parent so wipe
+ * out the twrp.
+ */
+ parent->twrp = 0;
+ goto out;
+ }
+
+ converted_name = shadow_copy2_convert(frame,
+ handle,
+ stripped,
+ timestamp);
+
+ if (converted_name == NULL) {
+ /*
+ * Can't find snapshot for parent so wipe
+ * out the twrp.
+ */
+ parent->twrp = 0;
+ }
+
+ out:
+
+ *parent_dir_out = talloc_move(ctx, &parent);
+ if (atname_out != NULL) {
+ *atname_out = talloc_move(*parent_dir_out, &atname);
+ }
+
+ fail:
+
+ TALLOC_FREE(frame);
+ return status;
+}
+
static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
const struct smb_filename *smb_fname,
uint64_t *bsize,
if (!shadow_copy2_strip_snapshot(talloc_tos(),
handle,
- smb_fname->base_name,
+ smb_fname,
×tamp,
&stripped)) {
return (uint64_t)-1;
conv,
NULL,
NULL,
+ 0,
smb_fname->flags);
if (conv_smb_fname == NULL) {
TALLOC_FREE(conv);
if (!shadow_copy2_strip_snapshot(talloc_tos(),
handle,
- smb_fname->base_name,
+ smb_fname,
×tamp,
&stripped)) {
return -1;
conv,
NULL,
NULL,
+ 0,
smb_fname->flags);
if (conv_smb_fname == NULL) {
TALLOC_FREE(conv);
return ret;
}
+static ssize_t shadow_copy2_pwrite(vfs_handle_struct *handle,
+ files_struct *fsp,
+ const void *data,
+ size_t n,
+ off_t offset)
+{
+ ssize_t nwritten;
+
+ nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ if (nwritten == -1) {
+ if (errno == EBADF && fsp->fsp_flags.can_write) {
+ errno = EROFS;
+ }
+ }
+
+ return nwritten;
+}
+
+struct shadow_copy2_pwrite_state {
+ vfs_handle_struct *handle;
+ files_struct *fsp;
+ ssize_t ret;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void shadow_copy2_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *shadow_copy2_pwrite_send(
+ struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev, struct files_struct *fsp,
+ const void *data, size_t n, off_t offset)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct shadow_copy2_pwrite_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct shadow_copy2_pwrite_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->handle = handle;
+ state->fsp = fsp;
+
+ subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
+ ev,
+ handle,
+ fsp,
+ data,
+ n,
+ offset);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, shadow_copy2_pwrite_done, req);
+
+ return req;
+}
+
+static void shadow_copy2_pwrite_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct shadow_copy2_pwrite_state *state = tevent_req_data(
+ req, struct shadow_copy2_pwrite_state);
+
+ state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+ if (state->ret == -1) {
+ tevent_req_error(req, state->vfs_aio_state.error);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static ssize_t shadow_copy2_pwrite_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct shadow_copy2_pwrite_state *state = tevent_req_data(
+ req, struct shadow_copy2_pwrite_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ if ((vfs_aio_state->error == EBADF) &&
+ state->fsp->fsp_flags.can_write)
+ {
+ vfs_aio_state->error = EROFS;
+ errno = EROFS;
+ }
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->ret;
+}
+
static int shadow_copy2_connect(struct vfs_handle_struct *handle,
const char *service, const char *user)
{
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;
}
static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
.connect_fn = shadow_copy2_connect,
- .opendir_fn = shadow_copy2_opendir,
.disk_free_fn = shadow_copy2_disk_free,
.get_quota_fn = shadow_copy2_get_quota,
- .rename_fn = shadow_copy2_rename,
- .link_fn = shadow_copy2_link,
- .symlink_fn = shadow_copy2_symlink,
+ .create_dfs_pathat_fn = shadow_copy2_create_dfs_pathat,
+ .read_dfs_pathat_fn = shadow_copy2_read_dfs_pathat,
+ .renameat_fn = shadow_copy2_renameat,
+ .linkat_fn = shadow_copy2_linkat,
+ .symlinkat_fn = shadow_copy2_symlinkat,
.stat_fn = shadow_copy2_stat,
.lstat_fn = shadow_copy2_lstat,
.fstat_fn = shadow_copy2_fstat,
- .open_fn = shadow_copy2_open,
- .unlink_fn = shadow_copy2_unlink,
- .chmod_fn = shadow_copy2_chmod,
- .chown_fn = shadow_copy2_chown,
+ .fstatat_fn = shadow_copy2_fstatat,
+ .openat_fn = shadow_copy2_openat,
+ .unlinkat_fn = shadow_copy2_unlinkat,
+ .fchmod_fn = shadow_copy2_fchmod,
.chdir_fn = shadow_copy2_chdir,
- .ntimes_fn = shadow_copy2_ntimes,
- .readlink_fn = shadow_copy2_readlink,
- .mknod_fn = shadow_copy2_mknod,
+ .fntimes_fn = shadow_copy2_fntimes,
+ .readlinkat_fn = shadow_copy2_readlinkat,
+ .mknodat_fn = shadow_copy2_mknodat,
.realpath_fn = shadow_copy2_realpath,
- .get_nt_acl_fn = shadow_copy2_get_nt_acl,
- .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
.get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
- .mkdir_fn = shadow_copy2_mkdir,
- .rmdir_fn = shadow_copy2_rmdir,
- .getxattr_fn = shadow_copy2_getxattr,
- .listxattr_fn = shadow_copy2_listxattr,
- .removexattr_fn = shadow_copy2_removexattr,
- .setxattr_fn = shadow_copy2_setxattr,
- .chflags_fn = shadow_copy2_chflags,
- .get_real_filename_fn = shadow_copy2_get_real_filename,
+ .mkdirat_fn = shadow_copy2_mkdirat,
+ .fsetxattr_fn = shadow_copy2_fsetxattr,
+ .fchflags_fn = shadow_copy2_fchflags,
+ .pwrite_fn = shadow_copy2_pwrite,
+ .pwrite_send_fn = shadow_copy2_pwrite_send,
+ .pwrite_recv_fn = shadow_copy2_pwrite_recv,
.connectpath_fn = shadow_copy2_connectpath,
+ .parent_pathname_fn = shadow_copy2_parent_pathname,
};
static_decl_vfs;