X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fmodules%2Fvfs_streams_depot.c;h=b74e774f08cbd45282e45b3b89ae3db4e7f7fe99;hb=987ebb15918a10fd17bf784a054499111d4ad4e5;hp=ba3b180244082753f5c058b67b1c089044dfd68d;hpb=431e63cd8bfff6f67b6e6595ee5a054877709c0d;p=samba.git diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index ba3b1802440..b74e774f08c 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -18,6 +18,8 @@ */ #include "includes.h" +#include "smbd/smbd.h" +#include "system/filesys.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS @@ -65,17 +67,10 @@ static uint32_t hash_fn(DATA_BLOB key) * an option to put in a special ACL entry for a non-existing group. */ -#define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS" - -static bool file_is_valid(vfs_handle_struct *handle, const char *path, - bool check_valid) +static bool file_is_valid(vfs_handle_struct *handle, const char *path) { char buf; - if (!check_valid) { - return true; - } - DEBUG(10, ("file_is_valid (%s) called\n", path)); if (SMB_VFS_GETXATTR(handle->conn, path, SAMBA_XATTR_MARKER, @@ -92,16 +87,11 @@ 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, - bool check_valid) +static bool mark_file_valid(vfs_handle_struct *handle, const char *path) { char buf = '1'; int ret; - if (!check_valid) { - return true; - } - DEBUG(10, ("marking file %s as valid\n", path)); ret = SMB_VFS_SETXATTR(handle->conn, path, SAMBA_XATTR_MARKER, @@ -134,12 +124,11 @@ static char *stream_dir(vfs_handle_struct *handle, uint8 id_buf[16]; bool check_valid; const char *rootdir; - NTSTATUS status; check_valid = lp_parm_bool(SNUM(handle->conn), "streams_depot", "check_valid", true); - tmp = talloc_asprintf(talloc_tos(), "%s/.streams", handle->conn->connectpath); + tmp = talloc_asprintf(talloc_tos(), "%s/.streams", handle->conn->cwd); if (tmp == NULL) { errno = ENOMEM; @@ -152,14 +141,12 @@ static char *stream_dir(vfs_handle_struct *handle, /* Stat the base file if it hasn't already been done. */ if (base_sbuf == NULL) { - struct smb_filename *smb_fname_base = NULL; + struct smb_filename *smb_fname_base; - status = create_synthetic_smb_fname(talloc_tos(), - smb_fname->base_name, - NULL, NULL, - &smb_fname_base); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); + smb_fname_base = synthetic_smb_fname( + talloc_tos(), smb_fname->base_name, NULL, NULL); + if (smb_fname_base == NULL) { + errno = ENOMEM; goto fail; } if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) { @@ -198,58 +185,75 @@ static char *stream_dir(vfs_handle_struct *handle, return NULL; } - status = create_synthetic_smb_fname(talloc_tos(), result, NULL, NULL, - &smb_fname_hash); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); + smb_fname_hash = synthetic_smb_fname(talloc_tos(), result, NULL, NULL); + if (smb_fname_hash == NULL) { + errno = ENOMEM; goto fail; } if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) { struct smb_filename *smb_fname_new = NULL; char *newname; + bool delete_lost; if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) { errno = EINVAL; goto fail; } - if (file_is_valid(handle, smb_fname->base_name, check_valid)) { + if (!check_valid || + file_is_valid(handle, smb_fname->base_name)) { return result; } /* * Someone has recreated a file under an existing inode - * without deleting the streams directory. For now, just move - * it away. + * without deleting the streams directory. + * Move it away or remove if streams_depot:delete_lost is set. */ again: - newname = talloc_asprintf(talloc_tos(), "lost-%lu", random()); - if (newname == NULL) { - errno = ENOMEM; - goto fail; - } + delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot", + "delete_lost", false); + + if (delete_lost) { + DEBUG(3, ("Someone has recreated a file under an " + "existing inode. Removing: %s\n", + smb_fname_hash->base_name)); + recursive_rmdir(talloc_tos(), handle->conn, + smb_fname_hash); + SMB_VFS_NEXT_RMDIR(handle, smb_fname_hash->base_name); + } else { + newname = talloc_asprintf(talloc_tos(), "lost-%lu", + random()); + DEBUG(3, ("Someone has recreated a file under an " + "existing inode. Renaming: %s to: %s\n", + smb_fname_hash->base_name, + newname)); + if (newname == NULL) { + errno = ENOMEM; + goto fail; + } - status = create_synthetic_smb_fname(talloc_tos(), newname, - NULL, NULL, - &smb_fname_new); - TALLOC_FREE(newname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto fail; - } + smb_fname_new = synthetic_smb_fname( + talloc_tos(), newname, NULL, NULL); + TALLOC_FREE(newname); + if (smb_fname_new == NULL) { + errno = ENOMEM; + goto fail; + } - if (SMB_VFS_NEXT_RENAME(handle, smb_fname_hash, - smb_fname_new) == -1) { - TALLOC_FREE(smb_fname_new); - if ((errno == EEXIST) || (errno == ENOTEMPTY)) { - goto again; + if (SMB_VFS_NEXT_RENAME(handle, smb_fname_hash, + smb_fname_new) == -1) { + TALLOC_FREE(smb_fname_new); + if ((errno == EEXIST) || (errno == ENOTEMPTY)) { + goto again; + } + goto fail; } - goto fail; - } - TALLOC_FREE(smb_fname_new); + TALLOC_FREE(smb_fname_new); + } } if (!create_it) { @@ -294,7 +298,7 @@ static char *stream_dir(vfs_handle_struct *handle, goto fail; } - if (!mark_file_valid(handle, smb_fname->base_name, check_valid)) { + if (check_valid && !mark_file_valid(handle, smb_fname->base_name)) { goto fail; } @@ -321,6 +325,14 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle, *smb_fname_out = NULL; + stype = strchr_m(smb_fname->stream_name + 1, ':'); + + if (stype) { + if (strcasecmp_m(stype, ":$DATA") != 0) { + return NT_STATUS_INVALID_PARAMETER; + } + } + dirname = stream_dir(handle, smb_fname, NULL, create_dir); if (dirname == NULL) { @@ -328,8 +340,6 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle, goto fail; } - stype = strchr_m(smb_fname->stream_name + 1, ':'); - stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, smb_fname->stream_name); @@ -348,7 +358,10 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle, } } else { /* Normalize the stream type to upercase. */ - strupper_m(strrchr_m(stream_fname, ':') + 1); + if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } } DEBUG(10, ("stream filename = %s\n", stream_fname)); @@ -377,8 +390,9 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, void *private_data) { char *dirname; - SMB_STRUCT_DIR *dirhandle = NULL; - char *dirent; + DIR *dirhandle = NULL; + const char *dirent = NULL; + char *talloced = NULL; dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st, false); @@ -402,17 +416,21 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, return map_nt_error_from_unix(errno); } - while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL)) != NULL) { + while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL, + &talloced)) != NULL) { if (ISDOT(dirent) || ISDOTDOT(dirent)) { + TALLOC_FREE(talloced); continue; } DEBUG(10, ("walk_streams: dirent=%s\n", dirent)); if (!fn(dirname, dirent, private_data)) { + TALLOC_FREE(talloced); break; } + TALLOC_FREE(talloced); } SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle); @@ -646,13 +664,58 @@ static int streams_depot_unlink(vfs_handle_struct *handle, return ret; } +static int streams_depot_rmdir(vfs_handle_struct *handle, const char *path) +{ + struct smb_filename *smb_fname_base = NULL; + NTSTATUS status; + int ret = -1; + + DEBUG(10, ("streams_depot_rmdir called for %s\n", path)); + + /* + * We potentially need to delete the per-inode streams directory + */ + + status = create_synthetic_smb_fname(talloc_tos(), path, + NULL, NULL, &smb_fname_base); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + if (lp_posix_pathnames()) { + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base); + } else { + ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base); + } + + if (ret == -1) { + TALLOC_FREE(smb_fname_base); + return -1; + } + + if (smb_fname_base->st.st_ex_nlink == 2) { + char *dirname = stream_dir(handle, smb_fname_base, + &smb_fname_base->st, false); + + if (dirname != NULL) { + SMB_VFS_NEXT_RMDIR(handle, dirname); + } + TALLOC_FREE(dirname); + } + + ret = SMB_VFS_NEXT_RMDIR(handle, path); + + TALLOC_FREE(smb_fname_base); + return ret; +} + static int streams_depot_rename(vfs_handle_struct *handle, const struct smb_filename *smb_fname_src, const struct smb_filename *smb_fname_dst) { struct smb_filename *smb_fname_src_stream = NULL; struct smb_filename *smb_fname_dst_stream = NULL; - struct smb_filename *smb_fname_dst_mod = NULL; bool src_is_stream, dst_is_stream; NTSTATUS status; int ret = -1; @@ -683,23 +746,7 @@ static int streams_depot_rename(vfs_handle_struct *handle, goto done; } - /* - * Handle passing in a stream name without the base file. This is - * exercised by the NTRENAME streams rename path. - */ - if (StrCaseCmp(smb_fname_dst->base_name, "./") == 0) { - status = create_synthetic_smb_fname(talloc_tos(), - smb_fname_src->base_name, - smb_fname_dst->stream_name, - NULL, &smb_fname_dst_mod); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto done; - } - } - - status = stream_smb_fname(handle, (smb_fname_dst_mod ? - smb_fname_dst_mod : smb_fname_dst), + status = stream_smb_fname(handle, smb_fname_dst, &smb_fname_dst_stream, false); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); @@ -712,18 +759,17 @@ static int streams_depot_rename(vfs_handle_struct *handle, done: TALLOC_FREE(smb_fname_src_stream); TALLOC_FREE(smb_fname_dst_stream); - TALLOC_FREE(smb_fname_dst_mod); 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, - SMB_OFF_T alloc_size) + const char *name, off_t size, + off_t alloc_size) { struct stream_struct *tmp; - tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct, + tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct, (*num_streams)+1); if (tmp == NULL) { return false; @@ -834,20 +880,8 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, goto out; } - state.streams = NULL; - state.num_streams = 0; - - if (!S_ISDIR(smb_fname_base->st.st_ex_mode)) { - if (!add_one_stream(mem_ctx, - &state.num_streams, &state.streams, - "::$DATA", smb_fname_base->st.st_ex_size, - SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp, - &smb_fname_base->st))) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - } - + state.streams = *pstreams; + state.num_streams = *pnum_streams; state.mem_ctx = mem_ctx; state.handle = handle; state.status = NT_STATUS_OK; @@ -868,41 +902,33 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, *pnum_streams = state.num_streams; *pstreams = state.streams; - status = NT_STATUS_OK; + status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, pnum_streams, pstreams); out: TALLOC_FREE(smb_fname_base); return status; } -static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle) +static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) { - return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS; + return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS; } -/* VFS operations structure */ - -static vfs_op_tuple streams_depot_ops[] = { - {SMB_VFS_OP(streams_depot_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES, - SMB_VFS_LAYER_TRANSPARENT}, - {SMB_VFS_OP(streams_depot_open), SMB_VFS_OP_OPEN, - SMB_VFS_LAYER_TRANSPARENT}, - {SMB_VFS_OP(streams_depot_stat), SMB_VFS_OP_STAT, - SMB_VFS_LAYER_TRANSPARENT}, - {SMB_VFS_OP(streams_depot_lstat), SMB_VFS_OP_LSTAT, - 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} +static struct vfs_fn_pointers vfs_streams_depot_fns = { + .fs_capabilities_fn = streams_depot_fs_capabilities, + .open_fn = streams_depot_open, + .stat_fn = streams_depot_stat, + .lstat_fn = streams_depot_lstat, + .unlink_fn = streams_depot_unlink, + .rmdir_fn = streams_depot_rmdir, + .rename_fn = streams_depot_rename, + .streaminfo_fn = streams_depot_streaminfo, }; NTSTATUS vfs_streams_depot_init(void); NTSTATUS vfs_streams_depot_init(void) { return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot", - streams_depot_ops); + &vfs_streams_depot_fns); }