From 1c59d825afc3cdfe2ea42821123ece934ad7b5e0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 13 Nov 2004 05:47:27 +0000 Subject: 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) --- source4/ntvfs/posix/pvfs_rename.c | 225 +++++++++++++++++++++++++++++++++++++- 1 file changed, 222 insertions(+), 3 deletions(-) (limited to 'source4/ntvfs/posix/pvfs_rename.c') 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; } -- cgit