From 6f3b421c4a29e63e87a5987f54c925b8668f813c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 11 Sep 2016 12:39:13 +0200 Subject: [PATCH] s3/vfs: merge offline functionality into DOS attributes handling The offline VFS functions predate the SMB_VFS_{GET|SET}_DOS_ATTRIBUTES() functions, now that we have these, we can use them for the offline attribute as well. The primary reason for this is: performance. Merging both functions has the benefit that in VFS modules that use same backing store bits for both offline attribute and DOS attributes (like gpfs), we avoid calling the backing store twice in dos_mode() and file_set_dosmode(). This commit modifies all existing users of the offline attribute to adapt to the change, the next commit will then remove the obsolete offline functions. Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke --- libcli/smb/smb_constants.h | 3 +- source3/modules/vfs_default.c | 32 ++++++----- source3/modules/vfs_gpfs.c | 6 ++ source3/modules/vfs_offline.c | 20 +++++-- source3/modules/vfs_tsmsm.c | 102 +++++++++++++++++++++++++++++++--- source3/smbd/dosmode.c | 45 +++------------ 6 files changed, 141 insertions(+), 67 deletions(-) diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h index b963c73c5d3..47b5629743b 100644 --- a/libcli/smb/smb_constants.h +++ b/libcli/smb/smb_constants.h @@ -341,7 +341,8 @@ enum csc_policy { FILE_ATTRIBUTE_HIDDEN|\ FILE_ATTRIBUTE_SYSTEM|\ FILE_ATTRIBUTE_DIRECTORY|\ - FILE_ATTRIBUTE_ARCHIVE) + FILE_ATTRIBUTE_ARCHIVE|\ + FILE_ATTRIBUTE_OFFLINE) /* File type flags */ #define FILE_TYPE_DISK 0 diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 53199b8c5bb..4e8605bdaee 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1544,10 +1544,21 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, return NT_STATUS_NOT_SUPPORTED; } +static bool vfswrap_is_offline(struct vfs_handle_struct *handle, + const struct smb_filename *fname, + SMB_STRUCT_STAT *sbuf); + static NTSTATUS vfswrap_get_dos_attributes(struct vfs_handle_struct *handle, struct smb_filename *smb_fname, uint32_t *dosmode) { + bool offline; + + offline = vfswrap_is_offline(handle, smb_fname, &smb_fname->st); + if (offline) { + *dosmode |= FILE_ATTRIBUTE_OFFLINE; + } + return get_ea_dos_attribute(handle->conn, smb_fname, dosmode); } @@ -1555,6 +1566,13 @@ static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32_t *dosmode) { + bool offline; + + offline = vfswrap_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st); + if (offline) { + *dosmode |= FILE_ATTRIBUTE_OFFLINE; + } + return get_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode); } @@ -2683,16 +2701,6 @@ static bool vfswrap_is_offline(struct vfs_handle_struct *handle, return offline; } -static int vfswrap_set_offline(struct vfs_handle_struct *handle, - const struct smb_filename *fname) -{ - /* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */ -#if defined(ENOTSUP) - errno = ENOTSUP; -#endif - return -1; -} - static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle, struct files_struct *fsp, TALLOC_CTX *mem_ctx, @@ -2852,10 +2860,6 @@ static struct vfs_fn_pointers vfs_default_fns = { /* aio operations */ .aio_force_fn = vfswrap_aio_force, - /* offline operations */ - .is_offline_fn = vfswrap_is_offline, - .set_offline_fn = vfswrap_set_offline, - /* durable handle operations */ .durable_cookie_fn = vfswrap_durable_cookie, .durable_disconnect_fn = vfswrap_durable_disconnect, diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 730dda27dc3..dbbb55a1844 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1502,6 +1502,9 @@ static uint32_t vfs_gpfs_winattrs_to_dosmode(unsigned int winattrs) if (winattrs & GPFS_WINATTR_SPARSE_FILE) { dosmode |= FILE_ATTRIBUTE_SPARSE; } + if (winattrs & GPFS_WINATTR_OFFLINE) { + dosmode |= FILE_ATTRIBUTE_OFFLINE; + } return dosmode; } @@ -1525,6 +1528,9 @@ static unsigned int vfs_gpfs_dosmode_to_winattrs(uint32_t dosmode) if (dosmode & FILE_ATTRIBUTE_SPARSE) { winattrs |= GPFS_WINATTR_SPARSE_FILE; } + if (dosmode & FILE_ATTRIBUTE_OFFLINE) { + winattrs |= GPFS_WINATTR_OFFLINE; + } return winattrs; } diff --git a/source3/modules/vfs_offline.c b/source3/modules/vfs_offline.c index 5921f4392fc..e2d66fa930e 100644 --- a/source3/modules/vfs_offline.c +++ b/source3/modules/vfs_offline.c @@ -27,16 +27,26 @@ static uint32_t offline_fs_capabilities(struct vfs_handle_struct *handle, FILE_SUPPORTS_REMOTE_STORAGE; } -static bool offline_is_offline(struct vfs_handle_struct *handle, - const struct smb_filename *fname, - SMB_STRUCT_STAT *stbuf) +static NTSTATUS offline_get_dos_attributes(struct vfs_handle_struct *handle, + struct smb_filename *smb_fname, + uint32_t *dosmode) { - return true; + *dosmode |= FILE_ATTRIBUTE_OFFLINE; + return SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle, smb_fname, dosmode); +} + +static NTSTATUS offline_fget_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t *dosmode) +{ + *dosmode |= FILE_ATTRIBUTE_OFFLINE; + return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode); } static struct vfs_fn_pointers offline_fns = { .fs_capabilities_fn = offline_fs_capabilities, - .is_offline_fn = offline_is_offline, + .get_dos_attributes_fn = offline_get_dos_attributes, + .fget_dos_attributes_fn = offline_fget_dos_attributes, }; NTSTATUS vfs_offline_init(void); diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c index 91daa6f5a06..b943515a8fc 100644 --- a/source3/modules/vfs_tsmsm.c +++ b/source3/modules/vfs_tsmsm.c @@ -266,6 +266,33 @@ done: return offline; } +static NTSTATUS tsmsm_get_dos_attributes(struct vfs_handle_struct *handle, + struct smb_filename *fname, + uint32_t *dosmode) +{ + bool offline; + + offline = tsmsm_is_offline(handle, fname, &fname->st); + if (offline) { + *dosmode |= FILE_ATTRIBUTE_OFFLINE; + } + + return SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle, fname, dosmode); +} + +static NTSTATUS tsmsm_fget_dos_attributes(struct vfs_handle_struct *handle, + files_struct *fsp, + uint32_t *dosmode) +{ + bool offline; + + offline = tsmsm_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st); + if (offline) { + *dosmode |= FILE_ATTRIBUTE_OFFLINE; + } + + return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode); +} static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp) { @@ -467,8 +494,8 @@ static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struc return result; } -static int tsmsm_set_offline(struct vfs_handle_struct *handle, - const struct smb_filename *fname) +static NTSTATUS tsmsm_set_offline(struct vfs_handle_struct *handle, + const struct smb_filename *fname) { struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data; int result = 0; @@ -479,27 +506,82 @@ static int tsmsm_set_offline(struct vfs_handle_struct *handle, if (tsmd->hsmscript == NULL) { /* no script enabled */ DEBUG(1, ("tsmsm_set_offline: No 'tsmsm:hsm script' configured\n")); - return 0; + return NT_STATUS_OK; } status = get_full_smb_filename(talloc_tos(), fname, &path); if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return false; + return status; } /* Now, call the script */ command = talloc_asprintf(tsmd, "%s offline \"%s\"", tsmd->hsmscript, path); if(!command) { DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script")); - return -1; + return NT_STATUS_NO_MEMORY; } DEBUG(10, ("tsmsm_set_offline: Running [%s]\n", command)); if((result = smbrun(command, NULL)) != 0) { DEBUG(1,("tsmsm_set_offline: Running [%s] returned %d\n", command, result)); + TALLOC_FREE(command); + return NT_STATUS_INTERNAL_ERROR; } TALLOC_FREE(command); - return result; + return NT_STATUS_OK; +} + +static NTSTATUS tsmsm_set_dos_attributes(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uint32_t dosmode) +{ + NTSTATUS status; + uint32_t old_dosmode; + struct smb_filename *fname = NULL; + + /* dos_mode() doesn't like const smb_fname */ + fname = cp_smb_filename(talloc_tos(), smb_fname); + if (fname == NULL) { + return NT_STATUS_NO_MEMORY; + } + + old_dosmode = dos_mode(handle->conn, fname); + TALLOC_FREE(fname); + + status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle, smb_fname, dosmode); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!(old_dosmode & FILE_ATTRIBUTE_OFFLINE) && + (dosmode & FILE_ATTRIBUTE_OFFLINE)) + { + return NT_STATUS_OK; + } + + return tsmsm_set_offline(handle, smb_fname); +} + +static NTSTATUS tsmsm_fset_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t dosmode) +{ + NTSTATUS status; + uint32_t old_dosmode; + + old_dosmode = dos_mode(handle->conn, fsp->fsp_name); + + status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!(old_dosmode & FILE_ATTRIBUTE_OFFLINE) && + (dosmode & FILE_ATTRIBUTE_OFFLINE)) + { + return NT_STATUS_OK; + } + + return tsmsm_set_offline(handle, fsp->fsp_name); } static uint32_t tsmsm_fs_capabilities(struct vfs_handle_struct *handle, @@ -519,8 +601,10 @@ static struct vfs_fn_pointers tsmsm_fns = { .pwrite_send_fn = tsmsm_pwrite_send, .pwrite_recv_fn = tsmsm_pwrite_recv, .sendfile_fn = tsmsm_sendfile, - .is_offline_fn = tsmsm_is_offline, - .set_offline_fn = tsmsm_set_offline, + .set_dos_attributes_fn = tsmsm_set_dos_attributes, + .fset_dos_attributes_fn = tsmsm_fset_dos_attributes, + .get_dos_attributes_fn = tsmsm_get_dos_attributes, + .fget_dos_attributes_fn = tsmsm_fget_dos_attributes, }; NTSTATUS vfs_tsmsm_init(void); diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index a376cbc0f38..dab47c09c99 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -384,6 +384,12 @@ NTSTATUS set_ea_dos_attribute(connection_struct *conn, return NT_STATUS_NOT_IMPLEMENTED; } + /* + * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in + * vfs_default via DMAPI if that is enabled. + */ + dosmode &= ~FILE_ATTRIBUTE_OFFLINE; + ZERO_STRUCT(dosattrib); ZERO_STRUCT(blob); @@ -605,7 +611,6 @@ static uint32_t dos_mode_from_name(connection_struct *conn, uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname) { uint32_t result = 0; - bool offline; NTSTATUS status = NT_STATUS_OK; DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname))); @@ -620,11 +625,6 @@ uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname) result |= dos_mode_from_sbuf(conn, smb_fname); } - offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st); - if (S_ISREG(smb_fname->st.st_ex_mode) && offline) { - result |= FILE_ATTRIBUTE_OFFLINE; - } - if (conn->fs_capabilities & FILE_FILE_COMPRESSION) { bool compressed = false; status = dos_mode_check_compressed(conn, smb_fname, @@ -665,8 +665,6 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, mode_t tmp; mode_t unixmode; int ret = -1, lret = -1; - uint32_t old_mode; - struct timespec new_create_timespec; files_struct *fsp = NULL; bool need_close = false; NTSTATUS status; @@ -676,8 +674,7 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, return -1; } - /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */ - dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE); + dosmode &= SAMBA_ATTRIBUTES_MASK; DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, smb_fname_str_dbg(smb_fname))); @@ -692,34 +689,6 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, else dosmode &= ~FILE_ATTRIBUTE_DIRECTORY; - new_create_timespec = smb_fname->st.st_ex_btime; - - old_mode = dos_mode(conn, smb_fname); - - if ((dosmode & FILE_ATTRIBUTE_OFFLINE) && - !(old_mode & FILE_ATTRIBUTE_OFFLINE)) { - lret = SMB_VFS_SET_OFFLINE(conn, smb_fname); - if (lret == -1) { - if (errno == ENOTSUP) { - DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for " - "%s/%s is not supported.\n", - parent_dir, - smb_fname_str_dbg(smb_fname))); - } else { - DEBUG(0, ("An error occurred while setting " - "FILE_ATTRIBUTE_OFFLINE for " - "%s/%s: %s", parent_dir, - smb_fname_str_dbg(smb_fname), - strerror(errno))); - } - } - } - - dosmode &= ~FILE_ATTRIBUTE_OFFLINE; - old_mode &= ~FILE_ATTRIBUTE_OFFLINE; - - smb_fname->st.st_ex_btime = new_create_timespec; - /* Store the DOS attributes in an EA by preference. */ status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode); if (NT_STATUS_IS_OK(status)) {