r3717: - expanded the RAW-RENAME test a little
authorAndrew Tridgell <tridge@samba.org>
Sat, 13 Nov 2004 05:47:27 +0000 (05:47 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:05:46 +0000 (13:05 -0500)
- added support for wildcard rename in pvfs

- made more consistent use of pvfs_map_errno()

source/ntvfs/posix/pvfs_open.c
source/ntvfs/posix/pvfs_rename.c
source/ntvfs/posix/pvfs_setfileinfo.c
source/ntvfs/posix/pvfs_write.c
source/ntvfs/posix/pvfs_xattr.c
source/torture/raw/rename.c

index cc4498eee1b9d14ab18e84d0001a1275c0ca6031..af0f46ece32711295173502eb259192add68b724 100644 (file)
@@ -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);
index a621165ce43f720ab32adcd0f966e96ee96a5440..d36af2b91d93950372096692ab74827e019e33ce 100644 (file)
 #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;
        }
index 391a2e9d820b6dec3d4fa508853afa69bbcce6ff..e54c37741c1cee9e79c0fd3f8c6e60d69c4c4e3f 100644 (file)
@@ -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);
index 989e8d7b1b77fd75ea7e8376d0db8234ba6b9589..c24de08a13473e47de455d11114c3136357c05aa 100644 (file)
@@ -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;
index f4063b48b595f1a88b1623e03aecbd83e2af202f..d5a7d17a31e6bfff170e6a09dcacccc1dd487395 100644 (file)
@@ -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);
 }
index 68bd2eda2daa75cbc635d0e6233e48519a68991c..c3fc739d6ade7a59e3fa6c77e5efff489315549b 100644 (file)
@@ -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);