Merge commit 'release-4-0-0alpha2' into v4-0-test
[gd/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_rename.c
index f8d0ba1c279a9ca06ce621120685dcaf0e11d117..3b9842db7f22a54d67779447eaae27700237b021 100644 (file)
@@ -7,7 +7,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "vfs_posix.h"
+#include "librpc/gen_ndr/security.h"
+#include "param/param.h"
+
+
+/*
+  do a file rename, and send any notify triggers
+*/
+NTSTATUS pvfs_do_rename(struct pvfs_state *pvfs, const struct pvfs_filename *name1, 
+                       const char *name2)
+{
+       const char *r1, *r2;
+       uint32_t mask;
+
+       if (rename(name1->full_name, name2) == -1) {
+               return pvfs_map_errno(pvfs, errno);
+       }
+
+       if (name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
+               mask = FILE_NOTIFY_CHANGE_DIR_NAME;
+       } else {
+               mask = FILE_NOTIFY_CHANGE_FILE_NAME;
+       }
+       /* 
+          renames to the same directory cause a OLD_NAME->NEW_NAME notify.
+          renames to a different directory are considered a remove/add 
+       */
+       r1 = strrchr_m(name1->full_name, '/');
+       r2 = strrchr_m(name2, '/');
+
+       if ((r1-name1->full_name) != (r2-name2) ||
+           strncmp(name1->full_name, name2, r1-name1->full_name) != 0) {
+               notify_trigger(pvfs->notify_context, 
+                              NOTIFY_ACTION_REMOVED, 
+                              mask,
+                              name1->full_name);
+               notify_trigger(pvfs->notify_context, 
+                              NOTIFY_ACTION_ADDED, 
+                              mask,
+                              name2);
+       } else {
+               notify_trigger(pvfs->notify_context, 
+                              NOTIFY_ACTION_OLD_NAME, 
+                              mask,
+                              name1->full_name);
+               notify_trigger(pvfs->notify_context, 
+                              NOTIFY_ACTION_NEW_NAME, 
+                              mask,
+                              name2);
+       }
+
+       /* this is a strange one. w2k3 gives an additional event for CHANGE_ATTRIBUTES
+          and CHANGE_CREATION on the new file when renaming files, but not 
+          directories */
+       if ((name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+               notify_trigger(pvfs->notify_context, 
+                              NOTIFY_ACTION_MODIFIED, 
+                              FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION,
+                              name2);
+       }
+       
+       return NT_STATUS_OK;
+}
 
 
 /*
@@ -35,7 +96,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(mem_ctx, strlen(fname) + strlen(pattern) + 1);
+       dest = talloc_size(mem_ctx, strlen(fname) + strlen(pattern) + 1);
        if (dest == NULL) {
                return NULL;
        }
@@ -47,16 +108,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(p1, &c_size1);
-               c2 = next_codepoint(p2, &c_size2);
+               c1 = next_codepoint(lp_iconv_convenience(global_loadparm), p1, &c_size1);
+               c2 = next_codepoint(lp_iconv_convenience(global_loadparm), p2, &c_size2);
                if (c2 == '?') {
-                       d += push_codepoint(d, c1);
+                       d += push_codepoint(lp_iconv_convenience(global_loadparm), d, c1);
                } else if (c2 == '*') {
                        memcpy(d, p1, strlen(p1));
                        d += strlen(p1);
                        break;
                } else {
-                       d += push_codepoint(d, c2);
+                       d += push_codepoint(lp_iconv_convenience(global_loadparm), d, c2);
                }
 
                p1 += c_size1;
@@ -121,15 +182,16 @@ static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx,
   rename one file from a wildcard set
 */
 static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, 
-                               struct smbsrv_request *req, 
+                               struct ntvfs_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);
+       TALLOC_CTX *mem_ctx = talloc_new(req);
        NTSTATUS status;
+       struct odb_lock *lck, *lck2;
 
        /* resolve the wildcard pattern for this name */
        fname2 = pvfs_resolve_wildcard(mem_ctx, fname1, fname2);
@@ -150,7 +212,7 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
                goto failed;
        }
 
-       status = pvfs_can_rename(pvfs, name1);
+       status = pvfs_can_rename(pvfs, req, name1, &lck);
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
        }
@@ -159,7 +221,7 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
        status = pvfs_resolve_partial(pvfs, mem_ctx, 
                                      dir_path, fname2, &name2);
        if (NT_STATUS_IS_OK(status)) {
-               status = pvfs_can_delete(pvfs, req, name2);
+               status = pvfs_can_delete(pvfs, req, name2, &lck2);
                if (!NT_STATUS_IS_OK(status)) {
                        goto failed;
                }
@@ -172,9 +234,10 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (rename(name1->full_name, fname2) == -1) {
-               talloc_free(mem_ctx);
-               return pvfs_map_errno(pvfs, errno);
+       status = pvfs_do_rename(pvfs, name1, fname2);
+
+       if (NT_STATUS_IS_OK(status)) {
+               status = odb_rename(lck, fname2);
        }
 
 failed:
@@ -187,14 +250,14 @@ failed:
   rename a set of files with wildcards
 */
 static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs, 
-                                    struct smbsrv_request *req, 
+                                    struct ntvfs_request *req, 
                                     union smb_rename *ren, 
                                     struct pvfs_filename *name1, 
                                     struct pvfs_filename *name2)
 {
        struct pvfs_dir *dir;
        NTSTATUS status;
-       uint_t ofs = 0;
+       off_t ofs = 0;
        const char *fname, *fname2, *dir_path;
        uint16_t attrib = ren->rename.in.attrib;
        int total_renamed = 0;
@@ -241,11 +304,12 @@ static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs,
   rename a set of files - SMBmv interface
 */
 static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
-                              struct smbsrv_request *req, union smb_rename *ren)
+                              struct ntvfs_request *req, union smb_rename *ren)
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        NTSTATUS status;
        struct pvfs_filename *name1, *name2;
+       struct odb_lock *lck;
 
        /* resolve the cifs name to a posix name */
        status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern1, 
@@ -281,18 +345,19 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
                return status;
        }
 
-       status = pvfs_access_check_create(pvfs, req, name2);
+       status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       status = pvfs_can_rename(pvfs, name1);
+       status = pvfs_can_rename(pvfs, req, name1, &lck);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       if (rename(name1->full_name, name2->full_name) == -1) {
-               return pvfs_map_errno(pvfs, errno);
+       status = pvfs_do_rename(pvfs, name1, name2->full_name);
+       if (NT_STATUS_IS_OK(status)) {
+               status = odb_rename(lck, name2->full_name);
        }
        
        return NT_STATUS_OK;
@@ -303,11 +368,12 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
   rename a set of files - ntrename interface
 */
 static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
-                              struct smbsrv_request *req, union smb_rename *ren)
+                              struct ntvfs_request *req, union smb_rename *ren)
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        NTSTATUS status;
        struct pvfs_filename *name1, *name2;
+       struct odb_lock *lck;
 
        switch (ren->ntrename.in.flags) {
        case RENAME_FLAG_RENAME:
@@ -353,37 +419,30 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
                return status;
        }
 
-       status = pvfs_can_rename(pvfs, name1);
+       status = pvfs_can_rename(pvfs, req, name1, &lck);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
        switch (ren->ntrename.in.flags) {
        case RENAME_FLAG_RENAME:
-               status = pvfs_access_check_create(pvfs, req, name2);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-               if (rename(name1->full_name, name2->full_name) == -1) {
-                       return pvfs_map_errno(pvfs, errno);
-               }
+               status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
+               NT_STATUS_NOT_OK_RETURN(status);
+               status = pvfs_do_rename(pvfs, name1, name2->full_name);
+               NT_STATUS_NOT_OK_RETURN(status);
                break;
 
        case RENAME_FLAG_HARD_LINK:
-               status = pvfs_access_check_create(pvfs, req, name2);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+               status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
+               NT_STATUS_NOT_OK_RETURN(status);
                if (link(name1->full_name, name2->full_name) == -1) {
                        return pvfs_map_errno(pvfs, errno);
                }
                break;
 
        case RENAME_FLAG_COPY:
-               status = pvfs_access_check_create(pvfs, req, name2);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+               status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
+               NT_STATUS_NOT_OK_RETURN(status);
                return pvfs_copy_file(pvfs, name1, name2);
 
        case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
@@ -401,7 +460,7 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
   rename a set of files - ntrename interface
 */
 NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
-                    struct smbsrv_request *req, union smb_rename *ren)
+                    struct ntvfs_request *req, union smb_rename *ren)
 {
        switch (ren->generic.level) {
        case RAW_RENAME_RENAME: