diff options
Diffstat (limited to 'source3/modules/vfs_streams_depot.c')
-rw-r--r-- | source3/modules/vfs_streams_depot.c | 123 |
1 files changed, 115 insertions, 8 deletions
diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index d8c476f96f..69d34940fd 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -67,10 +67,15 @@ static uint32_t hash_fn(DATA_BLOB key) #define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS" -static bool file_is_valid(vfs_handle_struct *handle, const char *path) +static bool file_is_valid(vfs_handle_struct *handle, const char *path, + bool check_valid) { char buf; + if (!check_valid) { + return true; + } + DEBUG(10, ("file_is_valid (%s) called\n", path)); if (SMB_VFS_NEXT_GETXATTR(handle, path, SAMBA_XATTR_MARKER, @@ -87,11 +92,16 @@ static bool file_is_valid(vfs_handle_struct *handle, const char *path) return true; } -static bool mark_file_valid(vfs_handle_struct *handle, const char *path) +static bool mark_file_valid(vfs_handle_struct *handle, const char *path, + bool check_valid) { char buf = '1'; int ret; + if (!check_valid) { + return true; + } + DEBUG(10, ("marking file %s as valid\n", path)); ret = SMB_VFS_NEXT_SETXATTR(handle, path, SAMBA_XATTR_MARKER, @@ -116,10 +126,22 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, char *id_hex; struct file_id id; uint8 id_buf[16]; + bool check_valid; + const char *rootdir; + + check_valid = lp_parm_bool(SNUM(handle->conn), + "streams_depot", "check_valid", true); + + tmp = talloc_asprintf(talloc_tos(), "%s/.streams", handle->conn->connectpath); - const char *rootdir = lp_parm_const_string( + if (tmp == NULL) { + errno = ENOMEM; + goto fail; + } + + rootdir = lp_parm_const_string( SNUM(handle->conn), "streams_depot", "directory", - handle->conn->connectpath); + tmp); if (base_sbuf == NULL) { if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) { @@ -141,7 +163,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, first = hash & 0xff; second = (hash >> 8) & 0xff; - id_hex = hex_encode(talloc_tos(), id_buf, sizeof(id_buf)); + id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf)); if (id_hex == NULL) { errno = ENOMEM; @@ -166,7 +188,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, goto fail; } - if (file_is_valid(handle, base_path)) { + if (file_is_valid(handle, base_path, check_valid)) { return result; } @@ -236,7 +258,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path, goto fail; } - if (!mark_file_valid(handle, base_path)) { + if (!mark_file_valid(handle, base_path, check_valid)) { goto fail; } @@ -262,6 +284,11 @@ static char *stream_name(vfs_handle_struct *handle, const char *fname, goto fail; } + /* if it's the ::$DATA stream just return the base file name */ + if (!sname) { + return base; + } + dirname = stream_dir(handle, base, NULL, create_dir); if (dirname == NULL) { @@ -401,6 +428,7 @@ static int streams_depot_open(vfs_handle_struct *handle, const char *fname, { TALLOC_CTX *frame; char *base = NULL; + char *sname = NULL; SMB_STRUCT_STAT base_sbuf; char *stream_fname; int ret = -1; @@ -412,11 +440,16 @@ static int streams_depot_open(vfs_handle_struct *handle, const char *fname, frame = talloc_stackframe(); if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname, - &base, NULL))) { + &base, &sname))) { errno = ENOMEM; goto done; } + if (!sname) { + ret = SMB_VFS_NEXT_OPEN(handle, base, fsp, flags, mode); + goto done; + } + ret = SMB_VFS_NEXT_STAT(handle, base, &base_sbuf); if (ret == -1) { @@ -478,6 +511,78 @@ static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname) return SMB_VFS_NEXT_UNLINK(handle, fname); } +static int streams_depot_rename(vfs_handle_struct *handle, + const char *oldname, + const char *newname) +{ + TALLOC_CTX *frame = NULL; + int ret = -1; + bool old_is_stream; + bool new_is_stream; + char *obase = NULL; + char *osname = NULL; + char *nbase = NULL; + char *nsname = NULL; + char *ostream_fname = NULL; + char *nstream_fname = NULL; + + DEBUG(10, ("streams_depot_rename called for %s => %s\n", + oldname, newname)); + + old_is_stream = is_ntfs_stream_name(oldname); + new_is_stream = is_ntfs_stream_name(newname); + + if (!old_is_stream && !new_is_stream) { + return SMB_VFS_NEXT_RENAME(handle, oldname, newname); + } + + if (!(old_is_stream && new_is_stream)) { + errno = ENOSYS; + return -1; + } + + frame = talloc_stackframe(); + + if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), oldname, + &obase, &osname))) { + errno = ENOMEM; + goto done; + } + + if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), oldname, + &nbase, &nsname))) { + errno = ENOMEM; + goto done; + } + + /* for now don't allow renames from or to the default stream */ + if (!osname || !nsname) { + errno = ENOSYS; + goto done; + } + + if (StrCaseCmp(obase, nbase) != 0) { + errno = ENOSYS; + goto done; + } + + ostream_fname = stream_name(handle, oldname, false); + if (ostream_fname == NULL) { + return -1; + } + + nstream_fname = stream_name(handle, newname, false); + if (nstream_fname == NULL) { + return -1; + } + + ret = SMB_VFS_NEXT_RENAME(handle, ostream_fname, nstream_fname); + +done: + TALLOC_FREE(frame); + return ret; +} + static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams, struct stream_struct **streams, const char *name, SMB_OFF_T size, @@ -628,6 +733,8 @@ static vfs_op_tuple streams_depot_ops[] = { SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(streams_depot_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(streams_depot_rename), SMB_VFS_OP_RENAME, + SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(streams_depot_streaminfo), SMB_VFS_OP_STREAMINFO, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} |