LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_rename.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 235 282 83.3 %
Date: 2021-09-23 10:06:22 Functions: 11 14 78.6 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend - rename
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2004
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "vfs_posix.h"
      24             : #include "librpc/gen_ndr/security.h"
      25             : #include "param/param.h"
      26             : 
      27             : 
      28             : /*
      29             :   do a file rename, and send any notify triggers
      30             : */
      31         114 : NTSTATUS pvfs_do_rename(struct pvfs_state *pvfs,
      32             :                         struct odb_lock *lck,
      33             :                         const struct pvfs_filename *name1,
      34             :                         const char *name2)
      35             : {
      36             :         const char *r1, *r2;
      37             :         uint32_t mask;
      38             :         NTSTATUS status;
      39             : 
      40         114 :         if (pvfs_sys_rename(pvfs, name1->full_name, name2,
      41         114 :                             name1->allow_override) == -1) {
      42           0 :                 return pvfs_map_errno(pvfs, errno);
      43             :         }
      44             : 
      45         114 :         status = odb_rename(lck, name2);
      46         114 :         NT_STATUS_NOT_OK_RETURN(status);
      47             : 
      48         114 :         if (name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
      49          40 :                 mask = FILE_NOTIFY_CHANGE_DIR_NAME;
      50             :         } else {
      51          74 :                 mask = FILE_NOTIFY_CHANGE_FILE_NAME;
      52             :         }
      53             :         /* 
      54             :            renames to the same directory cause a OLD_NAME->NEW_NAME notify.
      55             :            renames to a different directory are considered a remove/add 
      56             :         */
      57         114 :         r1 = strrchr_m(name1->full_name, '/');
      58         114 :         r2 = strrchr_m(name2, '/');
      59             : 
      60         225 :         if ((r1-name1->full_name) != (r2-name2) ||
      61         112 :             strncmp(name1->full_name, name2, r1-name1->full_name) != 0) {
      62           2 :                 notify_trigger(pvfs->notify_context, 
      63             :                                NOTIFY_ACTION_REMOVED, 
      64             :                                mask,
      65           2 :                                name1->full_name);
      66           2 :                 notify_trigger(pvfs->notify_context, 
      67             :                                NOTIFY_ACTION_ADDED, 
      68             :                                mask,
      69             :                                name2);
      70             :         } else {
      71         112 :                 notify_trigger(pvfs->notify_context, 
      72             :                                NOTIFY_ACTION_OLD_NAME, 
      73             :                                mask,
      74         112 :                                name1->full_name);
      75         112 :                 notify_trigger(pvfs->notify_context, 
      76             :                                NOTIFY_ACTION_NEW_NAME, 
      77             :                                mask,
      78             :                                name2);
      79             :         }
      80             : 
      81             :         /* this is a strange one. w2k3 gives an additional event for CHANGE_ATTRIBUTES
      82             :            and CHANGE_CREATION on the new file when renaming files, but not 
      83             :            directories */
      84         114 :         if ((name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) == 0) {
      85          74 :                 notify_trigger(pvfs->notify_context, 
      86             :                                NOTIFY_ACTION_MODIFIED, 
      87             :                                FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION,
      88             :                                name2);
      89             :         }
      90             :         
      91         114 :         return NT_STATUS_OK;
      92             : }
      93             : 
      94             : 
      95             : /*
      96             :   resolve a wildcard rename pattern. This works on one component of the name
      97             : */
      98          10 : static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx, 
      99             :                                                    const char *fname, 
     100             :                                                    const char *pattern)
     101             : {
     102             :         const char *p1, *p2;
     103             :         char *dest, *d;
     104             : 
     105             :         /* the length is bounded by the length of the two strings combined */
     106          10 :         dest = talloc_array(mem_ctx, char, strlen(fname) + strlen(pattern) + 1);
     107          10 :         if (dest == NULL) {
     108           0 :                 return NULL;
     109             :         }
     110             : 
     111          10 :         p1 = fname;
     112          10 :         p2 = pattern;
     113          10 :         d = dest;
     114             : 
     115          45 :         while (*p2) {
     116             :                 codepoint_t c1, c2;
     117             :                 size_t c_size1, c_size2;
     118          28 :                 c1 = next_codepoint(p1, &c_size1);
     119          28 :                 c2 = next_codepoint(p2, &c_size2);
     120          28 :                 if (c2 == '?') {
     121           0 :                         d += push_codepoint(d, c1);
     122          28 :                 } else if (c2 == '*') {
     123           3 :                         memcpy(d, p1, strlen(p1));
     124           3 :                         d += strlen(p1);
     125           3 :                         break;
     126             :                 } else {
     127          25 :                         d += push_codepoint(d, c2);
     128             :                 }
     129             : 
     130          25 :                 p1 += c_size1;
     131          25 :                 p2 += c_size2;
     132             :         }
     133             : 
     134          10 :         *d = 0;
     135             : 
     136          10 :         talloc_set_name_const(dest, dest);
     137             : 
     138          10 :         return dest;
     139             : }
     140             : 
     141             : /*
     142             :   resolve a wildcard rename pattern.
     143             : */
     144           5 : static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx, 
     145             :                                          const char *fname, 
     146             :                                          const char *pattern)
     147             : {
     148             :         const char *base1, *base2;
     149             :         const char *ext1, *ext2;
     150             :         char *p;
     151             : 
     152             :         /* break into base part plus extension */
     153           5 :         p = strrchr_m(fname, '.');
     154           5 :         if (p == NULL) {
     155           0 :                 ext1 = "";
     156           0 :                 base1 = fname;
     157             :         } else {
     158           5 :                 ext1 = talloc_strdup(mem_ctx, p+1);
     159           5 :                 base1 = talloc_strndup(mem_ctx, fname, p-fname);
     160             :         }
     161           5 :         if (ext1 == NULL || base1 == NULL) {
     162           0 :                 return NULL;
     163             :         }
     164             : 
     165           5 :         p = strrchr_m(pattern, '.');
     166           5 :         if (p == NULL) {
     167           0 :                 ext2 = "";
     168           0 :                 base2 = fname;
     169             :         } else {
     170           5 :                 ext2 = talloc_strdup(mem_ctx, p+1);
     171           5 :                 base2 = talloc_strndup(mem_ctx, pattern, p-pattern);
     172             :         }
     173           5 :         if (ext2 == NULL || base2 == NULL) {
     174           0 :                 return NULL;
     175             :         }
     176             : 
     177           5 :         base1 = pvfs_resolve_wildcard_component(mem_ctx, base1, base2);
     178           5 :         ext1 = pvfs_resolve_wildcard_component(mem_ctx, ext1, ext2);
     179           5 :         if (base1 == NULL || ext1 == NULL) {
     180           0 :                 return NULL;
     181             :         }
     182             : 
     183           5 :         if (*ext1 == 0) {
     184           0 :                 return base1;
     185             :         }
     186             : 
     187           5 :         return talloc_asprintf(mem_ctx, "%s.%s", base1, ext1);
     188             : }
     189             : 
     190             : /*
     191             :   retry an rename after a sharing violation
     192             : */
     193          15 : static void pvfs_retry_rename(struct pvfs_odb_retry *r,
     194             :                               struct ntvfs_module_context *ntvfs,
     195             :                               struct ntvfs_request *req,
     196             :                               void *_io,
     197             :                               void *private_data,
     198             :                               enum pvfs_wait_notice reason)
     199             : {
     200          15 :         union smb_rename *io = talloc_get_type(_io, union smb_rename);
     201          15 :         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
     202             : 
     203          15 :         talloc_free(r);
     204             : 
     205          15 :         switch (reason) {
     206           0 :         case PVFS_WAIT_CANCEL:
     207             : /*TODO*/
     208           0 :                 status = NT_STATUS_CANCELLED;
     209           0 :                 break;
     210          11 :         case PVFS_WAIT_TIMEOUT:
     211             :                 /* if it timed out, then give the failure
     212             :                    immediately */
     213             : /*TODO*/
     214          11 :                 status = NT_STATUS_SHARING_VIOLATION;
     215          11 :                 break;
     216           4 :         case PVFS_WAIT_EVENT:
     217             : 
     218             :                 /* try the open again, which could trigger another retry setup
     219             :                    if it wants to, so we have to unmark the async flag so we
     220             :                    will know if it does a second async reply */
     221           4 :                 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
     222             : 
     223           4 :                 status = pvfs_rename(ntvfs, req, io);
     224           4 :                 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
     225             :                         /* the 2nd try also replied async, so we don't send
     226             :                            the reply yet */
     227           4 :                         return;
     228             :                 }
     229             : 
     230             :                 /* re-mark it async, just in case someone up the chain does
     231             :                    paranoid checking */
     232           0 :                 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
     233           0 :                 break;
     234             :         }
     235             : 
     236             :         /* send the reply up the chain */
     237          11 :         req->async_states->status = status;
     238          11 :         req->async_states->send_fn(req);
     239             : }
     240             : 
     241             : /*
     242             :   setup for a rename retry after a sharing violation
     243             :   or a non granted oplock
     244             : */
     245          15 : static NTSTATUS pvfs_rename_setup_retry(struct ntvfs_module_context *ntvfs,
     246             :                                         struct ntvfs_request *req,
     247             :                                         union smb_rename *io,
     248             :                                         struct odb_lock *lck,
     249             :                                         NTSTATUS status)
     250             : {
     251          15 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     252             :                                   struct pvfs_state);
     253             :         struct timeval end_time;
     254             : 
     255          15 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
     256          11 :                 end_time = timeval_add(&req->statistics.request_time,
     257             :                                        0, pvfs->sharing_violation_delay);
     258           4 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
     259           4 :                 end_time = timeval_add(&req->statistics.request_time,
     260             :                                        pvfs->oplock_break_timeout, 0);
     261             :         } else {
     262           0 :                 return NT_STATUS_INTERNAL_ERROR;
     263             :         }
     264             : 
     265          15 :         return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
     266             :                                     pvfs_retry_rename);
     267             : }
     268             : 
     269             : /*
     270             :   rename one file from a wildcard set
     271             : */
     272           5 : static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, 
     273             :                                 struct ntvfs_request *req, 
     274             :                                 const char *dir_path,
     275             :                                 const char *fname1,
     276             :                                 const char *fname2,
     277             :                                 uint16_t attrib)
     278             : {
     279             :         struct pvfs_filename *name1, *name2;
     280           5 :         TALLOC_CTX *mem_ctx = talloc_new(req);
     281           5 :         struct odb_lock *lck = NULL;
     282             :         NTSTATUS status;
     283             : 
     284             :         /* resolve the wildcard pattern for this name */
     285           5 :         fname2 = pvfs_resolve_wildcard(mem_ctx, fname1, fname2);
     286           5 :         if (fname2 == NULL) {
     287           0 :                 return NT_STATUS_NO_MEMORY;
     288             :         }
     289             : 
     290             :         /* get a pvfs_filename source object */
     291           5 :         status = pvfs_resolve_partial(pvfs, mem_ctx, 
     292             :                                       dir_path, fname1,
     293             :                                       PVFS_RESOLVE_NO_OPENDB,
     294             :                                       &name1);
     295           5 :         if (!NT_STATUS_IS_OK(status)) {
     296           0 :                 goto failed;
     297             :         }
     298             : 
     299             :         /* make sure its matches the given attributes */
     300           5 :         status = pvfs_match_attrib(pvfs, name1, attrib, 0);
     301           5 :         if (!NT_STATUS_IS_OK(status)) {
     302           1 :                 goto failed;
     303             :         }
     304             : 
     305           4 :         status = pvfs_can_rename(pvfs, req, name1, &lck);
     306           4 :         if (!NT_STATUS_IS_OK(status)) {
     307           0 :                 talloc_free(lck);
     308           0 :                 goto failed;
     309             :         }
     310             : 
     311             :         /* get a pvfs_filename dest object */
     312           4 :         status = pvfs_resolve_partial(pvfs, mem_ctx, 
     313             :                                       dir_path, fname2,
     314             :                                       PVFS_RESOLVE_NO_OPENDB,
     315             :                                       &name2);
     316           4 :         if (NT_STATUS_IS_OK(status)) {
     317           1 :                 status = pvfs_can_delete(pvfs, req, name2, NULL);
     318           1 :                 if (!NT_STATUS_IS_OK(status)) {
     319           0 :                         goto failed;
     320             :                 }
     321             :         }
     322             : 
     323           4 :         status = NT_STATUS_OK;
     324             : 
     325           4 :         fname2 = talloc_asprintf(mem_ctx, "%s/%s", dir_path, fname2);
     326           4 :         if (fname2 == NULL) {
     327           0 :                 return NT_STATUS_NO_MEMORY;
     328             :         }
     329             : 
     330           4 :         status = pvfs_do_rename(pvfs, lck, name1, fname2);
     331             : 
     332           5 : failed:
     333           5 :         talloc_free(mem_ctx);
     334           5 :         return status;
     335             : }
     336             : 
     337             : 
     338             : /*
     339             :   rename a set of files with wildcards
     340             : */
     341           8 : static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs, 
     342             :                                      struct ntvfs_request *req, 
     343             :                                      union smb_rename *ren, 
     344             :                                      struct pvfs_filename *name1, 
     345             :                                      struct pvfs_filename *name2)
     346             : {
     347             :         struct pvfs_dir *dir;
     348             :         NTSTATUS status;
     349           8 :         off_t ofs = 0;
     350             :         const char *fname, *fname2, *dir_path;
     351           8 :         uint16_t attrib = ren->rename.in.attrib;
     352           8 :         int total_renamed = 0;
     353             : 
     354             :         /* get list of matching files */
     355           8 :         status = pvfs_list_start(pvfs, name1, req, &dir);
     356           8 :         if (!NT_STATUS_IS_OK(status)) {
     357           2 :                 return status;
     358             :         }
     359             : 
     360           6 :         status = NT_STATUS_NO_SUCH_FILE;
     361             : 
     362           6 :         dir_path = pvfs_list_unix_path(dir);
     363             : 
     364             :         /* only allow wildcard renames within a directory */
     365          12 :         if (strncmp(dir_path, name2->full_name, strlen(dir_path)) != 0 ||
     366          12 :             name2->full_name[strlen(dir_path)] != '/' ||
     367           6 :             strchr(name2->full_name + strlen(dir_path) + 1, '/')) {
     368           0 :                 DEBUG(3,(__location__ ": Invalid rename for %s -> %s\n",
     369             :                          name1->original_name, name2->original_name));
     370           0 :                 return NT_STATUS_INVALID_PARAMETER;
     371             :         }
     372             : 
     373           6 :         fname2 = talloc_strdup(name2, name2->full_name + strlen(dir_path) + 1);
     374           6 :         if (fname2 == NULL) {
     375           0 :                 return NT_STATUS_NO_MEMORY;
     376             :         }
     377             : 
     378          17 :         while ((fname = pvfs_list_next(dir, &ofs))) {
     379           5 :                 status = pvfs_rename_one(pvfs, req, 
     380             :                                          dir_path,
     381             :                                          fname, fname2, attrib);
     382           5 :                 if (NT_STATUS_IS_OK(status)) {
     383           4 :                         total_renamed++;
     384             :                 }
     385             :         }
     386             : 
     387           6 :         if (total_renamed == 0) {
     388           2 :                 return status;
     389             :         }
     390             : 
     391           4 :         return NT_STATUS_OK;
     392             : }
     393             : 
     394             : /*
     395             :   rename a set of files - SMBmv interface
     396             : */
     397         110 : static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
     398             :                                struct ntvfs_request *req, union smb_rename *ren)
     399             : {
     400         110 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     401             :                                   struct pvfs_state);
     402             :         NTSTATUS status;
     403             :         struct pvfs_filename *name1, *name2;
     404         110 :         struct odb_lock *lck = NULL;
     405             : 
     406             :         /* resolve the cifs name to a posix name */
     407         110 :         status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern1, 
     408             :                                    PVFS_RESOLVE_WILDCARD, &name1);
     409         110 :         if (!NT_STATUS_IS_OK(status)) {
     410           1 :                 return status;
     411             :         }
     412             : 
     413         109 :         status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern2, 
     414             :                                    PVFS_RESOLVE_WILDCARD, &name2);
     415         109 :         if (!NT_STATUS_IS_OK(status)) {
     416           0 :                 return status;
     417             :         }
     418             : 
     419         109 :         if (name1->has_wildcard || name2->has_wildcard) {
     420           8 :                 return pvfs_rename_wildcard(pvfs, req, ren, name1, name2);
     421             :         }
     422             : 
     423         101 :         if (!name1->exists) {
     424           4 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     425             :         }
     426             : 
     427          97 :         if (strcmp(name1->full_name, name2->full_name) == 0) {
     428           2 :                 return NT_STATUS_OK;
     429             :         }
     430             : 
     431          95 :         if (name2->exists) {
     432           0 :                 return NT_STATUS_OBJECT_NAME_COLLISION;
     433             :         }
     434             : 
     435          95 :         status = pvfs_match_attrib(pvfs, name1, ren->rename.in.attrib, 0);
     436          95 :         if (!NT_STATUS_IS_OK(status)) {
     437           1 :                 return status;
     438             :         }
     439             : 
     440          94 :         status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
     441          94 :         if (!NT_STATUS_IS_OK(status)) {
     442           0 :                 return status;
     443             :         }
     444             : 
     445          94 :         status = pvfs_can_rename(pvfs, req, name1, &lck);
     446             :         /*
     447             :          * on a sharing violation we need to retry when the file is closed by
     448             :          * the other user, or after 1 second
     449             :          * on a non granted oplock we need to retry when the file is closed by
     450             :          * the other user, or after 30 seconds
     451             :          */
     452         179 :         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
     453          96 :              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
     454          10 :             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
     455          10 :                 return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
     456             :         }
     457             : 
     458          84 :         if (!NT_STATUS_IS_OK(status)) {
     459           0 :                 return status;
     460             :         }
     461             : 
     462          84 :         status = pvfs_do_rename(pvfs, lck, name1, name2->full_name);
     463          84 :         if (!NT_STATUS_IS_OK(status)) {
     464           0 :                 return status;
     465             :         }
     466             :         
     467          84 :         return NT_STATUS_OK;
     468             : }
     469             : 
     470             : 
     471             : /*
     472             :   rename a stream
     473             : */
     474           6 : static NTSTATUS pvfs_rename_stream(struct ntvfs_module_context *ntvfs,
     475             :                                    struct ntvfs_request *req, union smb_rename *ren,
     476             :                                    struct pvfs_filename *name1)
     477             : {
     478           6 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     479             :                                   struct pvfs_state);
     480             :         NTSTATUS status;
     481           6 :         struct odb_lock *lck = NULL;
     482             : 
     483           6 :         if (name1->has_wildcard) {
     484           0 :                 DEBUG(3,(__location__ ": Invalid wildcard rename for %s\n",
     485             :                          name1->original_name));
     486           0 :                 return NT_STATUS_INVALID_PARAMETER;
     487             :         }
     488             : 
     489           6 :         if (ren->ntrename.in.new_name[0] != ':') {
     490           4 :                 DEBUG(3,(__location__ ": Invalid rename for %s\n",
     491             :                          ren->ntrename.in.new_name));
     492           4 :                 return NT_STATUS_INVALID_PARAMETER;
     493             :         }
     494             : 
     495           2 :         if (!name1->exists) {
     496           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     497             :         }
     498             : 
     499           2 :         if (ren->ntrename.in.flags != RENAME_FLAG_RENAME) {
     500           0 :                 DEBUG(3,(__location__ ": Invalid rename flags 0x%x for %s\n",
     501             :                          ren->ntrename.in.flags, ren->ntrename.in.new_name));
     502           0 :                 return NT_STATUS_INVALID_PARAMETER;
     503             :         }
     504             : 
     505           2 :         status = pvfs_can_rename(pvfs, req, name1, &lck);
     506             :         /*
     507             :          * on a sharing violation we need to retry when the file is closed by
     508             :          * the other user, or after 1 second
     509             :          * on a non granted oplock we need to retry when the file is closed by
     510             :          * the other user, or after 30 seconds
     511             :          */
     512           4 :         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
     513           2 :              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
     514           0 :             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
     515           0 :                 return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
     516             :         }
     517           2 :         if (!NT_STATUS_IS_OK(status)) {
     518           0 :                 return status;
     519             :         }
     520             : 
     521           2 :         status = pvfs_access_check_simple(pvfs, req, name1, SEC_FILE_WRITE_ATTRIBUTE);
     522           2 :         NT_STATUS_NOT_OK_RETURN(status);
     523             : 
     524           2 :         status = pvfs_stream_rename(pvfs, name1, -1, 
     525           2 :                                     ren->ntrename.in.new_name+1, 
     526             :                                     true);
     527           2 :         NT_STATUS_NOT_OK_RETURN(status);
     528             :         
     529           1 :         return NT_STATUS_OK;
     530             : }
     531             : 
     532             : /*
     533             :   rename a set of files - ntrename interface
     534             : */
     535        4129 : static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
     536             :                                struct ntvfs_request *req, union smb_rename *ren)
     537             : {
     538        4129 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     539             :                                   struct pvfs_state);
     540             :         NTSTATUS status;
     541             :         struct pvfs_filename *name1, *name2;
     542        4129 :         struct odb_lock *lck = NULL;
     543             : 
     544        4129 :         switch (ren->ntrename.in.flags) {
     545          33 :         case RENAME_FLAG_RENAME:
     546             :         case RENAME_FLAG_HARD_LINK:
     547             :         case RENAME_FLAG_COPY:
     548             :         case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
     549          33 :                 break;
     550        4096 :         default:
     551        4096 :                 return NT_STATUS_ACCESS_DENIED;
     552             :         }
     553             : 
     554             :         /* resolve the cifs name to a posix name */
     555          33 :         status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.old_name, 
     556             :                                    PVFS_RESOLVE_WILDCARD | PVFS_RESOLVE_STREAMS, &name1);
     557          33 :         if (!NT_STATUS_IS_OK(status)) {
     558           2 :                 return status;
     559             :         }
     560             : 
     561          31 :         if (name1->stream_name) {
     562             :                 /* stream renames need to be handled separately */
     563           6 :                 return pvfs_rename_stream(ntvfs, req, ren, name1);
     564             :         }
     565             : 
     566          25 :         status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.new_name, 
     567             :                                    PVFS_RESOLVE_WILDCARD, &name2);
     568          25 :         if (!NT_STATUS_IS_OK(status)) {
     569           3 :                 return status;
     570             :         }
     571             : 
     572          22 :         if (name1->has_wildcard || name2->has_wildcard) {
     573           1 :                 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
     574             :         }
     575             : 
     576          21 :         if (!name1->exists) {
     577           5 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     578             :         }
     579             : 
     580          16 :         if (strcmp(name1->full_name, name2->full_name) == 0) {
     581           1 :                 return NT_STATUS_OK;
     582             :         }
     583             : 
     584          15 :         if (name2->exists) {
     585           1 :                 return NT_STATUS_OBJECT_NAME_COLLISION;
     586             :         }
     587             : 
     588          14 :         status = pvfs_match_attrib(pvfs, name1, ren->ntrename.in.attrib, 0);
     589          14 :         if (!NT_STATUS_IS_OK(status)) {
     590           1 :                 return status;
     591             :         }
     592             : 
     593          13 :         status = pvfs_can_rename(pvfs, req, name1, &lck);
     594             :         /*
     595             :          * on a sharing violation we need to retry when the file is closed by
     596             :          * the other user, or after 1 second
     597             :          * on a non granted oplock we need to retry when the file is closed by
     598             :          * the other user, or after 30 seconds
     599             :          */
     600          23 :         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
     601          15 :              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
     602           5 :             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
     603           5 :                 return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
     604             :         }
     605           8 :         if (!NT_STATUS_IS_OK(status)) {
     606           0 :                 return status;
     607             :         }
     608             : 
     609           8 :         switch (ren->ntrename.in.flags) {
     610           3 :         case RENAME_FLAG_RENAME:
     611           3 :                 status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
     612           3 :                 NT_STATUS_NOT_OK_RETURN(status);
     613           3 :                 status = pvfs_do_rename(pvfs, lck, name1, name2->full_name);
     614           3 :                 NT_STATUS_NOT_OK_RETURN(status);
     615           3 :                 break;
     616             : 
     617           2 :         case RENAME_FLAG_HARD_LINK:
     618           2 :                 status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
     619           2 :                 NT_STATUS_NOT_OK_RETURN(status);
     620           2 :                 if (link(name1->full_name, name2->full_name) == -1) {
     621           0 :                         return pvfs_map_errno(pvfs, errno);
     622             :                 }
     623           2 :                 break;
     624             : 
     625           2 :         case RENAME_FLAG_COPY:
     626           2 :                 status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
     627           2 :                 NT_STATUS_NOT_OK_RETURN(status);
     628           2 :                 return pvfs_copy_file(pvfs, name1, name2, name1->allow_override && name2->allow_override);
     629             : 
     630           1 :         case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
     631           1 :                 DEBUG(3,(__location__ ": Invalid rename cluster for %s\n",
     632             :                          name1->original_name));
     633           1 :                 return NT_STATUS_INVALID_PARAMETER;
     634             : 
     635           0 :         default:
     636           0 :                 return NT_STATUS_ACCESS_DENIED;
     637             :         }
     638             : 
     639             :         
     640           5 :         return NT_STATUS_OK;
     641             : }
     642             : 
     643             : /*
     644             :   rename a set of files - ntrename interface
     645             : */
     646        4240 : NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
     647             :                      struct ntvfs_request *req, union smb_rename *ren)
     648             : {
     649        4240 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     650             :                                   struct pvfs_state);
     651             :         struct pvfs_file *f;
     652             : 
     653        4240 :         switch (ren->generic.level) {
     654         110 :         case RAW_RENAME_RENAME:
     655         110 :                 return pvfs_rename_mv(ntvfs, req, ren);
     656             : 
     657        4129 :         case RAW_RENAME_NTRENAME:
     658        4129 :                 return pvfs_rename_nt(ntvfs, req, ren);
     659             : 
     660           1 :         case RAW_RENAME_NTTRANS:
     661           1 :                 f = pvfs_find_fd(pvfs, req, ren->nttrans.in.file.ntvfs);
     662           1 :                 if (!f) {
     663           0 :                         return NT_STATUS_INVALID_HANDLE;
     664             :                 }
     665             : 
     666             :                 /* wk23 ignores the request */
     667           1 :                 return NT_STATUS_OK;
     668             : 
     669           0 :         default:
     670           0 :                 break;
     671             :         }
     672             : 
     673           0 :         return NT_STATUS_INVALID_LEVEL;
     674             : }
     675             : 

Generated by: LCOV version 1.13