s3/vfs: merge offline functionality into DOS attributes handling
authorRalph Boehme <slow@samba.org>
Sun, 11 Sep 2016 10:39:13 +0000 (12:39 +0200)
committerVolker Lendecke <vl@samba.org>
Tue, 11 Oct 2016 09:01:10 +0000 (11:01 +0200)
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 <slow@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
libcli/smb/smb_constants.h
source3/modules/vfs_default.c
source3/modules/vfs_gpfs.c
source3/modules/vfs_offline.c
source3/modules/vfs_tsmsm.c
source3/smbd/dosmode.c

index b963c73c5d3c1c1400500891afbf632bebf229ba..47b5629743b6f719aa9d6072052fd9a2e574e98b 100644 (file)
@@ -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
index 53199b8c5bb82725558c6378f10aaac1f24fba7b..4e8605bdaee346aedd2e110b99d8861c19866fee 100644 (file)
@@ -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,
index 730dda27dc30de2ba1bb6f39940e25c842e6dda7..dbbb55a1844738ad0b5336377bc1e417552ceef0 100644 (file)
@@ -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;
 }
index 5921f4392fce14cafa2b21eac05ab80ef1693e54..e2d66fa930ee74ab4d5f7b89a0a0ff0036b5ecbb 100644 (file)
@@ -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);
index 91daa6f5a065382ed0c82a5b04949f743bca793e..b943515a8fcb13210135daeaa093da6f9643a84b 100644 (file)
@@ -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);
index a376cbc0f38bc2fcaf1bad24652dc2334827db8f..dab47c09c9962ba19e32dd2f3c069d9c2012fad4 100644 (file)
@@ -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)) {