LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_unlink.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 86 94 91.5 %
Date: 2021-09-23 10:06:22 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend - unlink
       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 "system/dir.h"
      25             : 
      26             : /*
      27             :   retry an open after a sharing violation
      28             : */
      29          35 : static void pvfs_retry_unlink(struct pvfs_odb_retry *r,
      30             :                               struct ntvfs_module_context *ntvfs,
      31             :                               struct ntvfs_request *req,
      32             :                               void *_io,
      33             :                               void *private_data,
      34             :                               enum pvfs_wait_notice reason)
      35             : {
      36          35 :         union smb_unlink *io = talloc_get_type(_io, union smb_unlink);
      37          35 :         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
      38             : 
      39          35 :         talloc_free(r);
      40             : 
      41          35 :         switch (reason) {
      42           0 :         case PVFS_WAIT_CANCEL:
      43             : /*TODO*/
      44           0 :                 status = NT_STATUS_CANCELLED;
      45           0 :                 break;
      46          29 :         case PVFS_WAIT_TIMEOUT:
      47             :                 /* if it timed out, then give the failure
      48             :                    immediately */
      49             : /*TODO*/
      50          29 :                 status = NT_STATUS_SHARING_VIOLATION;
      51          29 :                 break;
      52           6 :         case PVFS_WAIT_EVENT:
      53             : 
      54             :                 /* try the open again, which could trigger another retry setup
      55             :                    if it wants to, so we have to unmark the async flag so we
      56             :                    will know if it does a second async reply */
      57           6 :                 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
      58             : 
      59           6 :                 status = pvfs_unlink(ntvfs, req, io);
      60           6 :                 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
      61             :                         /* the 2nd try also replied async, so we don't send
      62             :                            the reply yet */
      63           4 :                         return;
      64             :                 }
      65             : 
      66             :                 /* re-mark it async, just in case someone up the chain does
      67             :                    paranoid checking */
      68           2 :                 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
      69           2 :                 break;
      70             :         }
      71             : 
      72             :         /* send the reply up the chain */
      73          31 :         req->async_states->status = status;
      74          31 :         req->async_states->send_fn(req);
      75             : }
      76             : 
      77             : /*
      78             :   setup for a unlink retry after a sharing violation
      79             :   or a non granted oplock
      80             : */
      81          35 : static NTSTATUS pvfs_unlink_setup_retry(struct ntvfs_module_context *ntvfs,
      82             :                                         struct ntvfs_request *req,
      83             :                                         union smb_unlink *io,
      84             :                                         struct odb_lock *lck,
      85             :                                         NTSTATUS status)
      86             : {
      87          35 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
      88             :                                   struct pvfs_state);
      89             :         struct timeval end_time;
      90             : 
      91          35 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
      92          29 :                 end_time = timeval_add(&req->statistics.request_time,
      93             :                                        0, pvfs->sharing_violation_delay);
      94           6 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
      95           6 :                 end_time = timeval_add(&req->statistics.request_time,
      96             :                                        pvfs->oplock_break_timeout, 0);
      97             :         } else {
      98           0 :                 return NT_STATUS_INTERNAL_ERROR;
      99             :         }
     100             : 
     101          35 :         return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
     102             :                                     pvfs_retry_unlink);
     103             : }
     104             : 
     105             : 
     106             : /*
     107             :   unlink a file
     108             : */
     109       31018 : static NTSTATUS pvfs_unlink_file(struct pvfs_state *pvfs,
     110             :                                  struct pvfs_filename *name)
     111             : {
     112       31018 :         NTSTATUS status = NT_STATUS_OK;
     113             : 
     114       31018 :         if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
     115           0 :                 return NT_STATUS_FILE_IS_A_DIRECTORY;
     116             :         }
     117             : 
     118       31018 :         if (name->st.st_nlink == 1) {
     119       31016 :                 status = pvfs_xattr_unlink_hook(pvfs, name->full_name);
     120       31016 :                 if (!NT_STATUS_IS_OK(status)) {
     121           0 :                         return status;
     122             :                 }
     123             :         }
     124             : 
     125             :         /* finally try the actual unlink */
     126       31018 :         if (pvfs_sys_unlink(pvfs, name->full_name, name->allow_override) == -1) {
     127           0 :                 status = pvfs_map_errno(pvfs, errno);
     128             :         }
     129             : 
     130       31018 :         if (NT_STATUS_IS_OK(status)) {
     131       31018 :                 notify_trigger(pvfs->notify_context, 
     132             :                                NOTIFY_ACTION_REMOVED, 
     133             :                                FILE_NOTIFY_CHANGE_FILE_NAME,
     134       31018 :                                name->full_name);
     135             :         }
     136             : 
     137       31018 :         return status;
     138             : }
     139             : 
     140             : /*
     141             :   unlink one file
     142             : */
     143       37577 : static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
     144             :                                 struct ntvfs_request *req,
     145             :                                 union smb_unlink *unl,
     146             :                                 struct pvfs_filename *name)
     147             : {
     148             :         NTSTATUS status;
     149       37577 :         struct odb_lock *lck = NULL;
     150             : 
     151             :         /* make sure its matches the given attributes */
     152       37577 :         status = pvfs_match_attrib(pvfs, name,
     153       37577 :                                    unl->unlink.in.attrib, 0);
     154       37577 :         if (!NT_STATUS_IS_OK(status)) {
     155        6519 :                 return status;
     156             :         }
     157             : 
     158       31058 :         status = pvfs_can_delete(pvfs, req, name, &lck);
     159             : 
     160             :         /*
     161             :          * on a sharing violation we need to retry when the file is closed by
     162             :          * the other user, or after 1 second
     163             :          * on a non granted oplock we need to retry when the file is closed by
     164             :          * the other user, or after 30 seconds
     165             :          */
     166       62082 :         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
     167       31064 :              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
     168          37 :             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
     169          35 :                 return pvfs_unlink_setup_retry(pvfs->ntvfs, req, unl, lck, status);
     170             :         }
     171             : 
     172       31023 :         if (!NT_STATUS_IS_OK(status)) {
     173           2 :                 return status;
     174             :         }
     175             : 
     176       31021 :         if (name->stream_name) {
     177           3 :                 if (!name->stream_exists) {
     178           1 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     179             :                 }
     180             : 
     181           2 :                 return pvfs_stream_delete(pvfs, name, -1);
     182             :         }
     183             : 
     184       31018 :         return pvfs_unlink_file(pvfs, name);
     185             : }
     186             : 
     187             : /*
     188             :   delete a file - the dirtype specifies the file types to include in the search. 
     189             :   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
     190             : */
     191       30867 : NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
     192             :                      struct ntvfs_request *req,
     193             :                      union smb_unlink *unl)
     194             : {
     195       30867 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     196             :                                   struct pvfs_state);
     197             :         struct pvfs_dir *dir;
     198             :         NTSTATUS status;
     199       30867 :         uint32_t total_deleted=0;
     200             :         struct pvfs_filename *name;
     201             :         const char *fname;
     202             :         off_t ofs;
     203             : 
     204             :         /* resolve the cifs name to a posix name */
     205       30867 :         status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern, 
     206             :                                    PVFS_RESOLVE_WILDCARD |
     207             :                                    PVFS_RESOLVE_STREAMS |
     208             :                                    PVFS_RESOLVE_NO_OPENDB,
     209             :                                    &name);
     210       30867 :         if (!NT_STATUS_IS_OK(status)) {
     211          66 :                 return status;
     212             :         }
     213             : 
     214       30801 :         if (!name->exists && !name->has_wildcard) {
     215        1077 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     216             :         }
     217             : 
     218       57191 :         if (name->exists && 
     219       27471 :             (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
     220         203 :                 return NT_STATUS_FILE_IS_A_DIRECTORY;
     221             :         }
     222             : 
     223       29521 :         if (!name->has_wildcard) {
     224       27268 :                 return pvfs_unlink_one(pvfs, req, unl, name);
     225             :         }
     226             : 
     227             :         /*
     228             :          * disable async requests in the wildcard case
     229             :          * untill we have proper tests for this
     230             :          */
     231        2253 :         req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
     232             : 
     233             :         /* get list of matching files */
     234        2253 :         status = pvfs_list_start(pvfs, name, req, &dir);
     235        2253 :         if (!NT_STATUS_IS_OK(status)) {
     236           3 :                 return status;
     237             :         }
     238             : 
     239        2250 :         status = NT_STATUS_NO_SUCH_FILE;
     240        2250 :         talloc_free(name);
     241             : 
     242        2250 :         ofs = 0;
     243             : 
     244       14808 :         while ((fname = pvfs_list_next(dir, &ofs))) {
     245             :                 /* this seems to be a special case */
     246       10314 :                 if ((unl->unlink.in.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
     247           5 :                     (ISDOT(fname) || ISDOTDOT(fname))) {
     248           2 :                         return NT_STATUS_OBJECT_NAME_INVALID;
     249             :                 }
     250             : 
     251             :                 /* get a pvfs_filename object */
     252       10309 :                 status = pvfs_resolve_partial(pvfs, req,
     253             :                                               pvfs_list_unix_path(dir),
     254             :                                               fname,
     255             :                                               PVFS_RESOLVE_NO_OPENDB,
     256             :                                               &name);
     257       10309 :                 if (!NT_STATUS_IS_OK(status)) {
     258           0 :                         return status;
     259             :                 }
     260             : 
     261       10309 :                 status = pvfs_unlink_one(pvfs, req, unl, name);
     262       10309 :                 if (NT_STATUS_IS_OK(status)) {
     263        3789 :                         total_deleted++;
     264             :                 }
     265             : 
     266       10309 :                 talloc_free(name);
     267             :         }
     268             : 
     269        2248 :         if (total_deleted > 0) {
     270         156 :                 status = NT_STATUS_OK;
     271             :         }
     272             : 
     273        2248 :         return status;
     274             : }
     275             : 
     276             : 

Generated by: LCOV version 1.13