summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-11-13 05:47:27 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:05:46 -0500
commit1c59d825afc3cdfe2ea42821123ece934ad7b5e0 (patch)
tree43eeda9448035f46ebbd8fcbb881a876d7fcba81
parent1158268287f07310e79e9d470971dc021a334f9e (diff)
downloadsamba-1c59d825afc3cdfe2ea42821123ece934ad7b5e0.tar.gz
samba-1c59d825afc3cdfe2ea42821123ece934ad7b5e0.tar.bz2
samba-1c59d825afc3cdfe2ea42821123ece934ad7b5e0.zip
r3717: - expanded the RAW-RENAME test a little
- added support for wildcard rename in pvfs - made more consistent use of pvfs_map_errno() (This used to be commit e255d1c3a811c480a850452aaf636d9fa36f69fe)
-rw-r--r--source4/ntvfs/posix/pvfs_open.c2
-rw-r--r--source4/ntvfs/posix/pvfs_rename.c225
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c2
-rw-r--r--source4/ntvfs/posix/pvfs_write.c2
-rw-r--r--source4/ntvfs/posix/pvfs_xattr.c33
-rw-r--r--source4/torture/raw/rename.c49
6 files changed, 291 insertions, 22 deletions
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index cc4498eee1..af0f46ece3 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -937,7 +937,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
mode_t mode = pvfs_fileperms(pvfs, attrib);
if (fchmod(fd, mode) == -1) {
talloc_free(lck);
- return map_nt_error_from_unix(errno);
+ return pvfs_map_errno(pvfs, errno);
}
name->dos.attrib = attrib;
status = pvfs_dosattrib_save(pvfs, name, fd);
diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c
index a621165ce4..d36af2b91d 100644
--- a/source4/ntvfs/posix/pvfs_rename.c
+++ b/source4/ntvfs/posix/pvfs_rename.c
@@ -23,6 +23,223 @@
#include "includes.h"
#include "vfs_posix.h"
+
+/*
+ resolve a wildcard rename pattern. This works on one component of the name
+*/
+static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx,
+ const char *fname,
+ const char *pattern)
+{
+ const char *p1, *p2;
+ char *dest, *d;
+
+ /* the length is bounded by the length of the two strings combined */
+ dest = talloc(mem_ctx, strlen(fname) + strlen(pattern) + 1);
+ if (dest == NULL) {
+ return NULL;
+ }
+
+ p1 = fname;
+ p2 = pattern;
+ d = dest;
+
+ while (*p2) {
+ codepoint_t c1, c2;
+ size_t c_size1, c_size2;
+ c1 = next_codepoint(p1, &c_size1);
+ c2 = next_codepoint(p2, &c_size2);
+ if (c2 == '?') {
+ d += push_codepoint(d, c1);
+ } else if (c2 == '*') {
+ memcpy(d, p1, strlen(p1));
+ d += strlen(p1);
+ break;
+ } else {
+ d += push_codepoint(d, c2);
+ }
+
+ p1 += c_size1;
+ p2 += c_size2;
+ }
+
+ *d = 0;
+
+ return dest;
+}
+
+/*
+ resolve a wildcard rename pattern.
+*/
+static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx,
+ const char *fname,
+ const char *pattern)
+{
+ const char *base1, *base2;
+ const char *ext1, *ext2;
+ char *p;
+
+ /* break into base part plus extension */
+ p = strrchr_m(fname, '.');
+ if (p == NULL) {
+ ext1 = "";
+ base1 = fname;
+ } else {
+ ext1 = talloc_strdup(mem_ctx, p+1);
+ base1 = talloc_strndup(mem_ctx, fname, p-fname);
+ }
+ if (ext1 == NULL || base1 == NULL) {
+ return NULL;
+ }
+
+ p = strrchr_m(pattern, '.');
+ if (p == NULL) {
+ ext2 = "";
+ base2 = fname;
+ } else {
+ ext2 = talloc_strdup(mem_ctx, p+1);
+ base2 = talloc_strndup(mem_ctx, pattern, p-pattern);
+ }
+ if (ext2 == NULL || base2 == NULL) {
+ return NULL;
+ }
+
+ base1 = pvfs_resolve_wildcard_component(mem_ctx, base1, base2);
+ ext1 = pvfs_resolve_wildcard_component(mem_ctx, ext1, ext2);
+ if (base1 == NULL || ext1 == NULL) {
+ return NULL;
+ }
+
+ if (*ext1 == 0) {
+ return base1;
+ }
+
+ return talloc_asprintf(mem_ctx, "%s.%s", base1, ext1);
+}
+
+/*
+ rename one file from a wildcard set
+*/
+static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
+ struct smbsrv_request *req,
+ const char *dir_path,
+ const char *fname1,
+ const char *fname2,
+ uint16_t attrib)
+{
+ struct pvfs_filename *name1, *name2;
+ TALLOC_CTX *mem_ctx = talloc(req, 0);
+ NTSTATUS status;
+
+ /* resolve the wildcard pattern for this name */
+ fname2 = pvfs_resolve_wildcard(mem_ctx, fname1, fname2);
+ if (fname2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* get a pvfs_filename source object */
+ status = pvfs_resolve_partial(pvfs, mem_ctx,
+ dir_path, fname1, &name1);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* make sure its matches the given attributes */
+ status = pvfs_match_attrib(pvfs, name1, attrib, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ status = pvfs_can_rename(pvfs, name1);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* get a pvfs_filename dest object */
+ status = pvfs_resolve_partial(pvfs, mem_ctx,
+ dir_path, fname2, &name2);
+ if (NT_STATUS_IS_OK(status)) {
+ status = pvfs_can_delete(pvfs, name2);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+ }
+
+ fname2 = talloc_asprintf(mem_ctx, "%s/%s", dir_path, fname2);
+ if (fname2 == NULL) {
+ 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);
+ }
+
+ talloc_free(mem_ctx);
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ rename a set of files with wildcards
+*/
+static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs,
+ struct smbsrv_request *req,
+ union smb_rename *ren,
+ struct pvfs_filename *name1,
+ struct pvfs_filename *name2)
+{
+ struct pvfs_dir *dir;
+ NTSTATUS status;
+ uint_t ofs = 0;
+ const char *fname, *fname2, *dir_path;
+ uint16_t attrib = ren->rename.in.attrib;
+ int total_renamed = 0;
+
+ /* get list of matching files */
+ status = pvfs_list_start(pvfs, name1, req, &dir);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = NT_STATUS_NO_SUCH_FILE;
+
+ dir_path = pvfs_list_unix_path(dir);
+
+ /* only allow wildcard renames within a directory */
+ if (strncmp(dir_path, name2->full_name, strlen(dir_path)) != 0 ||
+ name2->full_name[strlen(dir_path)] != '/' ||
+ strchr(name2->full_name + strlen(dir_path) + 1, '/')) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ fname2 = talloc_strdup(name2, name2->full_name + strlen(dir_path) + 1);
+ if (fname2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while ((fname = pvfs_list_next(dir, &ofs))) {
+ status = pvfs_rename_one(pvfs, req,
+ dir_path,
+ fname, fname2, attrib);
+ if (NT_STATUS_IS_OK(status)) {
+ total_renamed++;
+ }
+ }
+
+ if (total_renamed == 0) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
/*
rename a set of files
*/
@@ -49,15 +266,17 @@ NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
}
if (name1->has_wildcard || name2->has_wildcard) {
- DEBUG(3,("Rejecting wildcard rename '%s' -> '%s'\n",
- ren->rename.in.pattern1, ren->rename.in.pattern2));
- return NT_STATUS_NOT_SUPPORTED;
+ return pvfs_rename_wildcard(pvfs, req, ren, name1, name2);
}
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;
}
diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c
index 391a2e9d82..e54c37741c 100644
--- a/source4/ntvfs/posix/pvfs_setfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_setfileinfo.c
@@ -96,7 +96,7 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
}
if (rename(name->full_name, name2->full_name) == -1) {
- return map_nt_error_from_unix(errno);
+ return pvfs_map_errno(pvfs, errno);
}
name->full_name = talloc_steal(name, name2->full_name);
diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c
index 989e8d7b1b..c24de08a13 100644
--- a/source4/ntvfs/posix/pvfs_write.c
+++ b/source4/ntvfs/posix/pvfs_write.c
@@ -68,7 +68,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
if (errno == EFBIG) {
return NT_STATUS_INVALID_PARAMETER;
}
- return map_nt_error_from_unix(errno);
+ return pvfs_map_errno(pvfs, errno);
}
f->handle->seek_offset = wr->writex.in.offset + ret;
diff --git a/source4/ntvfs/posix/pvfs_xattr.c b/source4/ntvfs/posix/pvfs_xattr.c
index f4063b48b5..d5a7d17a31 100644
--- a/source4/ntvfs/posix/pvfs_xattr.c
+++ b/source4/ntvfs/posix/pvfs_xattr.c
@@ -28,7 +28,8 @@
/*
pull a xattr as a blob, from either a file or a file descriptor
*/
-static NTSTATUS pull_xattr_blob(TALLOC_CTX *mem_ctx,
+static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
+ TALLOC_CTX *mem_ctx,
const char *attr_name,
const char *fname,
int fd,
@@ -61,7 +62,7 @@ again:
if (ret == -1) {
data_blob_free(blob);
- return map_nt_error_from_unix(errno);
+ return pvfs_map_errno(pvfs, errno);
}
blob->length = ret;
@@ -75,7 +76,8 @@ again:
/*
push a xattr as a blob, from either a file or a file descriptor
*/
-static NTSTATUS push_xattr_blob(const char *attr_name,
+static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
+ const char *attr_name,
const char *fname,
int fd,
const DATA_BLOB *blob)
@@ -89,7 +91,7 @@ static NTSTATUS push_xattr_blob(const char *attr_name,
ret = setxattr(fname, attr_name, blob->data, blob->length, 0);
}
if (ret == -1) {
- return map_nt_error_from_unix(errno);
+ return pvfs_map_errno(pvfs, errno);
}
return NT_STATUS_OK;
@@ -101,14 +103,15 @@ static NTSTATUS push_xattr_blob(const char *attr_name,
/*
load a NDR structure from a xattr
*/
-static NTSTATUS pvfs_xattr_ndr_load(TALLOC_CTX *mem_ctx,
+static NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
+ TALLOC_CTX *mem_ctx,
const char *fname, int fd, const char *attr_name,
void *p, ndr_pull_flags_fn_t pull_fn)
{
NTSTATUS status;
DATA_BLOB blob;
- status = pull_xattr_blob(mem_ctx, attr_name, fname,
+ status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -125,7 +128,8 @@ static NTSTATUS pvfs_xattr_ndr_load(TALLOC_CTX *mem_ctx,
/*
save a NDR structure into a xattr
*/
-static NTSTATUS pvfs_xattr_ndr_save(const char *fname, int fd, const char *attr_name,
+static NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
+ const char *fname, int fd, const char *attr_name,
void *p, ndr_push_flags_fn_t push_fn)
{
TALLOC_CTX *mem_ctx = talloc(NULL, 0);
@@ -138,7 +142,7 @@ static NTSTATUS pvfs_xattr_ndr_save(const char *fname, int fd, const char *attr_
return status;
}
- status = push_xattr_blob(attr_name, fname, fd, &blob);
+ status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
talloc_free(mem_ctx);
return status;
@@ -159,8 +163,10 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name
return NT_STATUS_OK;
}
- status = pvfs_xattr_ndr_load(mem_ctx, name->full_name, fd, XATTR_DOSATTRIB_NAME,
- &attrib, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
+ status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
+ fd, XATTR_DOSATTRIB_NAME,
+ &attrib,
+ (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
/* if the filesystem doesn't support them, then tell pvfs not to try again */
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
@@ -233,7 +239,8 @@ NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name
info1->create_time = name->dos.create_time;
info1->change_time = name->dos.change_time;
- return pvfs_xattr_ndr_save(name->full_name, fd, XATTR_DOSATTRIB_NAME, &attrib,
+ return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
+ XATTR_DOSATTRIB_NAME, &attrib,
(ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
}
@@ -249,7 +256,7 @@ NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, i
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
return NT_STATUS_OK;
}
- status = pvfs_xattr_ndr_load(eas, name->full_name, fd, XATTR_DOSEAS_NAME,
+ status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
return NT_STATUS_OK;
@@ -266,6 +273,6 @@ NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, i
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
return NT_STATUS_OK;
}
- return pvfs_xattr_ndr_save(name->full_name, fd, XATTR_DOSEAS_NAME, eas,
+ return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
(ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
}
diff --git a/source4/torture/raw/rename.c b/source4/torture/raw/rename.c
index 68bd2eda2d..c3fc739d6a 100644
--- a/source4/torture/raw/rename.c
+++ b/source4/torture/raw/rename.c
@@ -48,6 +48,7 @@ static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
int fnum;
const char *fname1 = BASEDIR "\\test1.txt";
const char *fname2 = BASEDIR "\\test2.txt";
+ union smb_open op;
printf("Testing SMBmv\n");
@@ -57,16 +58,58 @@ static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
printf("Trying simple rename\n");
- fnum = create_complex_file(cli, mem_ctx, fname1);
-
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_RIGHT_MAXIMUM_ALLOWED;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname1;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.fnum;
+
io.generic.level = RAW_RENAME_RENAME;
io.rename.in.pattern1 = fname1;
io.rename.in.pattern2 = fname2;
io.rename.in.attrib = 0;
+ printf("trying rename while first file open\n");
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
-
+
+ smbcli_close(cli->tree, fnum);
+
+ op.ntcreatex.in.access_mask = GENERIC_RIGHTS_FILE_READ;
+ op.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb_raw_open(cli->tree, mem_ctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.fnum;
+
+ printf("trying rename while first file open with SHARE_ACCESS_DELETE\n");
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.rename.in.pattern1 = fname2;
+ io.rename.in.pattern2 = fname1;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.rename.in.pattern1 = fname1;
+ io.rename.in.pattern2 = fname2;
+
+ printf("trying rename while not open\n");
smb_raw_exit(cli->session);
status = smb_raw_rename(cli->tree, &io);
CHECK_STATUS(status, NT_STATUS_OK);