smbd: Move lp_parm_bool out of notify_inotify.c
[obnox/samba/samba-obnox.git] / source3 / modules / vfs_default.c
index 2d49a943e102797f1f4d0108776242cffaff5086..dad6bb7440fa12d6002a902d7996cca5f7d2b3e5 100644 (file)
@@ -32,6 +32,7 @@
 #include "lib/util/tevent_unix.h"
 #include "lib/asys/asys.h"
 #include "lib/util/tevent_ntstatus.h"
+#include "lib/sys_rw.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -394,7 +395,7 @@ static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
                        if (ret == 0) {
                                init_stat_ex_from_stat(sbuf,
                                        &st,
-                                       lp_fake_dir_create_times(
+                                       lp_fake_directory_create_times(
                                                SNUM(handle->conn)));
                        }
                }
@@ -403,6 +404,14 @@ static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
        return result;
 }
 
+static NTSTATUS vfswrap_readdir_attr(struct vfs_handle_struct *handle,
+                                    const struct smb_filename *fname,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct readdir_attr_data **attr_data)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+
 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
 {
        START_PROFILE(syscall_seekdir);
@@ -437,7 +446,7 @@ static int vfswrap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mod
        if (lp_inherit_acls(SNUM(handle->conn))
            && parent_dirname(talloc_tos(), path, &parent, NULL)
            && (has_dacl = directory_has_default_acl(handle->conn, parent)))
-               mode = (0777 & lp_dir_mask(SNUM(handle->conn)));
+               mode = (0777 & lp_directory_mask(SNUM(handle->conn)));
 
        TALLOC_FREE(parent);
 
@@ -517,20 +526,23 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
                                    uint32_t create_options,
                                    uint32_t file_attributes,
                                    uint32_t oplock_request,
+                                   struct smb2_lease *lease,
                                    uint64_t allocation_size,
                                    uint32_t private_flags,
                                    struct security_descriptor *sd,
                                    struct ea_list *ea_list,
                                    files_struct **result,
-                                   int *pinfo)
+                                   int *pinfo,
+                                   const struct smb2_create_blobs *in_context_blobs,
+                                   struct smb2_create_blobs *out_context_blobs)
 {
        return create_file_default(handle->conn, req, root_dir_fid, smb_fname,
                                   access_mask, share_access,
                                   create_disposition, create_options,
-                                  file_attributes, oplock_request,
+                                  file_attributes, oplock_request, lease,
                                   allocation_size, private_flags,
                                   sd, ea_list, result,
-                                  pinfo);
+                                  pinfo, in_context_blobs, out_context_blobs);
 }
 
 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
@@ -549,7 +561,7 @@ static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, void *
 
        START_PROFILE_BYTES(syscall_read, n);
        result = sys_read(fsp->fh->fd, data, n);
-       END_PROFILE(syscall_read);
+       END_PROFILE_BYTES(syscall_read);
        return result;
 }
 
@@ -561,7 +573,7 @@ static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void
 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
        START_PROFILE_BYTES(syscall_pread, n);
        result = sys_pread(fsp->fh->fd, data, n, offset);
-       END_PROFILE(syscall_pread);
+       END_PROFILE_BYTES(syscall_pread);
 
        if (result == -1 && errno == ESPIPE) {
                /* Maintain the fiction that pipes can be seeked (sought?) on. */
@@ -603,7 +615,7 @@ static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, const
 
        START_PROFILE_BYTES(syscall_write, n);
        result = sys_write(fsp->fh->fd, data, n);
-       END_PROFILE(syscall_write);
+       END_PROFILE_BYTES(syscall_write);
        return result;
 }
 
@@ -615,7 +627,7 @@ static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, cons
 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
        START_PROFILE_BYTES(syscall_pwrite, n);
        result = sys_pwrite(fsp->fh->fd, data, n, offset);
-       END_PROFILE(syscall_pwrite);
+       END_PROFILE_BYTES(syscall_pwrite);
 
        if (result == -1 && errno == ESPIPE) {
                /* Maintain the fiction that pipes can be sought on. */
@@ -650,7 +662,7 @@ static void vfswrap_asys_finished(struct tevent_context *ev,
                                  struct tevent_fd *fde,
                                  uint16_t flags, void *p);
 
-static bool vfswrap_init_asys_ctx(struct smbXsrv_connection *conn)
+static bool vfswrap_init_asys_ctx(struct smbd_server_connection *conn)
 {
        int ret;
        int fd;
@@ -686,6 +698,8 @@ struct vfswrap_asys_state {
        struct tevent_req *req;
        ssize_t ret;
        int err;
+       SMBPROFILE_BASIC_ASYNC_STATE(profile_basic);
+       SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
 };
 
 static int vfswrap_asys_state_destructor(struct vfswrap_asys_state *s)
@@ -709,13 +723,15 @@ static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
        if (req == NULL) {
                return NULL;
        }
-       if (!vfswrap_init_asys_ctx(handle->conn->sconn->conn)) {
+       if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
                tevent_req_oom(req);
                return tevent_req_post(req, ev);
        }
-       state->asys_ctx = handle->conn->sconn->conn->asys_ctx;
+       state->asys_ctx = handle->conn->sconn->asys_ctx;
        state->req = req;
 
+       SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
+                                    state->profile_bytes, n);
        ret = asys_pread(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
        if (ret != 0) {
                tevent_req_error(req, ret);
@@ -741,13 +757,15 @@ static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
        if (req == NULL) {
                return NULL;
        }
-       if (!vfswrap_init_asys_ctx(handle->conn->sconn->conn)) {
+       if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
                tevent_req_oom(req);
                return tevent_req_post(req, ev);
        }
-       state->asys_ctx = handle->conn->sconn->conn->asys_ctx;
+       state->asys_ctx = handle->conn->sconn->asys_ctx;
        state->req = req;
 
+       SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
+                                    state->profile_bytes, n);
        ret = asys_pwrite(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
        if (ret != 0) {
                tevent_req_error(req, ret);
@@ -771,13 +789,15 @@ static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
        if (req == NULL) {
                return NULL;
        }
-       if (!vfswrap_init_asys_ctx(handle->conn->sconn->conn)) {
+       if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
                tevent_req_oom(req);
                return tevent_req_post(req, ev);
        }
-       state->asys_ctx = handle->conn->sconn->conn->asys_ctx;
+       state->asys_ctx = handle->conn->sconn->asys_ctx;
        state->req = req;
 
+       SMBPROFILE_BASIC_ASYNC_START(syscall_asys_fsync, profile_p,
+                                    state->profile_basic);
        ret = asys_fsync(state->asys_ctx, fsp->fh->fd, req);
        if (ret != 0) {
                tevent_req_error(req, ret);
@@ -793,44 +813,38 @@ static void vfswrap_asys_finished(struct tevent_context *ev,
                                        uint16_t flags, void *p)
 {
        struct asys_context *asys_ctx = (struct asys_context *)p;
-       struct tevent_req *req;
-       struct vfswrap_asys_state *state;
-       int res;
-       ssize_t ret;
-       int err;
-       void *private_data;
+       struct asys_result results[outstanding_aio_calls];
+       int i, ret;
 
        if ((flags & TEVENT_FD_READ) == 0) {
                return;
        }
 
-       while (true) {
-               res = asys_result(asys_ctx, &ret, &err, &private_data);
-               if (res == EINTR || res == EAGAIN) {
-                       return;
-               }
-#ifdef EWOULDBLOCK
-               if (res == EWOULDBLOCK) {
-                       return;
-               }
-#endif
+       ret = asys_results(asys_ctx, results, outstanding_aio_calls);
+       if (ret < 0) {
+               DEBUG(1, ("asys_results returned %s\n", strerror(-ret)));
+               return;
+       }
 
-               if (res == ECANCELED) {
-                       return;
-               }
+       for (i=0; i<ret; i++) {
+               struct asys_result *result = &results[i];
+               struct tevent_req *req;
+               struct vfswrap_asys_state *state;
 
-               if (res != 0) {
-                       DEBUG(1, ("asys_result returned %s\n", strerror(res)));
-                       return;
+               if ((result->ret == -1) && (result->err == ECANCELED)) {
+                       continue;
                }
 
-               req = talloc_get_type_abort(private_data, struct tevent_req);
+               req = talloc_get_type_abort(result->private_data,
+                                           struct tevent_req);
                state = tevent_req_data(req, struct vfswrap_asys_state);
 
                talloc_set_destructor(state, NULL);
 
-               state->ret = ret;
-               state->err = err;
+               SMBPROFILE_BASIC_ASYNC_END(state->profile_basic);
+               SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
+               state->ret = result->ret;
+               state->err = result->err;
                tevent_req_defer_callback(req, ev);
                tevent_req_done(req);
        }
@@ -893,7 +907,7 @@ static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struc
 
        START_PROFILE_BYTES(syscall_sendfile, n);
        result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
-       END_PROFILE(syscall_sendfile);
+       END_PROFILE_BYTES(syscall_sendfile);
        return result;
 }
 
@@ -907,7 +921,7 @@ static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
 
        START_PROFILE_BYTES(syscall_recvfile, n);
        result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
-       END_PROFILE(syscall_recvfile);
+       END_PROFILE_BYTES(syscall_recvfile);
        return result;
 }
 
@@ -958,7 +972,7 @@ static int vfswrap_stat(vfs_handle_struct *handle,
        }
 
        result = sys_stat(smb_fname->base_name, &smb_fname->st,
-                         lp_fake_dir_create_times(SNUM(handle->conn)));
+                         lp_fake_directory_create_times(SNUM(handle->conn)));
  out:
        END_PROFILE(syscall_stat);
        return result;
@@ -970,7 +984,7 @@ static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUC
 
        START_PROFILE(syscall_fstat);
        result = sys_fstat(fsp->fh->fd,
-                          sbuf, lp_fake_dir_create_times(SNUM(handle->conn)));
+                          sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
        END_PROFILE(syscall_fstat);
        return result;
 }
@@ -988,7 +1002,7 @@ static int vfswrap_lstat(vfs_handle_struct *handle,
        }
 
        result = sys_lstat(smb_fname->base_name, &smb_fname->st,
-                          lp_fake_dir_create_times(SNUM(handle->conn)));
+                          lp_fake_directory_create_times(SNUM(handle->conn)));
  out:
        END_PROFILE(syscall_lstat);
        return result;
@@ -1021,12 +1035,12 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
 {
        const char *in_data = (const char *)_in_data;
        char **out_data = (char **)_out_data;
+       NTSTATUS status;
 
        switch (function) {
        case FSCTL_SET_SPARSE:
        {
                bool set_sparse = true;
-               NTSTATUS status;
 
                if (in_len >= 1 && in_data[0] == 0) {
                        set_sparse = false;
@@ -1054,7 +1068,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
                          fsp_fnum_dbg(fsp)));
 
-               *out_len = (max_out_len >= 64) ? 64 : max_out_len;
+               *out_len = MIN(max_out_len, 64);
+
                /* Hmmm, will this cause problems if less data asked for? */
                return_data = talloc_array(ctx, char, 64);
                if (return_data == NULL) {
@@ -1065,6 +1080,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                push_file_id_16(return_data, &fsp->file_id);
                memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
                push_file_id_16(return_data+32, &fsp->file_id);
+               memset(return_data+48, 0, 16);
                *out_data = return_data;
                return NT_STATUS_OK;
        }
@@ -1123,16 +1139,23 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                 * Call the VFS routine to actually do the work.
                 */
                if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
-                       TALLOC_FREE(shadow_data);
-                       if (errno == ENOSYS) {
-                               DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n",
-                                       fsp->conn->connectpath));
-                               return NT_STATUS_NOT_SUPPORTED;
+                       int log_lev = 0;
+                       if (errno == 0) {
+                               /* broken module didn't set errno on error */
+                               status = NT_STATUS_UNSUCCESSFUL;
                        } else {
-                               DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n",
-                                       fsp->conn->connectpath));
-                               return NT_STATUS_UNSUCCESSFUL;
+                               status = map_nt_error_from_unix(errno);
+                               if (NT_STATUS_EQUAL(status,
+                                                   NT_STATUS_NOT_SUPPORTED)) {
+                                       log_lev = 5;
+                               }
                        }
+                       DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
+                                       "connectpath %s, failed - %s.\n",
+                                       fsp->conn->connectpath,
+                                       nt_errstr(status)));
+                       TALLOC_FREE(shadow_data);
+                       return status;
                }
 
                labels_data_count = (shadow_data->num_volumes * 2 *
@@ -1176,10 +1199,16 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                          shadow_data->num_volumes, fsp_str_dbg(fsp)));
                if (labels && shadow_data->labels) {
                        for (i=0; i<shadow_data->num_volumes; i++) {
-                               srvstr_push(cur_pdata, req_flags,
+                               size_t len = 0;
+                               status = srvstr_push(cur_pdata, req_flags,
                                            cur_pdata, shadow_data->labels[i],
                                            2 * sizeof(SHADOW_COPY_LABEL),
-                                           STR_UNICODE|STR_TERMINATE);
+                                           STR_UNICODE|STR_TERMINATE, &len);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       TALLOC_FREE(*out_data);
+                                       TALLOC_FREE(shadow_data);
+                                       return status;
+                               }
                                cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
                                DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
                        }
@@ -1260,7 +1289,6 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                 * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
                 * this FSCTL correct for sparse files.
                 */
-               NTSTATUS status;
                uint64_t offset, length;
                char *out_data_tmp = NULL;
 
@@ -1393,6 +1421,10 @@ static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *hand
                off_t this_num = MIN(sizeof(vfs_cc_state->buf),
                                     num - vfs_cc_state->copied);
 
+               if (src_fsp->op == NULL) {
+                       tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+                       return tevent_req_post(req, ev);
+               }
                init_strict_lock_struct(src_fsp,
                                        src_fsp->op->global->open_persistent_id,
                                        src_off,
@@ -1426,6 +1458,11 @@ static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *hand
 
                src_off += ret;
 
+               if (dest_fsp->op == NULL) {
+                       tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+                       return tevent_req_post(req, ev);
+               }
+
                init_strict_lock_struct(dest_fsp,
                                        dest_fsp->op->global->open_persistent_id,
                                        dest_off,
@@ -1538,6 +1575,18 @@ static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
 #else
 #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
 #endif
+       if (result == 0) {
+               /*
+                * Some file systems do not allocate a block for very
+                * small files. But for non-empty file should report a
+                * positive size.
+                */
+
+               uint64_t filesize = get_file_size_stat(sbuf);
+               if (filesize > 0) {
+                       result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
+               }
+       }
 #else
        result = get_file_size_stat(sbuf);
 #endif
@@ -1815,15 +1864,14 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
           return ENOTSUP or EINVAL in cases like that. */
        ret = SMB_VFS_FALLOCATE(fsp, VFS_FALLOCATE_EXTEND_SIZE,
                                pst->st_ex_size, space_to_write);
-       if (ret == ENOSPC) {
-               errno = ENOSPC;
+       if (ret == -1 && errno == ENOSPC) {
                return -1;
        }
        if (ret == 0) {
                return 0;
        }
        DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
-               "error %d. Falling back to slow manual allocation\n", ret));
+               "error %d. Falling back to slow manual allocation\n", errno));
 
        /* available disk space is enough or not? */
        space_avail = get_dfree_info(fsp->conn,
@@ -1839,8 +1887,7 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
        /* Write out the real space on disk. */
        ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
        if (ret != 0) {
-               errno = ret;
-               ret = -1;
+               return -1;
        }
 
        return 0;
@@ -1925,6 +1972,15 @@ static int vfswrap_fallocate(vfs_handle_struct *handle,
        START_PROFILE(syscall_fallocate);
        if (mode == VFS_FALLOCATE_EXTEND_SIZE) {
                result = sys_posix_fallocate(fsp->fh->fd, offset, len);
+               /*
+                * posix_fallocate returns 0 on success, errno on error
+                * and doesn't set errno. Make it behave like fallocate()
+                * which returns -1, and sets errno on failure.
+                */
+               if (result != 0) {
+                       errno = result;
+                       result = -1;
+               }
        } else if (mode == VFS_FALLOCATE_KEEP_SIZE) {
                result = sys_fallocate(fsp->fh->fd, mode, offset, len);
        } else {
@@ -2063,6 +2119,9 @@ static NTSTATUS vfswrap_notify_watch(vfs_handle_struct *vfs_handle,
         */
 #ifdef HAVE_INOTIFY
        if (lp_kernel_change_notify(vfs_handle->conn->params)) {
+               if (!lp_parm_bool(-1, "notify", "inotify", True)) {
+                       return NT_STATUS_INVALID_SYSTEM_SERVICE;
+               }
                return inotify_watch(ctx, path, filter, subdir_filter,
                                     callback, private_data, handle);
        }
@@ -2184,8 +2243,7 @@ static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
 static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
                                         struct byte_range_lock *br_lck,
                                         struct lock_struct *plock,
-                                        bool blocking_lock,
-                                        struct blocking_lock_record *blr)
+                                        bool blocking_lock)
 {
        SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
 
@@ -2205,8 +2263,7 @@ static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
 
 static bool vfswrap_brl_cancel_windows(struct vfs_handle_struct *handle,
                                       struct byte_range_lock *br_lck,
-                                      struct lock_struct *plock,
-                                      struct blocking_lock_record *blr)
+                                      struct lock_struct *plock)
 {
        SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
 
@@ -2485,6 +2542,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .opendir_fn = vfswrap_opendir,
        .fdopendir_fn = vfswrap_fdopendir,
        .readdir_fn = vfswrap_readdir,
+       .readdir_attr_fn = vfswrap_readdir_attr,
        .seekdir_fn = vfswrap_seekdir,
        .telldir_fn = vfswrap_telldir,
        .rewind_dir_fn = vfswrap_rewinddir,