summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix/pvfs_rename.c
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 /source4/ntvfs/posix/pvfs_rename.c
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)
Diffstat (limited to 'source4/ntvfs/posix/pvfs_rename.c')
-rw-r--r--source4/ntvfs/posix/pvfs_rename.c225
1 files changed, 222 insertions, 3 deletions
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;
}