<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_dst == 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) == -1) &&
- (errno != EPERM))
-#else
- if ((chmod (dest, source_stats.st_ex_mode & 07777) == -1) &&
- (errno != EPERM))
-#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,
+ full_fname_src,
+ 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_renameat(vfs_handle_struct *handle,
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: