Move posix_fallocate into the VFS where it belongs.
[samba.git] / source3 / modules / vfs_default.c
index 036a4380025bc1e314140575734b34eb572b9b0f..63993fed3656509640981d78564fbdbf59cd83aa 100644 (file)
@@ -134,7 +134,9 @@ static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
                 * we might be able to set sub-second timestamps.
                 * See what filetime set primitives we have.
                 */
-#if defined(HAVE_UTIMES)
+#if defined(HAVE_UTIMENSAT)
+               *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
+#elif defined(HAVE_UTIMES)
                /* utimes allows msec timestamps to be set. */
                *p_ts_res = TIMESTAMP_SET_MSEC;
 #elif defined(HAVE_UTIME)
@@ -142,15 +144,11 @@ static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
                *p_ts_res = TIMESTAMP_SET_SECONDS;
 #endif
 
-               /* TODO. Add a configure test for the Linux
-                * nsec timestamp set system call, and use it
-                * if available....
-                */
                DEBUG(10,("vfswrap_fs_capabilities: timestamp "
                        "resolution of %s "
                        "available on share %s, directory %s\n",
                        *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
-                       lp_servicename(conn->cnum),
+                       lp_servicename(conn->params->service),
                        conn->connectpath ));
        }
        TALLOC_FREE(smb_fname_cpath);
@@ -219,7 +217,7 @@ static int vfswrap_mkdir(vfs_handle_struct *handle,  const char *path, mode_t mo
        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;
+               mode = (0777 & lp_dir_mask(SNUM(handle->conn)));
 
        TALLOC_FREE(parent);
 
@@ -300,6 +298,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
                                    uint32_t file_attributes,
                                    uint32_t oplock_request,
                                    uint64_t allocation_size,
+                                   uint32_t private_flags,
                                    struct security_descriptor *sd,
                                    struct ea_list *ea_list,
                                    files_struct **result,
@@ -309,7 +308,8 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
                                   access_mask, share_access,
                                   create_disposition, create_options,
                                   file_attributes, oplock_request,
-                                  allocation_size, sd, ea_list, result,
+                                  allocation_size, private_flags,
+                                  sd, ea_list, result,
                                   pinfo);
 }
 
@@ -477,95 +477,6 @@ static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
        return result;
 }
 
-/*********************************************************
- For rename across filesystems Patch from Warren Birnbaum
- <warrenb@hpcvscdp.cv.hp.com>
-**********************************************************/
-
-static int copy_reg(const char *source, const char *dest)
-{
-       SMB_STRUCT_STAT source_stats;
-       int saved_errno;
-       int ifd = -1;
-       int ofd = -1;
-
-       if (sys_lstat (source, &source_stats) == -1)
-               return -1;
-
-       if (!S_ISREG (source_stats.st_ex_mode))
-               return -1;
-
-       if((ifd = sys_open (source, O_RDONLY, 0)) < 0)
-               return -1;
-
-       if (unlink (dest) && errno != ENOENT)
-               return -1;
-
-#ifdef O_NOFOLLOW
-       if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 )
-#else
-       if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 )
-#endif
-               goto err;
-
-       if (transfer_file(ifd, ofd, (size_t)-1) == -1)
-               goto err;
-
-       /*
-        * Try to preserve ownership.  For non-root it might fail, but that's ok.
-        * But root probably wants to know, e.g. if NFS disallows it.
-        */
-
-#ifdef HAVE_FCHOWN
-       if ((fchown(ofd, source_stats.st_ex_uid, source_stats.st_ex_gid) == -1) && (errno != EPERM))
-#else
-       if ((chown(dest, source_stats.st_ex_uid, source_stats.st_ex_gid) == -1) && (errno != EPERM))
-#endif
-               goto err;
-
-       /*
-        * fchown turns off set[ug]id bits for non-root,
-        * so do the chmod last.
-        */
-
-#if defined(HAVE_FCHMOD)
-       if (fchmod (ofd, source_stats.st_ex_mode & 07777))
-#else
-       if (chmod (dest, source_stats.st_ex_mode & 07777))
-#endif
-               goto err;
-
-       if (close (ifd) == -1)
-               goto err;
-
-       if (close (ofd) == -1)
-               return -1;
-
-       /* Try to copy the old file's modtime and access time.  */
-       {
-               struct utimbuf tv;
-
-               tv.actime = convert_timespec_to_time_t(source_stats.st_ex_atime);
-               tv.modtime = convert_timespec_to_time_t(source_stats.st_ex_mtime);
-               utime(dest, &tv);
-       }
-
-       if (unlink (source) == -1)
-               return -1;
-
-       return 0;
-
-  err:
-
-       saved_errno = errno;
-       if (ifd != -1)
-               close(ifd);
-       if (ofd != -1)
-               close(ofd);
-       errno = saved_errno;
-       return -1;
-}
-
 static int vfswrap_rename(vfs_handle_struct *handle,
                          const struct smb_filename *smb_fname_src,
                          const struct smb_filename *smb_fname_dst)
@@ -580,11 +491,6 @@ static int vfswrap_rename(vfs_handle_struct *handle,
        }
 
        result = rename(smb_fname_src->base_name, smb_fname_dst->base_name);
-       if ((result == -1) && (errno == EXDEV)) {
-               /* Rename across filesystems needed. */
-               result = copy_reg(smb_fname_src->base_name,
-                                 smb_fname_dst->base_name);
-       }
 
  out:
        END_PROFILE(syscall_rename);
@@ -617,7 +523,8 @@ static int vfswrap_stat(vfs_handle_struct *handle,
                goto out;
        }
 
-       result = sys_stat(smb_fname->base_name, &smb_fname->st);
+       result = sys_stat(smb_fname->base_name, &smb_fname->st,
+                         lp_fake_dir_create_times(SNUM(handle->conn)));
  out:
        END_PROFILE(syscall_stat);
        return result;
@@ -628,7 +535,8 @@ static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUC
        int result;
 
        START_PROFILE(syscall_fstat);
-       result = sys_fstat(fsp->fh->fd, sbuf);
+       result = sys_fstat(fsp->fh->fd,
+                          sbuf, lp_fake_dir_create_times(SNUM(handle->conn)));
        END_PROFILE(syscall_fstat);
        return result;
 }
@@ -645,23 +553,22 @@ static int vfswrap_lstat(vfs_handle_struct *handle,
                goto out;
        }
 
-       result = sys_lstat(smb_fname->base_name, &smb_fname->st);
+       result = sys_lstat(smb_fname->base_name, &smb_fname->st,
+                          lp_fake_dir_create_times(SNUM(handle->conn)));
  out:
        END_PROFILE(syscall_lstat);
        return result;
 }
 
-static NTSTATUS vfswrap_translate_name(vfs_handle_struct *handle,
-                                      char **mapped_name,
-                                      enum vfs_translate_direction direction)
+static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
+                                      const char *name,
+                                      enum vfs_translate_direction direction,
+                                      TALLOC_CTX *mem_ctx,
+                                      char **mapped_name)
 {
-       /* Default behavior is a NOOP */
-
-       if (*mapped_name != NULL)
-               return NT_STATUS_OK;
-
-       return NT_STATUS_INVALID_PARAMETER;
+       return NT_STATUS_NONE_MAPPED;
 }
+
 /********************************************************************
  Given a stat buffer return the allocated size on disk, taking into
  account sparse files.
@@ -847,30 +754,39 @@ static int vfswrap_ntimes(vfs_handle_struct *handle,
                goto out;
        }
 
-       if (null_timespec(ft->atime)) {
-               ft->atime= smb_fname->st.st_ex_atime;
-       }
+       if (ft != NULL) {
+               if (null_timespec(ft->atime)) {
+                       ft->atime= smb_fname->st.st_ex_atime;
+               }
 
-       if (null_timespec(ft->mtime)) {
-               ft->mtime = smb_fname->st.st_ex_mtime;
-       }
+               if (null_timespec(ft->mtime)) {
+                       ft->mtime = smb_fname->st.st_ex_mtime;
+               }
 
-       if (!null_timespec(ft->create_time) &&
-                       lp_store_create_time(SNUM(handle->conn))) {
-               set_create_timespec_ea(handle->conn,
-                               NULL,
-                               smb_fname,
-                               ft->create_time);
-       }
+               if (!null_timespec(ft->create_time)) {
+                       set_create_timespec_ea(handle->conn,
+                                              smb_fname,
+                                              ft->create_time);
+               }
 
-       if ((timespec_compare(&ft->atime,
-                               &smb_fname->st.st_ex_atime) == 0) &&
-                       (timespec_compare(&ft->mtime,
-                               &smb_fname->st.st_ex_mtime) == 0)) {
-               return 0;
+               if ((timespec_compare(&ft->atime,
+                                     &smb_fname->st.st_ex_atime) == 0) &&
+                   (timespec_compare(&ft->mtime,
+                                     &smb_fname->st.st_ex_mtime) == 0)) {
+                       return 0;
+               }
        }
 
-#if defined(HAVE_UTIMES)
+#if defined(HAVE_UTIMENSAT)
+       if (ft != NULL) {
+               struct timespec ts[2];
+               ts[0] = ft->atime;
+               ts[1] = ft->mtime;
+               result = utimensat(AT_FDCWD, smb_fname->base_name, ts, 0);
+       } else {
+               result = utimensat(AT_FDCWD, smb_fname->base_name, NULL, 0);
+       }
+#elif defined(HAVE_UTIMES)
        if (ft != NULL) {
                struct timeval tv[2];
                tv[0] = convert_timespec_to_timeval(ft->atime);
@@ -909,6 +825,9 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
        SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
        unsigned char zero_space[4096];
        SMB_OFF_T space_to_write;
+       uint64_t space_avail;
+       uint64_t bsize,dfree,dsize;
+       int ret;
 
        if (currpos == -1)
                return -1;
@@ -916,8 +835,6 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
        if (SMB_VFS_FSTAT(fsp, &st) == -1)
                return -1;
 
-       space_to_write = len - st.st_ex_size;
-
 #ifdef S_ISFIFO
        if (S_ISFIFO(st.st_ex_mode))
                return 0;
@@ -930,28 +847,39 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
        if (st.st_ex_size > len)
                return sys_ftruncate(fsp->fh->fd, len);
 
+       space_to_write = len - st.st_ex_size;
+
+       /* for allocation try posix_fallocate first. This can fail on some
+          platforms e.g. when the filesystem doesn't support it and no
+          emulation is being done by the libc (like on AIX with JFS1). In that
+          case we do our own emulation. posix_fallocate implementations can
+          return ENOTSUP or EINVAL in cases like that. */
+       ret = SMB_VFS_POSIX_FALLOCATE(fsp, st.st_ex_size, space_to_write);
+       if (ret == ENOSPC) {
+               errno = ENOSPC;
+               return -1;
+       }
+       if (ret == 0) {
+               return 0;
+       }
+       DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_POSIX_FALLOCATE failed with "
+               "error %d. Falling back to slow manual allocation\n", ret));
+
        /* available disk space is enough or not? */
-       if (lp_strict_allocate(SNUM(fsp->conn))){
-               uint64_t space_avail;
-               uint64_t bsize,dfree,dsize;
-
-               space_avail = get_dfree_info(fsp->conn,
-                                            fsp->fsp_name->base_name, false,
-                                            &bsize, &dfree, &dsize);
-               /* space_avail is 1k blocks */
-               if (space_avail == (uint64_t)-1 ||
-                               ((uint64_t)space_to_write/1024 > space_avail) ) {
-                       errno = ENOSPC;
-                       return -1;
-               }
+       space_avail = get_dfree_info(fsp->conn,
+                                    fsp->fsp_name->base_name, false,
+                                    &bsize,&dfree,&dsize);
+       /* space_avail is 1k blocks */
+       if (space_avail == (uint64_t)-1 ||
+                       ((uint64_t)space_to_write/1024 > space_avail) ) {
+               errno = ENOSPC;
+               return -1;
        }
 
        /* Write out the real space on disk. */
        if (SMB_VFS_LSEEK(fsp, st.st_ex_size, SEEK_SET) != st.st_ex_size)
                return -1;
 
-       space_to_write = len - st.st_ex_size;
-
        memset(zero_space, '\0', sizeof(zero_space));
        while ( space_to_write > 0) {
                SMB_OFF_T retlen;
@@ -1046,6 +974,19 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_O
        return result;
 }
 
+static int vfswrap_posix_fallocate(vfs_handle_struct *handle,
+                       files_struct *fsp,
+                       SMB_OFF_T offset,
+                       SMB_OFF_T len)
+{
+       int result;
+
+       START_PROFILE(syscall_posix_fallocate);
+       result = sys_posix_fallocate(fsp->fh->fd, offset, len);
+       END_PROFILE(syscall_posix_fallocate);
+       return result;
+}
+
 static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
 {
        bool result;
@@ -1136,12 +1077,25 @@ static int vfswrap_mknod(vfs_handle_struct *handle,  const char *pathname, mode_
        return result;
 }
 
-static char *vfswrap_realpath(vfs_handle_struct *handle,  const char *path, char *resolved_path)
+static char *vfswrap_realpath(vfs_handle_struct *handle,  const char *path)
 {
        char *result;
 
        START_PROFILE(syscall_realpath);
-       result = realpath(path, resolved_path);
+#ifdef REALPATH_TAKES_NULL
+       result = realpath(path, NULL);
+#else
+       result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
+       if (result) {
+               char *resolved_path = realpath(path, result);
+               if (!resolved_path) {
+                       SAFE_FREE(result);
+               } else {
+                       /* SMB_ASSERT(result == resolved_path) ? */
+                       result = resolved_path;
+               }
+       }
+#endif
        END_PROFILE(syscall_realpath);
        return result;
 }
@@ -1223,21 +1177,17 @@ static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
                ret = SMB_VFS_FSTAT(fsp, &sbuf);
        }
        else {
-               struct smb_filename *smb_fname = NULL;
-               NTSTATUS status;
+               struct smb_filename smb_fname;
+
+               ZERO_STRUCT(smb_fname);
+               smb_fname.base_name = discard_const_p(char, fname);
 
-               status = create_synthetic_smb_fname(talloc_tos(), fname, NULL,
-                                                   NULL, &smb_fname);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
                if (lp_posix_pathnames()) {
-                       ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
+                       ret = SMB_VFS_LSTAT(handle->conn, &smb_fname);
                } else {
-                       ret = SMB_VFS_STAT(handle->conn, smb_fname);
+                       ret = SMB_VFS_STAT(handle->conn, &smb_fname);
                }
-               sbuf = smb_fname->st;
-               TALLOC_FREE(smb_fname);
+               sbuf = smb_fname.st;
        }
 
        if (ret == -1) {
@@ -1347,7 +1297,8 @@ static void vfswrap_strict_unlock(struct vfs_handle_struct *handle,
 
 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
                                    files_struct *fsp,
-                                   uint32 security_info, SEC_DESC **ppdesc)
+                                   uint32 security_info,
+                                   struct security_descriptor **ppdesc)
 {
        NTSTATUS result;
 
@@ -1359,7 +1310,8 @@ static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
 
 static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
                                   const char *name,
-                                  uint32 security_info, SEC_DESC **ppdesc)
+                                  uint32 security_info,
+                                  struct security_descriptor **ppdesc)
 {
        NTSTATUS result;
 
@@ -1369,7 +1321,7 @@ static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
        return result;
 }
 
-static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
+static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
 {
        NTSTATUS result;