smbd: Fix a typo in a few places
[samba.git] / source3 / modules / vfs_crossrename.c
index 9bb42b9958ee9c793f342736dbbd97b378aa1a30..042144bfc4df9264a0f968fd9ca1a5c413316bf6 100644 (file)
@@ -48,156 +48,145 @@ static int crossrename_connect(
  <warrenb@hpcvscdp.cv.hp.com>
 **********************************************************/
 
-static int copy_reg(const char *source, const char *dest)
+static NTSTATUS copy_reg(vfs_handle_struct *handle,
+                        struct files_struct *srcfsp,
+                        const struct smb_filename *source,
+                        struct files_struct *dstfsp,
+                        const struct smb_filename *dest)
 {
-       SMB_STRUCT_STAT source_stats;
-       int saved_errno;
-       int ifd = -1;
-       int ofd = -1;
-
-       if (sys_lstat(source, &source_stats, false) == -1)
-               return -1;
-
-       if (!S_ISREG (source_stats.st_ex_mode))
-               return -1;
-
-       if (source_stats.st_ex_size > module_sizelimit) {
-               DEBUG(5,
-                       ("%s: size of %s larger than sizelimit (%lld > %lld), rename prohititted\n",
-                       MODULE, source,
-                       (long long)source_stats.st_ex_size,
-                       (long long)module_sizelimit));
-               return -1;
-       }
-
-       if((ifd = open (source, O_RDONLY, 0)) < 0)
-               return -1;
+       NTSTATUS status;
+       struct smb_filename *full_fname_src = NULL;
+       struct smb_filename *full_fname_dst = NULL;
+       int ret;
 
-       if (unlink (dest) && errno != ENOENT) {
-               close(ifd);
-               return -1;
+       if (!VALID_STAT(source->st)) {
+               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               goto out;
+       }
+       if (!S_ISREG(source->st.st_ex_mode)) {
+               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               goto out;
        }
 
-#ifdef O_NOFOLLOW
-       if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 )
-#else
-       if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 )
-#endif
-               goto err;
-
-       if (transfer_file(ifd, ofd, source_stats.st_ex_size) == -1)
-               goto err;
+       if (source->st.st_ex_size > module_sizelimit) {
+               DBG_INFO("%s: size of %s larger than sizelimit (%lld > %lld), "
+                        "rename prohibited\n",
+                       MODULE,
+                       source->base_name,
+                       (long long)source->st.st_ex_size,
+                       (long long)module_sizelimit);
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto out;
+       }
 
-       /*
-        * 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.
-        */
+       full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
+                                                     srcfsp,
+                                                     source);
+       if (full_fname_src == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+       full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
+                                                     dstfsp,
+                                                     dest);
+       if (full_fname_dst == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
 
-#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;
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                                   dstfsp,
+                                   dest,
+                                   0);
+       if (ret == -1) {
+               status = map_nt_error_from_unix(errno);
+               goto out;
+       }
 
        /*
-        * fchown turns off set[ug]id bits for non-root,
-        * so do the chmod last.
+        * copy_internals() takes attribute values from the NTrename call.
+        *
+        * From MS-CIFS:
+        *
+        * "If the attribute is 0x0000, then only normal files are renamed.
+        * If the system file or hidden attributes are specified, then the
+        * rename is inclusive of both special types."
         */
-
-#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.  */
-#if defined(HAVE_UTIMENSAT)
-       {
-               struct timespec ts[2];
-
-               ts[0] = source_stats.st_ex_atime;
-               ts[1] = source_stats.st_ex_mtime;
-               utimensat(AT_FDCWD, dest, ts, AT_SYMLINK_NOFOLLOW);
-       }
-#elif defined(HAVE_UTIMES)
-       {
-               struct timeval tv[2];
-
-               tv[0] = convert_timespec_to_timeval(source_stats.st_ex_atime);
-               tv[1] = convert_timespec_to_timeval(source_stats.st_ex_mtime);
-#ifdef HAVE_LUTIMES
-               lutimes(dest, tv);
-#else
-               utimes(dest, tv);
-#endif
+       status = copy_internals(talloc_tos(),
+                               handle->conn,
+                               NULL,
+                               srcfsp, /* src_dirfsp */
+                               full_fname_src,
+                               dstfsp, /* dst_dirfsp */
+                               full_fname_dst,
+                               FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
-#elif defined(HAVE_UTIME)
-       {
-               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);
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                                   srcfsp,
+                                   source,
+                                   0);
+       if (ret == -1) {
+               status = map_nt_error_from_unix(errno);
+               goto out;
        }
-#endif
-
-       if (unlink (source) == -1)
-               return -1;
-
-       return 0;
 
-  err:
+  out:
 
-       saved_errno = errno;
-       if (ifd != -1)
-               close(ifd);
-       if (ofd != -1)
-               close(ofd);
-       errno = saved_errno;
-       return -1;
+       TALLOC_FREE(full_fname_src);
+       TALLOC_FREE(full_fname_dst);
+       return status;
 }
 
-
-static int crossrename_rename(vfs_handle_struct *handle,
-                         const struct smb_filename *smb_fname_src,
-                         const struct smb_filename *smb_fname_dst)
+static int crossrename_renameat(vfs_handle_struct *handle,
+                       files_struct *srcfsp,
+                       const struct smb_filename *smb_fname_src,
+                       files_struct *dstfsp,
+                       const struct smb_filename *smb_fname_dst)
 {
        int result = -1;
 
-       START_PROFILE(syscall_rename);
+       START_PROFILE(syscall_renameat);
 
        if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
                errno = ENOENT;
                goto out;
        }
 
-       result = rename(smb_fname_src->base_name, smb_fname_dst->base_name);
+       result = SMB_VFS_NEXT_RENAMEAT(handle,
+                                      srcfsp,
+                                      smb_fname_src,
+                                      dstfsp,
+                                      smb_fname_dst);
+
        if ((result == -1) && (errno == EXDEV)) {
                /* Rename across filesystems needed. */
-               result = copy_reg(smb_fname_src->base_name,
-                                 smb_fname_dst->base_name);
+               NTSTATUS status = copy_reg(handle,
+                                          srcfsp,
+                                          smb_fname_src,
+                                          dstfsp,
+                                          smb_fname_dst);
+               if (!NT_STATUS_IS_OK(status)) {
+                       errno = map_errno_from_nt_status(status);
+                       result = -1;
+               }
        }
 
  out:
-       END_PROFILE(syscall_rename);
+       END_PROFILE(syscall_renameat);
        return result;
 }
 
+
 static struct vfs_fn_pointers vfs_crossrename_fns = {
        .connect_fn = crossrename_connect,
-       .rename_fn = crossrename_rename
+       .renameat_fn = crossrename_renameat
 };
 
-NTSTATUS vfs_crossrename_init(void);
-NTSTATUS vfs_crossrename_init(void)
+static_decl_vfs;
+NTSTATUS vfs_crossrename_init(TALLOC_CTX *ctx)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE,
                                &vfs_crossrename_fns);