diff options
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 3 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_rename.c | 122 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_util.c | 81 |
3 files changed, 196 insertions, 10 deletions
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index af0f46ece3..b07922dcbd 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -1118,8 +1118,7 @@ NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, struct pvfs_filename *name) status = odb_can_open(pvfs->odb_context, &key, NTCREATEX_SHARE_ACCESS_READ | - NTCREATEX_SHARE_ACCESS_WRITE | - NTCREATEX_SHARE_ACCESS_DELETE, + NTCREATEX_SHARE_ACCESS_WRITE, 0, STD_RIGHT_DELETE_ACCESS); diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c index d36af2b91d..aae17f327c 100644 --- a/source4/ntvfs/posix/pvfs_rename.c +++ b/source4/ntvfs/posix/pvfs_rename.c @@ -174,7 +174,6 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, return NT_STATUS_NO_MEMORY; } - /* finally try the actual rename */ if (rename(name1->full_name, fname2) == -1) { talloc_free(mem_ctx); return pvfs_map_errno(pvfs, errno); @@ -241,19 +240,15 @@ static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs, } /* - rename a set of files + rename a set of files - SMBmv interface */ -NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs, - struct smbsrv_request *req, union smb_rename *ren) +static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, union smb_rename *ren) { struct pvfs_state *pvfs = ntvfs->private_data; NTSTATUS status; struct pvfs_filename *name1, *name2; - if (ren->generic.level != RAW_RENAME_RENAME) { - return NT_STATUS_INVALID_LEVEL; - } - /* resolve the cifs name to a posix name */ status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern1, 0, &name1); if (!NT_STATUS_IS_OK(status)) { @@ -281,6 +276,11 @@ NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs, return NT_STATUS_OBJECT_NAME_COLLISION; } + status = pvfs_match_attrib(pvfs, name1, ren->rename.in.attrib, 0); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = pvfs_can_rename(pvfs, name1); if (!NT_STATUS_IS_OK(status)) { return status; @@ -292,3 +292,109 @@ NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs, return NT_STATUS_OK; } + + +/* + rename a set of files - ntrename interface +*/ +static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, union smb_rename *ren) +{ + struct pvfs_state *pvfs = ntvfs->private_data; + NTSTATUS status; + struct pvfs_filename *name1, *name2; + + switch (ren->ntrename.in.flags) { + case RENAME_FLAG_RENAME: + case RENAME_FLAG_HARD_LINK: + case RENAME_FLAG_COPY: + case RENAME_FLAG_MOVE_CLUSTER_INFORMATION: + break; + default: + return NT_STATUS_ACCESS_DENIED; + } + + /* resolve the cifs name to a posix name */ + status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.old_name, 0, &name1); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.new_name, 0, &name2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (name1->has_wildcard || name2->has_wildcard) { + return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; + } + + if (!name1->exists) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (strcmp(name1->full_name, name2->full_name) == 0) { + return NT_STATUS_OK; + } + + if (name2->exists) { + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + status = pvfs_match_attrib(pvfs, name1, ren->ntrename.in.attrib, 0); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = pvfs_can_rename(pvfs, name1); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (ren->ntrename.in.flags) { + case RENAME_FLAG_RENAME: + if (rename(name1->full_name, name2->full_name) == -1) { + return pvfs_map_errno(pvfs, errno); + } + break; + + case RENAME_FLAG_HARD_LINK: + if (link(name1->full_name, name2->full_name) == -1) { + return pvfs_map_errno(pvfs, errno); + } + break; + + case RENAME_FLAG_COPY: + return pvfs_copy_file(pvfs, name1, name2); + + case RENAME_FLAG_MOVE_CLUSTER_INFORMATION: + return NT_STATUS_INVALID_PARAMETER; + + default: + return NT_STATUS_ACCESS_DENIED; + } + + + return NT_STATUS_OK; +} + +/* + rename a set of files - ntrename interface +*/ +NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, union smb_rename *ren) +{ + switch (ren->generic.level) { + case RAW_RENAME_RENAME: + return pvfs_rename_mv(ntvfs, req, ren); + + case RAW_RENAME_NTRENAME: + return pvfs_rename_nt(ntvfs, req, ren); + + default: + break; + } + + return NT_STATUS_INVALID_LEVEL; +} + diff --git a/source4/ntvfs/posix/pvfs_util.c b/source4/ntvfs/posix/pvfs_util.c index 92d696970a..6503769013 100644 --- a/source4/ntvfs/posix/pvfs_util.c +++ b/source4/ntvfs/posix/pvfs_util.c @@ -79,3 +79,84 @@ uint32_t pvfs_attrib_normalise(uint32_t attrib) return attrib; } + +/* + copy a file. Caller is supposed to have already ensured that the + operation is allowed. The destination file must not exist. +*/ +NTSTATUS pvfs_copy_file(struct pvfs_state *pvfs, + struct pvfs_filename *name1, + struct pvfs_filename *name2) +{ + int fd1, fd2; + mode_t mode; + NTSTATUS status; + size_t buf_size = 0x10000; + char *buf = talloc(name2, buf_size); + + if (buf == NULL) { + return NT_STATUS_NO_MEMORY; + } + + fd1 = open(name1->full_name, O_RDONLY); + if (fd1 == -1) { + talloc_free(buf); + return pvfs_map_errno(pvfs, errno); + } + + fd2 = open(name2->full_name, O_CREAT|O_EXCL|O_WRONLY, 0); + if (fd2 == -1) { + close(fd1); + talloc_free(buf); + return pvfs_map_errno(pvfs, errno); + } + + while (1) { + ssize_t ret2, ret = read(fd1, buf, buf_size); + if (ret == -1 && + (errno == EINTR || errno == EAGAIN)) { + continue; + } + if (ret <= 0) break; + + ret2 = write(fd2, buf, ret); + if (ret2 == -1 && + (errno == EINTR || errno == EAGAIN)) { + continue; + } + + if (ret2 != ret) { + close(fd1); + close(fd2); + talloc_free(buf); + unlink(name2->full_name); + if (ret2 == -1) { + return pvfs_map_errno(pvfs, errno); + } + return NT_STATUS_DISK_FULL; + } + } + + close(fd1); + + mode = pvfs_fileperms(pvfs, name1->dos.attrib); + if (fchmod(fd2, mode) == -1) { + status = pvfs_map_errno(pvfs, errno); + close(fd2); + unlink(name2->full_name); + return status; + } + + name2->dos = name1->dos; + + status = pvfs_dosattrib_save(pvfs, name2, fd2); + if (!NT_STATUS_IS_OK(status)) { + close(fd2); + unlink(name2->full_name); + return status; + } + + close(fd2); + + return NT_STATUS_OK; +} |