s4-streams: fixed handling of stream rename and overwrite
[ira/wip.git] / source4 / ntvfs / posix / pvfs_rename.c
index 29b2d030059a2ca5e8a110de8c0cc559308e2f7f..d963357cbabd2ad4d0cd18537d6ae153c2746689 100644 (file)
@@ -103,7 +103,7 @@ static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx,
        char *dest, *d;
 
        /* the length is bounded by the length of the two strings combined */
-       dest = talloc_size(mem_ctx, strlen(fname) + strlen(pattern) + 1);
+       dest = talloc_array(mem_ctx, char, strlen(fname) + strlen(pattern) + 1);
        if (dest == NULL) {
                return NULL;
        }
@@ -115,16 +115,16 @@ static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx,
        while (*p2) {
                codepoint_t c1, c2;
                size_t c_size1, c_size2;
-               c1 = next_codepoint(iconv_convenience, p1, &c_size1);
-               c2 = next_codepoint(iconv_convenience, p2, &c_size2);
+               c1 = next_codepoint_convenience(iconv_convenience, p1, &c_size1);
+               c2 = next_codepoint_convenience(iconv_convenience, p2, &c_size2);
                if (c2 == '?') {
-                       d += push_codepoint(iconv_convenience, d, c1);
+                       d += push_codepoint_convenience(iconv_convenience, d, c1);
                } else if (c2 == '*') {
                        memcpy(d, p1, strlen(p1));
                        d += strlen(p1);
                        break;
                } else {
-                       d += push_codepoint(iconv_convenience, d, c2);
+                       d += push_codepoint_convenience(iconv_convenience, d, c2);
                }
 
                p1 += c_size1;
@@ -133,6 +133,8 @@ static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx,
 
        *d = 0;
 
+       talloc_set_name_const(dest, dest);
+
        return dest;
 }
 
@@ -247,7 +249,8 @@ static NTSTATUS pvfs_rename_setup_retry(struct ntvfs_module_context *ntvfs,
                                        struct odb_lock *lck,
                                        NTSTATUS status)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        struct timeval end_time;
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
@@ -287,7 +290,9 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
 
        /* get a pvfs_filename source object */
        status = pvfs_resolve_partial(pvfs, mem_ctx, 
-                                     dir_path, fname1, &name1);
+                                     dir_path, fname1,
+                                     PVFS_RESOLVE_NO_OPENDB,
+                                     &name1);
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
        }
@@ -306,7 +311,9 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
 
        /* get a pvfs_filename dest object */
        status = pvfs_resolve_partial(pvfs, mem_ctx, 
-                                     dir_path, fname2, &name2);
+                                     dir_path, fname2,
+                                     PVFS_RESOLVE_NO_OPENDB,
+                                     &name2);
        if (NT_STATUS_IS_OK(status)) {
                status = pvfs_can_delete(pvfs, req, name2, NULL);
                if (!NT_STATUS_IS_OK(status)) {
@@ -389,7 +396,8 @@ static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs,
 static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
                               struct ntvfs_request *req, union smb_rename *ren)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        NTSTATUS status;
        struct pvfs_filename *name1, *name2;
        struct odb_lock *lck = NULL;
@@ -459,13 +467,69 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
 }
 
 
+/*
+  rename a stream
+*/
+static NTSTATUS pvfs_rename_stream(struct ntvfs_module_context *ntvfs,
+                                  struct ntvfs_request *req, union smb_rename *ren,
+                                  struct pvfs_filename *name1)
+{
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
+       NTSTATUS status;
+       struct odb_lock *lck = NULL;
+
+       if (name1->has_wildcard) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (ren->ntrename.in.new_name[0] != ':') {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (!name1->exists) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       if (ren->ntrename.in.flags != RENAME_FLAG_RENAME) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       status = pvfs_can_rename(pvfs, req, name1, &lck);
+       /*
+        * on a sharing violation we need to retry when the file is closed by
+        * the other user, or after 1 second
+        * on a non granted oplock we need to retry when the file is closed by
+        * the other user, or after 30 seconds
+        */
+       if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
+           (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+               return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = pvfs_access_check_simple(pvfs, req, name1, SEC_FILE_WRITE_ATTRIBUTE);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = pvfs_stream_rename(pvfs, name1, -1, 
+                                   ren->ntrename.in.new_name+1, 
+                                   true);
+       NT_STATUS_NOT_OK_RETURN(status);
+       
+       return NT_STATUS_OK;
+}
+
 /*
   rename a set of files - ntrename interface
 */
 static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
                               struct ntvfs_request *req, union smb_rename *ren)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        NTSTATUS status;
        struct pvfs_filename *name1, *name2;
        struct odb_lock *lck = NULL;
@@ -482,11 +546,16 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
 
        /* resolve the cifs name to a posix name */
        status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.old_name, 
-                                  PVFS_RESOLVE_WILDCARD, &name1);
+                                  PVFS_RESOLVE_WILDCARD | PVFS_RESOLVE_STREAMS, &name1);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
+       if (name1->stream_name) {
+               /* stream renames need to be handled separately */
+               return pvfs_rename_stream(ntvfs, req, ren, name1);
+       }
+
        status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.new_name, 
                                   PVFS_RESOLVE_WILDCARD, &name2);
        if (!NT_STATUS_IS_OK(status)) {
@@ -568,6 +637,10 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
 NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
                     struct ntvfs_request *req, union smb_rename *ren)
 {
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
+       struct pvfs_file *f;
+
        switch (ren->generic.level) {
        case RAW_RENAME_RENAME:
                return pvfs_rename_mv(ntvfs, req, ren);
@@ -575,6 +648,15 @@ NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
        case RAW_RENAME_NTRENAME:
                return pvfs_rename_nt(ntvfs, req, ren);
 
+       case RAW_RENAME_NTTRANS:
+               f = pvfs_find_fd(pvfs, req, ren->nttrans.in.file.ntvfs);
+               if (!f) {
+                       return NT_STATUS_INVALID_HANDLE;
+               }
+
+               /* wk23 ignores the request */
+               return NT_STATUS_OK;
+
        default:
                break;
        }