smbd: Fix a typo in a few places
[samba.git] / source3 / modules / vfs_tsmsm.c
index c11e896daa0420e9a838e4418f267aa12df855b2..89191f7e3ae55be0d38083365fc33754efcacc3e 100644 (file)
@@ -27,7 +27,7 @@
         where <operation> is currently 'offline' to set offline status of the <filepath>
 
   tsmsm: online ratio = ratio to check reported size against actual file size (0.5 by default)
-  tsmsm: attribute name = name of DMAPI attribute that is present when a file is offline. 
+  tsmsm: dmapi attribute = name of DMAPI attribute that is present when a file is offline.
   Default is "IBMobj" (which is what GPFS uses)
 
   The TSMSM VFS module tries to avoid calling expensive DMAPI calls with some heuristics
@@ -39,6 +39,8 @@
  */
 
 #include "includes.h"
+#include "smbd/smbd.h"
+#include "lib/util/tevent_unix.h"
 
 #ifndef USE_DMAPI
 #error "This module requires DMAPI support!"
@@ -87,6 +89,8 @@ static void tsmsm_free_data(void **pptr) {
 static int tsmsm_connect(struct vfs_handle_struct *handle,
                         const char *service,
                         const char *user) {
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        struct tsmsm_struct *tsmd;
        const char *fres;
        const char *tsmname;
@@ -96,7 +100,7 @@ static int tsmsm_connect(struct vfs_handle_struct *handle,
                return ret;
        }
 
-       tsmd = TALLOC_ZERO_P(handle, struct tsmsm_struct);
+       tsmd = talloc_zero(handle, struct tsmsm_struct);
        if (!tsmd) {
                SMB_VFS_NEXT_DISCONNECT(handle);
                DEBUG(0,("tsmsm_connect: out of memory!\n"));
@@ -113,16 +117,19 @@ static int tsmsm_connect(struct vfs_handle_struct *handle,
        tsmname = (handle->param ? handle->param : "tsmsm");
        
        /* Get 'hsm script' and 'dmapi attribute' parameters to tsmd context */
-       tsmd->hsmscript = lp_parm_talloc_string(SNUM(handle->conn), tsmname,
-                                               "hsm script", NULL);
+       tsmd->hsmscript = lp_parm_substituted_string(
+               tsmd, lp_sub, SNUM(handle->conn), tsmname,
+               "hsm script", NULL);
        talloc_steal(tsmd, tsmd->hsmscript);
        
-       tsmd->attrib_name = lp_parm_talloc_string(SNUM(handle->conn), tsmname, 
-                                                 "dmapi attribute", DM_ATTRIB_OBJECT);
+       tsmd->attrib_name = lp_parm_substituted_string(
+               tsmd, lp_sub, SNUM(handle->conn), tsmname,
+               "dmapi attribute", DM_ATTRIB_OBJECT);
        talloc_steal(tsmd, tsmd->attrib_name);
        
-       tsmd->attrib_value = lp_parm_talloc_string(SNUM(handle->conn), "tsmsm", 
-                                                  "dmapi value", NULL);
+       tsmd->attrib_value = lp_parm_substituted_string(
+               tsmd, lp_sub, SNUM(handle->conn), tsmname,
+               "dmapi value", NULL);
        talloc_steal(tsmd, tsmd->attrib_value);
        
        /* retrieve 'online ratio'. In case of error default to FILE_IS_ONLINE_RATIO */
@@ -146,8 +153,9 @@ static int tsmsm_connect(struct vfs_handle_struct *handle,
 }
 
 static bool tsmsm_is_offline(struct vfs_handle_struct *handle, 
-                           const char *path,
-                           SMB_STRUCT_STAT *stbuf) {
+                            const struct smb_filename *fname,
+                            SMB_STRUCT_STAT *stbuf)
+{
        struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
        const dm_sessid_t *dmsession_id;
        void *dmhandle = NULL;
@@ -158,10 +166,18 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        bool offline;
        char *buf = NULL;
        size_t buflen;
+       NTSTATUS status;
+       char *path;
+
+        status = get_full_smb_filename(talloc_tos(), fname, &path);
+        if (!NT_STATUS_IS_OK(status)) {
+                errno = map_errno_from_nt_status(status);
+                return false;
+        }
 
         /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
           then assume it is not offline (it may not be 100%, as it could be sparse) */
-       if (512 * (off_t)stbuf->st_ex_blocks >=
+       if (512 * stbuf->st_ex_blocks >=
            stbuf->st_ex_size * tsmd->online_ratio) {
                DEBUG(10,("%s not offline: st_blocks=%llu st_size=%llu "
                          "online_ratio=%.2f\n", path,
@@ -181,7 +197,7 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
         * become_root() is just as good anyway (tridge) 
         */
 
-       /* Also, AIX has DMAPI but no POSIX capablities support. In this case,
+       /* Also, AIX has DMAPI but no POSIX capabilities support. In this case,
         * we need to be root to do DMAPI manipulations.
         */
        become_root();
@@ -252,6 +268,19 @@ done:
        return offline;
 }
 
+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)
 {
@@ -266,29 +295,143 @@ static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struc
                DEBUG(10,("tsmsm_aio_force st_blocks=%llu st_size=%llu "
                          "online_ratio=%.2f\n", (unsigned long long)sbuf.st_ex_blocks,
                          (unsigned long long)sbuf.st_ex_size, tsmd->online_ratio));
-               return !(512 * (off_t)sbuf.st_ex_blocks >=
+               return !(512 * sbuf.st_ex_blocks >=
                         sbuf.st_ex_size * tsmd->online_ratio);
        }
        return false;
 }
 
-static ssize_t tsmsm_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, 
-                               SMB_STRUCT_AIOCB *aiocb)
+struct tsmsm_pread_state {
+       struct files_struct *fsp;
+       ssize_t ret;
+       bool was_offline;
+       struct vfs_aio_state vfs_aio_state;
+};
+
+static void tsmsm_pread_done(struct tevent_req *subreq);
+
+static struct tevent_req *tsmsm_pread_send(struct vfs_handle_struct *handle,
+                                          TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct files_struct *fsp,
+                                          void *data, size_t n, off_t offset)
 {
-       ssize_t result;
+       struct tevent_req *req, *subreq;
+       struct tsmsm_pread_state *state;
 
-       result = SMB_VFS_NEXT_AIO_RETURN(handle, fsp, aiocb);
-       if(result >= 0) {
-               notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+       req = tevent_req_create(mem_ctx, &state, struct tsmsm_pread_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->fsp = fsp;
+       state->was_offline = tsmsm_aio_force(handle, fsp);
+       subreq = SMB_VFS_NEXT_PREAD_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, tsmsm_pread_done, req);
+       return req;
+}
+
+static void tsmsm_pread_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct tsmsm_pread_state *state = tevent_req_data(
+               req, struct tsmsm_pread_state);
+
+       state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static ssize_t tsmsm_pread_recv(struct tevent_req *req,
+                               struct vfs_aio_state *vfs_aio_state)
+{
+       struct tsmsm_pread_state *state = tevent_req_data(
+               req, struct tsmsm_pread_state);
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
+       if (state->ret >= 0 && state->was_offline) {
+               struct files_struct *fsp = state->fsp;
+               notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
                             FILE_NOTIFY_CHANGE_ATTRIBUTES,
                             fsp->fsp_name->base_name);
        }
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
+}
 
-       return result;
+struct tsmsm_pwrite_state {
+       struct files_struct *fsp;
+       ssize_t ret;
+       bool was_offline;
+       struct vfs_aio_state vfs_aio_state;
+};
+
+static void tsmsm_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *tsmsm_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, *subreq;
+       struct tsmsm_pwrite_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct tsmsm_pwrite_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->fsp = fsp;
+       state->was_offline = tsmsm_aio_force(handle, 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, tsmsm_pwrite_done, req);
+       return req;
+}
+
+static void tsmsm_pwrite_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct tsmsm_pwrite_state *state = tevent_req_data(
+               req, struct tsmsm_pwrite_state);
+
+       state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+       TALLOC_FREE(subreq);
+       tevent_req_done(req);
+}
+
+static ssize_t tsmsm_pwrite_recv(struct tevent_req *req,
+                                struct vfs_aio_state *vfs_aio_state)
+{
+       struct tsmsm_pwrite_state *state = tevent_req_data(
+               req, struct tsmsm_pwrite_state);
+
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+               return -1;
+       }
+       if (state->ret >= 0 && state->was_offline) {
+               struct files_struct *fsp = state->fsp;
+               notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_ATTRIBUTES,
+                            fsp->fsp_name->base_name);
+       }
+       *vfs_aio_state = state->vfs_aio_state;
+       return state->ret;
 }
 
 static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, const DATA_BLOB *hdr,
-                             SMB_OFF_T offset, size_t n)
+                             off_t offset, size_t n)
 {
        bool file_offline = tsmsm_aio_force(handle, fsp);
 
@@ -304,7 +447,7 @@ static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct
 /* We do overload pread to allow notification when file becomes online after offline status */
 /* We don't intercept SMB_VFS_READ here because all file I/O now goes through SMB_VFS_PREAD instead */
 static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct *fsp, 
-                          void *data, size_t n, SMB_OFF_T offset) {
+                          void *data, size_t n, off_t offset) {
        ssize_t result;
        bool notify_online = tsmsm_aio_force(handle, fsp);
 
@@ -322,7 +465,7 @@ static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct
 }
 
 static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struct *fsp, 
-                           const void *data, size_t n, SMB_OFF_T offset) {
+                           const void *data, size_t n, off_t offset) {
        ssize_t result;
        bool notify_online = tsmsm_aio_force(handle, fsp);
 
@@ -339,30 +482,64 @@ 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 char *path) {
+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;
        char *command;
+       NTSTATUS status;
+       char *path;
 
        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)) {
+               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;
+               DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script\n"));
+               return NT_STATUS_NO_MEMORY;
        }
        DEBUG(10, ("tsmsm_set_offline: Running [%s]\n", command));
-       if((result = smbrun(command, NULL)) != 0) {
+       result = smbrun(command, NULL, NULL);
+       if(result != 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_fset_dos_attributes(struct vfs_handle_struct *handle,
+                                         struct files_struct *fsp,
+                                         uint32_t dosmode)
+{
+       NTSTATUS status;
+       uint32_t old_dosmode;
+
+       old_dosmode = fdos_mode(fsp);
+
+       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,
@@ -373,18 +550,23 @@ static uint32_t tsmsm_fs_capabilities(struct vfs_handle_struct *handle,
 
 static struct vfs_fn_pointers tsmsm_fns = {
        .connect_fn = tsmsm_connect,
-       .fs_capabilities = tsmsm_fs_capabilities,
-       .aio_force = tsmsm_aio_force,
-       .aio_return_fn = tsmsm_aio_return,
-       .pread = tsmsm_pread,
-       .pwrite = tsmsm_pwrite,
-       .sendfile = tsmsm_sendfile,
-       .is_offline = tsmsm_is_offline,
-       .set_offline = tsmsm_set_offline,
+       .fs_capabilities_fn = tsmsm_fs_capabilities,
+       .aio_force_fn = tsmsm_aio_force,
+       .pread_fn = tsmsm_pread,
+       .pread_send_fn = tsmsm_pread_send,
+       .pread_recv_fn = tsmsm_pread_recv,
+       .pwrite_fn = tsmsm_pwrite,
+       .pwrite_send_fn = tsmsm_pwrite_send,
+       .pwrite_recv_fn = tsmsm_pwrite_recv,
+       .sendfile_fn = tsmsm_sendfile,
+       .fset_dos_attributes_fn = tsmsm_fset_dos_attributes,
+       .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
+       .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
+       .fget_dos_attributes_fn = tsmsm_fget_dos_attributes,
 };
 
-NTSTATUS vfs_tsmsm_init(void);
-NTSTATUS vfs_tsmsm_init(void)
+static_decl_vfs;
+NTSTATUS vfs_tsmsm_init(TALLOC_CTX *ctx)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
                                "tsmsm", &tsmsm_fns);