mirror of
https://github.com/samba-team/samba.git
synced 2025-01-13 13:18:06 +03:00
r3718: added support for the ntrename level in pvfs_rename().
This commit is contained in:
parent
e255d1c3a8
commit
3d50982f54
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user