LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_open.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 806 966 83.4 %
Date: 2021-09-23 10:06:22 Functions: 26 28 92.9 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend - open and close
       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             : #include "system/time.h"
      26             : #include "../lib/util/dlinklist.h"
      27             : #include "messaging/messaging.h"
      28             : #include "librpc/gen_ndr/xattr.h"
      29             : 
      30             : /*
      31             :   find open file handle given fnum
      32             : */
      33      299172 : struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
      34             :                                struct ntvfs_request *req, struct ntvfs_handle *h)
      35             : {
      36             :         void *p;
      37             :         struct pvfs_file *f;
      38             : 
      39      299172 :         p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
      40      299172 :         if (!p) return NULL;
      41             : 
      42      299172 :         f = talloc_get_type(p, struct pvfs_file);
      43      299172 :         if (!f) return NULL;
      44             : 
      45      299172 :         return f;
      46             : }
      47             : 
      48             : /*
      49             :   cleanup a open directory handle
      50             : */
      51       10993 : static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
      52             : {
      53       10993 :         if (h->have_opendb_entry) {
      54             :                 struct odb_lock *lck;
      55             :                 NTSTATUS status;
      56       10993 :                 const char *delete_path = NULL;
      57             : 
      58       10993 :                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
      59       10993 :                 if (lck == NULL) {
      60           0 :                         DEBUG(0,("Unable to lock opendb for close\n"));
      61           0 :                         return 0;
      62             :                 }
      63             : 
      64       10993 :                 status = odb_close_file(lck, h, &delete_path);
      65       10993 :                 if (!NT_STATUS_IS_OK(status)) {
      66           0 :                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
      67             :                                  h->name->full_name, nt_errstr(status)));
      68             :                 }
      69             : 
      70       10993 :                 if (h->name->stream_name == NULL && delete_path) {
      71         400 :                         status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
      72         400 :                         if (!NT_STATUS_IS_OK(status)) {
      73           0 :                                 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
      74             :                                          delete_path, nt_errstr(status)));
      75             :                         }
      76         400 :                         if (pvfs_sys_rmdir(h->pvfs, delete_path, h->name->allow_override) != 0) {
      77           0 :                                 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
      78             :                                          delete_path, strerror(errno)));
      79             :                         }
      80             :                 }
      81             : 
      82       10993 :                 talloc_free(lck);
      83             :         }
      84             : 
      85       10993 :         return 0;
      86             : }
      87             : 
      88             : /*
      89             :   cleanup a open directory fnum
      90             : */
      91       10993 : static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
      92             : {
      93       10993 :         DLIST_REMOVE(f->pvfs->files.list, f);
      94       10993 :         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
      95             : 
      96       10993 :         return 0;
      97             : }
      98             : 
      99             : /*
     100             :   setup any EAs and the ACL on newly created files/directories
     101             : */
     102      101645 : static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
     103             :                                         struct ntvfs_request *req,
     104             :                                         struct pvfs_filename *name,
     105             :                                         int fd, struct pvfs_file *f,
     106             :                                         union smb_open *io,
     107             :                                         struct security_descriptor *sd)
     108             : {
     109      101645 :         NTSTATUS status = NT_STATUS_OK;
     110             : 
     111             :         /* setup any EAs that were asked for */
     112      101645 :         if (io->ntcreatex.in.ea_list) {
     113      132536 :                 status = pvfs_setfileinfo_ea_set(pvfs, name, fd, 
     114       66268 :                                                  io->ntcreatex.in.ea_list->num_eas,
     115       66268 :                                                  io->ntcreatex.in.ea_list->eas);
     116       66268 :                 if (!NT_STATUS_IS_OK(status)) {
     117           0 :                         return status;
     118             :                 }
     119             :         }
     120             : 
     121             :         /* setup an initial sec_desc if requested */
     122      101645 :         if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
     123             :                 union smb_setfileinfo set;
     124             : /* 
     125             :  * TODO: set the full ACL! 
     126             :  *       - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
     127             :  *         when a SACL is present on the sd,
     128             :  *         but the user doesn't have SeSecurityPrivilege
     129             :  *       - w2k3 allows it
     130             :  */
     131         382 :                 set.set_secdesc.in.file.ntvfs = f->ntvfs;
     132         382 :                 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
     133         382 :                 set.set_secdesc.in.sd = sd;
     134             : 
     135         382 :                 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
     136             :         }
     137             : 
     138      101645 :         return status;
     139             : }
     140             : 
     141             : /*
     142             :   form the lock context used for opendb locking. Note that we must
     143             :   zero here to take account of possible padding on some architectures
     144             : */
     145      873305 : NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
     146             :                           TALLOC_CTX *mem_ctx, DATA_BLOB *key)
     147             : {
     148             :         struct {
     149             :                 dev_t device;
     150             :                 ino_t inode;
     151             :         } lock_context;
     152      873305 :         ZERO_STRUCT(lock_context);
     153             : 
     154      873305 :         lock_context.device = name->st.st_dev;
     155      873305 :         lock_context.inode = name->st.st_ino;
     156             : 
     157      873305 :         *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
     158      873305 :         if (key->data == NULL) {
     159           0 :                 return NT_STATUS_NO_MEMORY;
     160             :         }
     161             :         
     162      873305 :         return NT_STATUS_OK;
     163             : }
     164             : 
     165             : 
     166             : /*
     167             :   open a directory
     168             : */
     169       11145 : static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, 
     170             :                                     struct ntvfs_request *req, 
     171             :                                     struct pvfs_filename *name, 
     172             :                                     union smb_open *io)
     173             : {
     174             :         struct pvfs_file *f;
     175             :         struct ntvfs_handle *h;
     176             :         NTSTATUS status;
     177             :         uint32_t create_action;
     178       11145 :         uint32_t access_mask = io->generic.in.access_mask;
     179             :         struct odb_lock *lck;
     180             :         bool del_on_close;
     181             :         uint32_t create_options;
     182             :         uint32_t share_access;
     183             :         bool forced;
     184       11145 :         struct security_descriptor *sd = NULL;
     185             : 
     186       11145 :         create_options = io->generic.in.create_options;
     187       11145 :         share_access   = io->generic.in.share_access;
     188             : 
     189       11145 :         forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
     190             : 
     191       11145 :         if (name->stream_name) {
     192           7 :                 if (forced) {
     193           4 :                         return NT_STATUS_NOT_A_DIRECTORY;
     194             :                 } else {
     195           3 :                         return NT_STATUS_FILE_IS_A_DIRECTORY;
     196             :                 }
     197             :         }
     198             : 
     199             :         /* if the client says it must be a directory, and it isn't,
     200             :            then fail */
     201       11138 :         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
     202           0 :                 return NT_STATUS_NOT_A_DIRECTORY;
     203             :         }
     204             : 
     205             :         /* found with gentest */
     206       11191 :         if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
     207         103 :             (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
     208          50 :             (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
     209           0 :                 DEBUG(3,(__location__ ": Invalid access_mask/create_options 0x%08x 0x%08x for %s\n",
     210             :                          io->ntcreatex.in.access_mask, io->ntcreatex.in.create_options, name->original_name));
     211           0 :                 return NT_STATUS_INVALID_PARAMETER;
     212             :         }
     213             :         
     214       11138 :         switch (io->generic.in.open_disposition) {
     215        8606 :         case NTCREATEX_DISP_OPEN_IF:
     216        8606 :                 break;
     217             : 
     218        2176 :         case NTCREATEX_DISP_OPEN:
     219        2176 :                 if (!name->exists) {
     220         101 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     221             :                 }
     222        2075 :                 break;
     223             : 
     224         345 :         case NTCREATEX_DISP_CREATE:
     225         345 :                 if (name->exists) {
     226          15 :                         return NT_STATUS_OBJECT_NAME_COLLISION;
     227             :                 }
     228         330 :                 break;
     229             : 
     230          11 :         case NTCREATEX_DISP_OVERWRITE_IF:
     231             :         case NTCREATEX_DISP_OVERWRITE:
     232             :         case NTCREATEX_DISP_SUPERSEDE:
     233             :         default:
     234          11 :                 DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
     235             :                          io->generic.in.open_disposition, name->original_name));
     236          11 :                 return NT_STATUS_INVALID_PARAMETER;
     237             :         }
     238             : 
     239       11011 :         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
     240       11011 :         NT_STATUS_NOT_OK_RETURN(status);
     241             : 
     242       11011 :         f = talloc(h, struct pvfs_file);
     243       11011 :         if (f == NULL) {
     244           0 :                 return NT_STATUS_NO_MEMORY;
     245             :         }
     246             : 
     247       11011 :         f->handle = talloc(f, struct pvfs_file_handle);
     248       11011 :         if (f->handle == NULL) {
     249           0 :                 return NT_STATUS_NO_MEMORY;
     250             :         }
     251             : 
     252       11011 :         if (name->exists) {
     253             :                 /* check the security descriptor */
     254        6354 :                 status = pvfs_access_check(pvfs, req, name, &access_mask);
     255             :         } else {                
     256        4657 :                 sd = io->ntcreatex.in.sec_desc;
     257        4657 :                 status = pvfs_access_check_create(pvfs, req, name, &access_mask, true, &sd);
     258             :         }
     259       11011 :         NT_STATUS_NOT_OK_RETURN(status);
     260             : 
     261       11011 :         if (io->generic.in.query_maximal_access) {
     262           0 :                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
     263             :                                                      &io->generic.out.maximal_access);
     264           0 :                 NT_STATUS_NOT_OK_RETURN(status);
     265             :         }
     266             : 
     267       11011 :         f->ntvfs         = h;
     268       11011 :         f->pvfs          = pvfs;
     269       11011 :         f->pending_list  = NULL;
     270       11011 :         f->lock_count    = 0;
     271       11011 :         f->share_access  = io->generic.in.share_access;
     272       11011 :         f->impersonation = io->generic.in.impersonation;
     273       11011 :         f->access_mask   = access_mask;
     274       11011 :         f->brl_handle         = NULL;
     275       11011 :         f->notify_buffer = NULL;
     276       11011 :         f->search        = NULL;
     277             : 
     278       11011 :         f->handle->pvfs              = pvfs;
     279       11011 :         f->handle->name              = talloc_steal(f->handle, name);
     280       11011 :         f->handle->fd                = -1;
     281       11011 :         f->handle->odb_locking_key   = data_blob(NULL, 0);
     282       11011 :         f->handle->create_options    = io->generic.in.create_options;
     283       11011 :         f->handle->private_flags     = io->generic.in.private_flags;
     284       11011 :         f->handle->seek_offset       = 0;
     285       11011 :         f->handle->position          = 0;
     286       11011 :         f->handle->mode              = 0;
     287       11011 :         f->handle->oplock            = NULL;
     288       11011 :         ZERO_STRUCT(f->handle->write_time);
     289       11011 :         f->handle->open_completed    = false;
     290             : 
     291       11166 :         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
     292         155 :             pvfs_directory_empty(pvfs, f->handle->name)) {
     293         150 :                 del_on_close = true;
     294             :         } else {
     295       10861 :                 del_on_close = false;
     296             :         }
     297             : 
     298       11011 :         if (name->exists) {
     299             :                 /* form the lock context used for opendb locking */
     300        6354 :                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
     301        6354 :                 if (!NT_STATUS_IS_OK(status)) {
     302           0 :                         return status;
     303             :                 }
     304             : 
     305             :                 /* get a lock on this file before the actual open */
     306        6354 :                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
     307        6354 :                 if (lck == NULL) {
     308           0 :                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
     309             :                                  name->full_name));
     310             :                         /* we were supposed to do a blocking lock, so something
     311             :                            is badly wrong! */
     312           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     313             :                 }
     314             :                 
     315             :                 /* see if we are allowed to open at the same time as existing opens */
     316        6354 :                 status = odb_can_open(lck, name->stream_id,
     317             :                                       share_access, access_mask, del_on_close,
     318             :                                       io->generic.in.open_disposition, false);
     319        6354 :                 if (!NT_STATUS_IS_OK(status)) {
     320          18 :                         talloc_free(lck);
     321          18 :                         return status;
     322             :                 }
     323             : 
     324             :                 /* now really mark the file as open */
     325        6336 :                 status = odb_open_file(lck, f->handle, name->full_name,
     326        6336 :                                        NULL, name->dos.write_time,
     327             :                                        false, OPLOCK_NONE, NULL);
     328             : 
     329        6336 :                 if (!NT_STATUS_IS_OK(status)) {
     330           0 :                         talloc_free(lck);
     331           0 :                         return status;
     332             :                 }
     333             : 
     334        6336 :                 f->handle->have_opendb_entry = true;
     335             :         }
     336             : 
     337       10993 :         DLIST_ADD(pvfs->files.list, f);
     338             : 
     339             :         /* setup destructors to avoid leaks on abnormal termination */
     340       10993 :         talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
     341       10993 :         talloc_set_destructor(f, pvfs_dir_fnum_destructor);
     342             : 
     343       10993 :         if (!name->exists) {
     344        4657 :                 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
     345        4657 :                 mode_t mode = pvfs_fileperms(pvfs, attrib);
     346             : 
     347        4657 :                 if (pvfs_sys_mkdir(pvfs, name->full_name, mode, name->allow_override) == -1) {
     348           0 :                         return pvfs_map_errno(pvfs,errno);
     349             :                 }
     350             : 
     351        4657 :                 pvfs_xattr_unlink_hook(pvfs, name->full_name);
     352             : 
     353        4657 :                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
     354        4657 :                 if (!NT_STATUS_IS_OK(status)) {
     355           0 :                         goto cleanup_delete;
     356             :                 }
     357             : 
     358        4657 :                 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io, sd);
     359        4657 :                 if (!NT_STATUS_IS_OK(status)) {
     360           0 :                         goto cleanup_delete;
     361             :                 }
     362             : 
     363             :                 /* form the lock context used for opendb locking */
     364        4657 :                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
     365        4657 :                 if (!NT_STATUS_IS_OK(status)) {
     366           0 :                         return status;
     367             :                 }
     368             : 
     369        4657 :                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
     370        4657 :                 if (lck == NULL) {
     371           0 :                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
     372             :                                  name->full_name));
     373             :                         /* we were supposed to do a blocking lock, so something
     374             :                            is badly wrong! */
     375           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     376             :                 }
     377             : 
     378        4657 :                 status = odb_can_open(lck, name->stream_id,
     379             :                                       share_access, access_mask, del_on_close,
     380             :                                       io->generic.in.open_disposition, false);
     381             : 
     382        4657 :                 if (!NT_STATUS_IS_OK(status)) {
     383           0 :                         goto cleanup_delete;
     384             :                 }
     385             : 
     386        4657 :                 status = odb_open_file(lck, f->handle, name->full_name,
     387        4657 :                                        NULL, name->dos.write_time,
     388             :                                        false, OPLOCK_NONE, NULL);
     389             : 
     390        4657 :                 if (!NT_STATUS_IS_OK(status)) {
     391           0 :                         goto cleanup_delete;
     392             :                 }
     393             : 
     394        4657 :                 f->handle->have_opendb_entry = true;
     395             : 
     396        4657 :                 create_action = NTCREATEX_ACTION_CREATED;
     397             : 
     398        4657 :                 notify_trigger(pvfs->notify_context, 
     399             :                                NOTIFY_ACTION_ADDED, 
     400             :                                FILE_NOTIFY_CHANGE_DIR_NAME,
     401        4657 :                                name->full_name);
     402             :         } else {
     403        6336 :                 create_action = NTCREATEX_ACTION_EXISTED;
     404             :         }
     405             : 
     406       10993 :         if (!name->exists) {
     407           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     408             :         }
     409             : 
     410       10993 :         if (io->generic.in.query_on_disk_id) {
     411           0 :                 ZERO_ARRAY(io->generic.out.on_disk_id);
     412           0 :                 SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
     413           0 :                 SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
     414             :         }
     415             : 
     416             :         /* the open succeeded, keep this handle permanently */
     417       10993 :         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
     418       10993 :         if (!NT_STATUS_IS_OK(status)) {
     419           0 :                 goto cleanup_delete;
     420             :         }
     421             : 
     422       10993 :         f->handle->open_completed = true;
     423             : 
     424       10993 :         io->generic.out.oplock_level  = OPLOCK_NONE;
     425       10993 :         io->generic.out.file.ntvfs    = h;
     426       10993 :         io->generic.out.create_action = create_action;
     427       10993 :         io->generic.out.create_time   = name->dos.create_time;
     428       10993 :         io->generic.out.access_time   = name->dos.access_time;
     429       10993 :         io->generic.out.write_time    = name->dos.write_time;
     430       10993 :         io->generic.out.change_time   = name->dos.change_time;
     431       10993 :         io->generic.out.attrib        = name->dos.attrib;
     432       10993 :         io->generic.out.alloc_size    = name->dos.alloc_size;
     433       10993 :         io->generic.out.size          = name->st.st_size;
     434       10993 :         io->generic.out.file_type     = FILE_TYPE_DISK;
     435       10993 :         io->generic.out.ipc_state     = 0;
     436       10993 :         io->generic.out.is_directory  = 1;
     437             : 
     438       10993 :         return NT_STATUS_OK;
     439             : 
     440           0 : cleanup_delete:
     441           0 :         pvfs_sys_rmdir(pvfs, name->full_name, name->allow_override);
     442           0 :         return status;
     443             : }
     444             : 
     445             : /*
     446             :   destroy a struct pvfs_file_handle
     447             : */
     448      188961 : static int pvfs_handle_destructor(struct pvfs_file_handle *h)
     449             : {
     450      188961 :         talloc_free(h->write_time.update_event);
     451      188961 :         h->write_time.update_event = NULL;
     452             : 
     453      254924 :         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
     454       65963 :             h->name->stream_name) {
     455             :                 NTSTATUS status;
     456           5 :                 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
     457           5 :                 if (!NT_STATUS_IS_OK(status)) {
     458           0 :                         DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
     459             :                                  h->name->stream_name, h->name->full_name));
     460             :                 }
     461             :         }
     462             : 
     463      188961 :         if (h->fd != -1) {
     464      185988 :                 if (close(h->fd) != 0) {
     465           0 :                         DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
     466             :                                  h->fd, h->name->full_name, strerror(errno)));
     467             :                 }
     468      185988 :                 h->fd = -1;
     469             :         }
     470             : 
     471      377609 :         if (!h->write_time.update_forced &&
     472      197884 :             h->write_time.update_on_close &&
     473        9216 :             h->write_time.close_time == 0) {
     474             :                 struct timeval tv;
     475        9215 :                 tv = timeval_current();
     476        9215 :                 h->write_time.close_time = timeval_to_nttime(&tv);
     477             :         }
     478             : 
     479      188961 :         if (h->have_opendb_entry) {
     480             :                 struct odb_lock *lck;
     481             :                 NTSTATUS status;
     482      185988 :                 const char *delete_path = NULL;
     483             : 
     484      185988 :                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
     485      185988 :                 if (lck == NULL) {
     486           0 :                         DEBUG(0,("Unable to lock opendb for close\n"));
     487           0 :                         return 0;
     488             :                 }
     489             : 
     490      185988 :                 if (h->write_time.update_forced) {
     491         290 :                         status = odb_get_file_infos(h->pvfs->odb_context,
     492             :                                                     &h->odb_locking_key,
     493             :                                                     NULL,
     494             :                                                     &h->write_time.close_time);
     495         290 :                         if (!NT_STATUS_IS_OK(status)) {
     496           0 :                                 DEBUG(0,("Unable get write time for '%s' - %s\n",
     497             :                                          h->name->full_name, nt_errstr(status)));
     498             :                         }
     499             : 
     500         290 :                         h->write_time.update_forced = false;
     501         290 :                         h->write_time.update_on_close = true;
     502      185698 :                 } else if (h->write_time.update_on_close) {
     503        9216 :                         status = odb_set_write_time(lck, h->write_time.close_time, true);
     504        9216 :                         if (!NT_STATUS_IS_OK(status)) {
     505           0 :                                 DEBUG(0,("Unable set write time for '%s' - %s\n",
     506             :                                          h->name->full_name, nt_errstr(status)));
     507             :                         }
     508             :                 }
     509             : 
     510      185988 :                 status = odb_close_file(lck, h, &delete_path);
     511      185988 :                 if (!NT_STATUS_IS_OK(status)) {
     512           0 :                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
     513             :                                  h->name->full_name, nt_errstr(status)));
     514             :                 }
     515             : 
     516      371859 :                 if (h->name->stream_name == NULL &&
     517      371765 :                     h->open_completed && delete_path) {
     518       65923 :                         status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
     519       65923 :                         if (!NT_STATUS_IS_OK(status)) {
     520           0 :                                 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
     521             :                                          delete_path, nt_errstr(status)));
     522             :                         }
     523       65923 :                         if (pvfs_sys_unlink(h->pvfs, delete_path, h->name->allow_override) != 0) {
     524           0 :                                 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
     525             :                                          delete_path, strerror(errno)));
     526             :                         } else {
     527       65923 :                                 notify_trigger(h->pvfs->notify_context,
     528             :                                                NOTIFY_ACTION_REMOVED,
     529             :                                                FILE_NOTIFY_CHANGE_FILE_NAME,
     530             :                                                delete_path);
     531             :                         }
     532       65923 :                         h->write_time.update_on_close = false;
     533             :                 }
     534             : 
     535      185988 :                 talloc_free(lck);
     536             :         }
     537             : 
     538      188961 :         if (h->write_time.update_on_close) {
     539             :                 struct timeval tv[2];
     540             : 
     541        9499 :                 nttime_to_timeval(&tv[0], h->name->dos.access_time);
     542        9499 :                 nttime_to_timeval(&tv[1], h->write_time.close_time);
     543             : 
     544        9499 :                 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
     545        9499 :                         if (utimes(h->name->full_name, tv) == -1) {
     546           1 :                                 DEBUG(3,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
     547             :                                          h->name->full_name, strerror(errno)));
     548             :                         }
     549             :                 }
     550             :         }
     551             : 
     552      188961 :         return 0;
     553             : }
     554             : 
     555             : 
     556             : /*
     557             :   destroy a struct pvfs_file
     558             : */
     559      188961 : static int pvfs_fnum_destructor(struct pvfs_file *f)
     560             : {
     561      188961 :         DLIST_REMOVE(f->pvfs->files.list, f);
     562      188961 :         pvfs_lock_close(f->pvfs, f);
     563      188961 :         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
     564             : 
     565      188961 :         return 0;
     566             : }
     567             : 
     568             : 
     569             : /*
     570             :   form the lock context used for byte range locking. This is separate
     571             :   from the locking key used for opendb locking as it needs to take
     572             :   account of file streams (each stream is a separate byte range
     573             :   locking space)
     574             : */
     575      188961 : static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
     576             :                                         struct pvfs_filename *name,
     577             :                                         struct ntvfs_handle *ntvfs,
     578             :                                         struct brl_handle **_h)
     579             : {
     580             :         DATA_BLOB odb_key, key;
     581             :         NTSTATUS status;
     582             :         struct brl_handle *h;
     583             : 
     584      188961 :         status = pvfs_locking_key(name, mem_ctx, &odb_key);
     585      188961 :         NT_STATUS_NOT_OK_RETURN(status);
     586             : 
     587      188961 :         if (name->stream_name == NULL) {
     588      188854 :                 key = odb_key;
     589             :         } else {
     590         107 :                 key = data_blob_talloc(mem_ctx, NULL, 
     591             :                                        odb_key.length + strlen(name->stream_name) + 1);
     592         107 :                 NT_STATUS_HAVE_NO_MEMORY(key.data);
     593         107 :                 memcpy(key.data, odb_key.data, odb_key.length);
     594         214 :                 memcpy(key.data + odb_key.length, 
     595         214 :                        name->stream_name, strlen(name->stream_name) + 1);
     596         107 :                 data_blob_free(&odb_key);
     597             :         }
     598             : 
     599      188961 :         h = brlock_create_handle(mem_ctx, ntvfs, &key);
     600      188961 :         NT_STATUS_HAVE_NO_MEMORY(h);
     601             : 
     602      188961 :         *_h = h;
     603      188961 :         return NT_STATUS_OK;
     604             : }
     605             : 
     606             : /*
     607             :   create a new file
     608             : */
     609       96994 : static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 
     610             :                                  struct ntvfs_request *req, 
     611             :                                  struct pvfs_filename *name, 
     612             :                                  union smb_open *io)
     613             : {
     614             :         struct pvfs_file *f;
     615             :         NTSTATUS status;
     616             :         struct ntvfs_handle *h;
     617             :         int flags, fd;
     618             :         struct odb_lock *lck;
     619       96994 :         uint32_t create_options = io->generic.in.create_options;
     620       96994 :         uint32_t share_access = io->generic.in.share_access;
     621       96994 :         uint32_t access_mask = io->generic.in.access_mask;
     622             :         mode_t mode;
     623             :         uint32_t attrib;
     624             :         bool del_on_close;
     625             :         struct pvfs_filename *parent;
     626       96994 :         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
     627       96994 :         bool allow_level_II_oplock = false;
     628       96994 :         struct security_descriptor *sd = NULL;
     629             : 
     630       96994 :         if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
     631           0 :                 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
     632             :                          io->ntcreatex.in.file_attr, name->original_name));
     633           0 :                 return NT_STATUS_INVALID_PARAMETER;
     634             :         }
     635             : 
     636       96994 :         if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
     637           1 :                 DEBUG(3,(__location__ ": Invalid encryption request for %s\n",
     638             :                          name->original_name));
     639           1 :                 return NT_STATUS_ACCESS_DENIED;
     640             :         }
     641             :             
     642       97024 :         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
     643          31 :             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
     644           3 :                 DEBUG(4,(__location__ ": Invalid delete on close for readonly file %s\n",
     645             :                          name->original_name));
     646           3 :                 return NT_STATUS_CANNOT_DELETE;
     647             :         }
     648             : 
     649       96990 :         sd = io->ntcreatex.in.sec_desc;
     650       96990 :         status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd);
     651       96990 :         NT_STATUS_NOT_OK_RETURN(status);
     652             : 
     653             :         /* check that the parent isn't opened with delete on close set */
     654       96990 :         status = pvfs_resolve_parent(pvfs, req, name, &parent);
     655       96990 :         if (NT_STATUS_IS_OK(status)) {
     656             :                 DATA_BLOB locking_key;
     657       96990 :                 status = pvfs_locking_key(parent, req, &locking_key);
     658       96992 :                 NT_STATUS_NOT_OK_RETURN(status);
     659       96990 :                 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
     660             :                                             &del_on_close, NULL);
     661       96990 :                 NT_STATUS_NOT_OK_RETURN(status);
     662       96990 :                 if (del_on_close) {
     663           2 :                         return NT_STATUS_DELETE_PENDING;
     664             :                 }
     665             :         }
     666             : 
     667       96988 :         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
     668       92635 :                 flags = O_RDWR;
     669             :         } else {
     670        4353 :                 flags = O_RDONLY;
     671             :         }
     672             : 
     673       96988 :         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
     674       96988 :         NT_STATUS_NOT_OK_RETURN(status);
     675             : 
     676       96988 :         f = talloc(h, struct pvfs_file);
     677       96988 :         NT_STATUS_HAVE_NO_MEMORY(f);
     678             : 
     679       96988 :         f->handle = talloc(f, struct pvfs_file_handle);
     680       96988 :         NT_STATUS_HAVE_NO_MEMORY(f->handle);
     681             : 
     682       96988 :         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
     683       96988 :         mode = pvfs_fileperms(pvfs, attrib);
     684             : 
     685             :         /* create the file */
     686       96988 :         fd = pvfs_sys_open(pvfs, name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode, name->allow_override);
     687       96988 :         if (fd == -1) {
     688           0 :                 return pvfs_map_errno(pvfs, errno);
     689             :         }
     690             : 
     691       96988 :         pvfs_xattr_unlink_hook(pvfs, name->full_name);
     692             : 
     693             :         /* if this was a stream create then create the stream as well */
     694       96988 :         if (name->stream_name) {
     695          20 :                 status = pvfs_stream_create(pvfs, name, fd);
     696          20 :                 if (!NT_STATUS_IS_OK(status)) {
     697           0 :                         close(fd);
     698           0 :                         return status;
     699             :                 }
     700             :         }
     701             : 
     702             :         /* re-resolve the open fd */
     703       96988 :         status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
     704       96988 :         if (!NT_STATUS_IS_OK(status)) {
     705           0 :                 close(fd);
     706           0 :                 return status;
     707             :         }
     708             : 
     709             :         /* support initial alloc sizes */
     710       96988 :         name->dos.alloc_size = io->ntcreatex.in.alloc_size;
     711       96988 :         name->dos.attrib = attrib;
     712       96988 :         status = pvfs_dosattrib_save(pvfs, name, fd);
     713       96988 :         if (!NT_STATUS_IS_OK(status)) {
     714           0 :                 goto cleanup_delete;
     715             :         }
     716             : 
     717             : 
     718       96988 :         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd);
     719       96988 :         if (!NT_STATUS_IS_OK(status)) {
     720           0 :                 goto cleanup_delete;
     721             :         }
     722             : 
     723       96988 :         if (io->generic.in.query_maximal_access) {
     724           0 :                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
     725             :                                                      &io->generic.out.maximal_access);
     726           0 :                 if (!NT_STATUS_IS_OK(status)) {
     727           0 :                         goto cleanup_delete;
     728             :                 }
     729             :         }
     730             : 
     731       96988 :         if (io->generic.in.query_on_disk_id) {
     732           0 :                 ZERO_ARRAY(io->generic.out.on_disk_id);
     733           0 :                 SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
     734           0 :                 SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
     735             :         }
     736             : 
     737             :         /* form the lock context used for byte range locking and
     738             :            opendb locking */
     739       96988 :         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
     740       96988 :         if (!NT_STATUS_IS_OK(status)) {
     741           0 :                 goto cleanup_delete;
     742             :         }
     743             : 
     744       96988 :         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
     745       96988 :         if (!NT_STATUS_IS_OK(status)) {
     746           0 :                 goto cleanup_delete;
     747             :         }
     748             : 
     749             :         /* grab a lock on the open file record */
     750       96988 :         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
     751       96988 :         if (lck == NULL) {
     752           0 :                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
     753             :                          name->full_name));
     754             :                 /* we were supposed to do a blocking lock, so something
     755             :                    is badly wrong! */
     756           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     757           0 :                 goto cleanup_delete;
     758             :         }
     759             : 
     760       96988 :         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
     761          20 :                 del_on_close = true;
     762             :         } else {
     763       96968 :                 del_on_close = false;
     764             :         }
     765             : 
     766       96988 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
     767           0 :                 oplock_level = OPLOCK_NONE;
     768       96988 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
     769          65 :                 oplock_level = OPLOCK_BATCH;
     770       96923 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
     771          22 :                 oplock_level = OPLOCK_EXCLUSIVE;
     772             :         }
     773             : 
     774       96988 :         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
     775       96714 :                 allow_level_II_oplock = true;
     776             :         }
     777             : 
     778       96988 :         status = odb_can_open(lck, name->stream_id,
     779             :                               share_access, access_mask, del_on_close,
     780             :                               io->generic.in.open_disposition, false);
     781       96988 :         if (!NT_STATUS_IS_OK(status)) {
     782           0 :                 talloc_free(lck);
     783             :                 /* bad news, we must have hit a race - we don't delete the file
     784             :                    here as the most likely scenario is that someone else created
     785             :                    the file at the same time */
     786           0 :                 close(fd);
     787           0 :                 return status;
     788             :         }
     789             : 
     790       96988 :         f->ntvfs             = h;
     791       96988 :         f->pvfs              = pvfs;
     792       96988 :         f->pending_list      = NULL;
     793       96988 :         f->lock_count        = 0;
     794       96988 :         f->share_access      = io->generic.in.share_access;
     795       96988 :         f->access_mask       = access_mask;
     796       96988 :         f->impersonation     = io->generic.in.impersonation;
     797       96988 :         f->notify_buffer     = NULL;
     798       96988 :         f->search            = NULL;
     799             : 
     800       96988 :         f->handle->pvfs              = pvfs;
     801       96988 :         f->handle->name              = talloc_steal(f->handle, name);
     802       96988 :         f->handle->fd                = fd;
     803       96988 :         f->handle->create_options    = io->generic.in.create_options;
     804       96988 :         f->handle->private_flags     = io->generic.in.private_flags;
     805       96988 :         f->handle->seek_offset       = 0;
     806       96988 :         f->handle->position          = 0;
     807       96988 :         f->handle->mode              = 0;
     808       96988 :         f->handle->oplock            = NULL;
     809       96988 :         f->handle->have_opendb_entry = true;
     810       96988 :         ZERO_STRUCT(f->handle->write_time);
     811       96988 :         f->handle->open_completed    = false;
     812             : 
     813      193972 :         status = odb_open_file(lck, f->handle, name->full_name,
     814       96988 :                                &f->handle->fd, name->dos.write_time,
     815             :                                allow_level_II_oplock,
     816             :                                oplock_level, &oplock_granted);
     817       96988 :         talloc_free(lck);
     818       96988 :         if (!NT_STATUS_IS_OK(status)) {
     819             :                 /* bad news, we must have hit a race - we don't delete the file
     820             :                    here as the most likely scenario is that someone else created
     821             :                    the file at the same time */
     822           0 :                 close(fd);
     823           0 :                 return status;
     824             :         }
     825             : 
     826       96988 :         DLIST_ADD(pvfs->files.list, f);
     827             : 
     828             :         /* setup a destructor to avoid file descriptor leaks on
     829             :            abnormal termination */
     830       96988 :         talloc_set_destructor(f, pvfs_fnum_destructor);
     831       96988 :         talloc_set_destructor(f->handle, pvfs_handle_destructor);
     832             : 
     833       96988 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
     834           0 :                 oplock_granted = OPLOCK_BATCH;
     835       96988 :         } else if (oplock_granted != OPLOCK_NONE) {
     836          87 :                 status = pvfs_setup_oplock(f, oplock_granted);
     837          87 :                 if (!NT_STATUS_IS_OK(status)) {
     838           0 :                         return status;
     839             :                 }
     840             :         }
     841             : 
     842       96988 :         io->generic.out.oplock_level  = oplock_granted;
     843       96988 :         io->generic.out.file.ntvfs    = f->ntvfs;
     844       96988 :         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
     845       96988 :         io->generic.out.create_time   = name->dos.create_time;
     846       96988 :         io->generic.out.access_time   = name->dos.access_time;
     847       96988 :         io->generic.out.write_time    = name->dos.write_time;
     848       96988 :         io->generic.out.change_time   = name->dos.change_time;
     849       96988 :         io->generic.out.attrib        = name->dos.attrib;
     850       96988 :         io->generic.out.alloc_size    = name->dos.alloc_size;
     851       96988 :         io->generic.out.size          = name->st.st_size;
     852       96988 :         io->generic.out.file_type     = FILE_TYPE_DISK;
     853       96988 :         io->generic.out.ipc_state     = 0;
     854       96988 :         io->generic.out.is_directory  = 0;
     855             : 
     856             :         /* success - keep the file handle */
     857       96988 :         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
     858       96988 :         if (!NT_STATUS_IS_OK(status)) {
     859           0 :                 goto cleanup_delete;
     860             :         }
     861             : 
     862       96988 :         f->handle->open_completed = true;
     863             : 
     864       96988 :         notify_trigger(pvfs->notify_context, 
     865             :                        NOTIFY_ACTION_ADDED, 
     866             :                        FILE_NOTIFY_CHANGE_FILE_NAME,
     867       96988 :                        name->full_name);
     868             : 
     869       96988 :         return NT_STATUS_OK;
     870             : 
     871           0 : cleanup_delete:
     872           0 :         close(fd);
     873           0 :         pvfs_sys_unlink(pvfs, name->full_name, name->allow_override);
     874           0 :         return status;
     875             : }
     876             : 
     877             : /*
     878             :   state of a pending retry
     879             : */
     880             : struct pvfs_odb_retry {
     881             :         struct ntvfs_module_context *ntvfs;
     882             :         struct ntvfs_request *req;
     883             :         DATA_BLOB odb_locking_key;
     884             :         void *io;
     885             :         void *private_data;
     886             :         void (*callback)(struct pvfs_odb_retry *r,
     887             :                          struct ntvfs_module_context *ntvfs,
     888             :                          struct ntvfs_request *req,
     889             :                          void *io,
     890             :                          void *private_data,
     891             :                          enum pvfs_wait_notice reason);
     892             : };
     893             : 
     894             : /* destroy a pending request */
     895        2919 : static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
     896             : {
     897        2919 :         struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
     898             :                                   struct pvfs_state);
     899        2919 :         if (r->odb_locking_key.data) {
     900             :                 struct odb_lock *lck;
     901        2833 :                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
     902        2833 :                 if (lck != NULL) {
     903        2833 :                         odb_remove_pending(lck, r);
     904             :                 }
     905        2833 :                 talloc_free(lck);
     906             :         }
     907        2919 :         return 0;
     908             : }
     909             : 
     910        2879 : static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
     911             : {
     912        2879 :         struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
     913             : 
     914        2879 :         if (reason == PVFS_WAIT_EVENT) {
     915             :                 /*
     916             :                  * The pending odb entry is already removed.
     917             :                  * We use a null locking key to indicate this
     918             :                  * to the destructor.
     919             :                  */
     920          86 :                 data_blob_free(&r->odb_locking_key);
     921             :         }
     922             : 
     923        2879 :         r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
     924        2879 : }
     925             : 
     926             : /*
     927             :   setup for a retry of a request that was rejected
     928             :   by odb_can_open()
     929             : */
     930        2919 : NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
     931             :                               struct ntvfs_request *req,
     932             :                               struct odb_lock *lck,
     933             :                               struct timeval end_time,
     934             :                               void *io,
     935             :                               void *private_data,
     936             :                               void (*callback)(struct pvfs_odb_retry *r,
     937             :                                                struct ntvfs_module_context *ntvfs,
     938             :                                                struct ntvfs_request *req,
     939             :                                                void *io,
     940             :                                                void *private_data,
     941             :                                                enum pvfs_wait_notice reason))
     942             : {
     943        2919 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     944             :                                   struct pvfs_state);
     945             :         struct pvfs_odb_retry *r;
     946             :         struct pvfs_wait *wait_handle;
     947             :         NTSTATUS status;
     948             : 
     949        2919 :         r = talloc(req, struct pvfs_odb_retry);
     950        2919 :         NT_STATUS_HAVE_NO_MEMORY(r);
     951             : 
     952        2919 :         r->ntvfs = ntvfs;
     953        2919 :         r->req = req;
     954        2919 :         r->io = io;
     955        2919 :         r->private_data = private_data;
     956        2919 :         r->callback = callback;
     957        2919 :         r->odb_locking_key = odb_get_key(r, lck);
     958        2919 :         if (r->odb_locking_key.data == NULL) {
     959           0 :                 return NT_STATUS_NO_MEMORY;
     960             :         }
     961             : 
     962             :         /* setup a pending lock */
     963        2919 :         status = odb_open_file_pending(lck, r);
     964        2919 :         if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
     965             :                 /*
     966             :                  * maybe only a unix application
     967             :                  * has the file open
     968             :                  */
     969           0 :                 data_blob_free(&r->odb_locking_key);
     970        2919 :         } else if (!NT_STATUS_IS_OK(status)) {
     971           0 :                 return status;
     972             :         }
     973             : 
     974        2919 :         talloc_free(lck);
     975             : 
     976        2919 :         talloc_set_destructor(r, pvfs_odb_retry_destructor);
     977             : 
     978        2919 :         wait_handle = pvfs_wait_message(pvfs, req,
     979             :                                         MSG_PVFS_RETRY_OPEN, end_time,
     980             :                                         pvfs_odb_retry_callback, r);
     981        2919 :         if (wait_handle == NULL) {
     982           0 :                 return NT_STATUS_NO_MEMORY;
     983             :         }
     984             : 
     985        2919 :         talloc_steal(r, wait_handle);
     986             : 
     987        2919 :         return NT_STATUS_OK;
     988             : }
     989             : 
     990             : /*
     991             :   retry an open after a sharing violation
     992             : */
     993        2824 : static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
     994             :                                     struct ntvfs_module_context *ntvfs,
     995             :                                     struct ntvfs_request *req,
     996             :                                     void *_io,
     997             :                                     void *private_data,
     998             :                                     enum pvfs_wait_notice reason)
     999             : {
    1000        2824 :         union smb_open *io = talloc_get_type(_io, union smb_open);
    1001        2824 :         struct timeval *final_timeout = NULL;
    1002             :         NTSTATUS status;
    1003             : 
    1004        2824 :         if (private_data) {
    1005           0 :                 final_timeout = talloc_get_type(private_data,
    1006             :                                                 struct timeval);
    1007             :         }
    1008             : 
    1009             :         /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
    1010             :            just a bug in their server, but we better do the same */
    1011        2824 :         if (reason == PVFS_WAIT_CANCEL) {
    1012        2761 :                 return;
    1013             :         }
    1014             : 
    1015        2823 :         if (reason == PVFS_WAIT_TIMEOUT) {
    1016        2750 :                 if (final_timeout &&
    1017           0 :                     !timeval_expired(final_timeout)) {
    1018             :                         /*
    1019             :                          * we need to retry periodictly
    1020             :                          * after an EAGAIN as there's
    1021             :                          * no way the kernel tell us
    1022             :                          * an oplock is released.
    1023             :                          */
    1024           0 :                         goto retry;
    1025             :                 }
    1026             :                 /* if it timed out, then give the failure
    1027             :                    immediately */
    1028        2750 :                 talloc_free(r);
    1029        2750 :                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
    1030        2750 :                 req->async_states->send_fn(req);
    1031        2750 :                 return;
    1032             :         }
    1033             : 
    1034          73 : retry:
    1035          73 :         talloc_free(r);
    1036             : 
    1037             :         /* try the open again, which could trigger another retry setup
    1038             :            if it wants to, so we have to unmark the async flag so we
    1039             :            will know if it does a second async reply */
    1040          73 :         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
    1041             : 
    1042          73 :         status = pvfs_open(ntvfs, req, io);
    1043          73 :         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
    1044             :                 /* the 2nd try also replied async, so we don't send
    1045             :                    the reply yet */
    1046           9 :                 return;
    1047             :         }
    1048             : 
    1049             :         /* re-mark it async, just in case someone up the chain does
    1050             :            paranoid checking */
    1051          64 :         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
    1052             : 
    1053             :         /* send the reply up the chain */
    1054          64 :         req->async_states->status = status;
    1055          64 :         req->async_states->send_fn(req);
    1056             : }
    1057             : 
    1058             : 
    1059             : /*
    1060             :   special handling for openx DENY_DOS semantics
    1061             : 
    1062             :   This function attempts a reference open using an existing handle. If its allowed,
    1063             :   then it returns NT_STATUS_OK, otherwise it returns any other code and normal
    1064             :   open processing continues.
    1065             : */
    1066         768 : static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
    1067             :                                    struct ntvfs_request *req, union smb_open *io,
    1068             :                                    struct pvfs_file *f, struct odb_lock *lck)
    1069             : {
    1070         768 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1071             :                                   struct pvfs_state);
    1072             :         struct pvfs_file *f2;
    1073             :         struct pvfs_filename *name;
    1074             :         NTSTATUS status;
    1075             : 
    1076             :         /* search for an existing open with the right parameters. Note
    1077             :            the magic ntcreatex options flag, which is set in the
    1078             :            generic mapping code. This might look ugly, but its
    1079             :            actually pretty much now w2k does it internally as well. 
    1080             :            
    1081             :            If you look at the BASE-DENYDOS test you will see that a
    1082             :            DENY_DOS is a very special case, and in the right
    1083             :            circumstances you actually get the _same_ handle back
    1084             :            twice, rather than a new handle.
    1085             :         */
    1086        1809 :         for (f2=pvfs->files.list;f2;f2=f2->next) {
    1087        1544 :                 if (f2 != f &&
    1088         776 :                     f2->ntvfs->session_info == req->session_info &&
    1089         776 :                     f2->ntvfs->smbpid == req->smbpid &&
    1090         388 :                     (f2->handle->private_flags &
    1091             :                      (NTCREATEX_FLAG_DENY_DOS |
    1092         131 :                       NTCREATEX_FLAG_DENY_FCB)) &&
    1093         246 :                     (f2->access_mask & SEC_FILE_WRITE_DATA) &&
    1094         115 :                     strcasecmp_m(f2->handle->name->original_name, 
    1095             :                                io->generic.in.fname)==0) {
    1096         115 :                         break;
    1097             :                 }
    1098             :         }
    1099             : 
    1100         768 :         if (!f2) {
    1101         653 :                 return NT_STATUS_SHARING_VIOLATION;
    1102             :         }
    1103             : 
    1104             :         /* quite an insane set of semantics ... */
    1105         163 :         if (is_exe_filename(io->generic.in.fname) &&
    1106          48 :             (f2->handle->private_flags & NTCREATEX_FLAG_DENY_DOS)) {
    1107          12 :                 return NT_STATUS_SHARING_VIOLATION;
    1108             :         }
    1109             : 
    1110             :         /*
    1111             :           setup a reference to the existing handle
    1112             :          */
    1113         103 :         talloc_free(f->handle);
    1114         103 :         f->handle = talloc_reference(f, f2->handle);
    1115             : 
    1116         103 :         talloc_free(lck);
    1117             : 
    1118         103 :         name = f->handle->name;
    1119             : 
    1120         103 :         io->generic.out.oplock_level  = OPLOCK_NONE;
    1121         103 :         io->generic.out.file.ntvfs    = f->ntvfs;
    1122         103 :         io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
    1123         103 :         io->generic.out.create_time   = name->dos.create_time;
    1124         103 :         io->generic.out.access_time   = name->dos.access_time;
    1125         103 :         io->generic.out.write_time    = name->dos.write_time;
    1126         103 :         io->generic.out.change_time   = name->dos.change_time;
    1127         103 :         io->generic.out.attrib        = name->dos.attrib;
    1128         103 :         io->generic.out.alloc_size    = name->dos.alloc_size;
    1129         103 :         io->generic.out.size          = name->st.st_size;
    1130         103 :         io->generic.out.file_type     = FILE_TYPE_DISK;
    1131         103 :         io->generic.out.ipc_state     = 0;
    1132         103 :         io->generic.out.is_directory  = 0;
    1133             :  
    1134         103 :         status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
    1135         103 :         NT_STATUS_NOT_OK_RETURN(status);
    1136             : 
    1137         103 :         return NT_STATUS_OK;
    1138             : }
    1139             : 
    1140             : 
    1141             : 
    1142             : /*
    1143             :   setup for a open retry after a sharing violation
    1144             : */
    1145        2967 : static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
    1146             :                                       struct ntvfs_request *req, 
    1147             :                                       union smb_open *io,
    1148             :                                       struct pvfs_file *f,
    1149             :                                       struct odb_lock *lck,
    1150             :                                       NTSTATUS parent_status)
    1151             : {
    1152        2967 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1153             :                                   struct pvfs_state);
    1154             :         NTSTATUS status;
    1155             :         struct timeval end_time;
    1156        2967 :         struct timeval *final_timeout = NULL;
    1157             : 
    1158        2967 :         if (io->generic.in.private_flags &
    1159             :             (NTCREATEX_FLAG_DENY_DOS | NTCREATEX_FLAG_DENY_FCB)) {
    1160             :                 /* see if we can satisfy the request using the special DENY_DOS
    1161             :                    code */
    1162         768 :                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
    1163         768 :                 if (NT_STATUS_IS_OK(status)) {
    1164         103 :                         return status;
    1165             :                 }
    1166             :         }
    1167             : 
    1168             :         /* the retry should allocate a new file handle */
    1169        2864 :         talloc_free(f);
    1170             : 
    1171        2864 :         if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
    1172        2793 :                 end_time = timeval_add(&req->statistics.request_time,
    1173             :                                        0, pvfs->sharing_violation_delay);
    1174          71 :         } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    1175          71 :                 end_time = timeval_add(&req->statistics.request_time,
    1176             :                                        pvfs->oplock_break_timeout, 0);
    1177           0 :         } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
    1178             :                 /*
    1179             :                  * we got EAGAIN which means a unix application
    1180             :                  * has an oplock or share mode
    1181             :                  *
    1182             :                  * we retry every 4/5 of the sharing violation delay
    1183             :                  * to see if the unix application
    1184             :                  * has released the oplock or share mode.
    1185             :                  */
    1186           0 :                 final_timeout = talloc(req, struct timeval);
    1187           0 :                 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
    1188           0 :                 *final_timeout = timeval_add(&req->statistics.request_time,
    1189             :                                              pvfs->oplock_break_timeout,
    1190             :                                              0);
    1191           0 :                 end_time = timeval_current_ofs_usec((pvfs->sharing_violation_delay*4)/5);
    1192           0 :                 end_time = timeval_min(final_timeout, &end_time);
    1193             :         } else {
    1194           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1195             :         }
    1196             : 
    1197        2864 :         return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
    1198             :                                     final_timeout, pvfs_retry_open_sharing);
    1199             : }
    1200             : 
    1201             : /*
    1202             :   open a file
    1203             : */
    1204      478260 : NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
    1205             :                    struct ntvfs_request *req, union smb_open *io)
    1206             : {
    1207      478260 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1208             :                                   struct pvfs_state);
    1209      478260 :         int flags = 0;
    1210             :         struct pvfs_filename *name;
    1211             :         struct pvfs_file *f;
    1212             :         struct ntvfs_handle *h;
    1213             :         NTSTATUS status;
    1214             :         int fd, count;
    1215             :         struct odb_lock *lck;
    1216             :         uint32_t create_options;
    1217             :         uint32_t create_options_must_ignore_mask;
    1218             :         uint32_t share_access;
    1219             :         uint32_t access_mask;
    1220      478260 :         uint32_t create_action = NTCREATEX_ACTION_EXISTED;
    1221             :         bool del_on_close;
    1222      478260 :         bool stream_existed, stream_truncate=false;
    1223      478260 :         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
    1224      478260 :         bool allow_level_II_oplock = false;
    1225             : 
    1226             :         /* use the generic mapping code to avoid implementing all the
    1227             :            different open calls. */
    1228      689278 :         if (io->generic.level != RAW_OPEN_GENERIC &&
    1229      211025 :             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
    1230      210928 :                 return ntvfs_map_open(ntvfs, req, io);
    1231             :         }
    1232             : 
    1233      267332 :         ZERO_STRUCT(io->generic.out);
    1234             : 
    1235      267332 :         create_options = io->generic.in.create_options;
    1236      267332 :         share_access   = io->generic.in.share_access;
    1237      267332 :         access_mask    = io->generic.in.access_mask;
    1238             : 
    1239      267332 :         if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
    1240           2 :                 DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
    1241             :                          share_access, io->ntcreatex.in.fname));
    1242           2 :                 return NT_STATUS_INVALID_PARAMETER;
    1243             :         }
    1244             : 
    1245             :         /*
    1246             :          * These options are ignored,
    1247             :          * but we reuse some of them as private values for the generic mapping
    1248             :          */
    1249      267330 :         create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
    1250      267330 :         create_options &= ~create_options_must_ignore_mask;
    1251             : 
    1252      267330 :         if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
    1253           4 :                 DEBUG(2,(__location__ " create_options 0x%x not supported\n", 
    1254             :                          create_options));
    1255           4 :                 return NT_STATUS_NOT_SUPPORTED;
    1256             :         }
    1257             : 
    1258      267326 :         if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
    1259          20 :                 DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
    1260             :                          create_options, io->ntcreatex.in.fname));
    1261          20 :                 return NT_STATUS_INVALID_PARAMETER;
    1262             :         }
    1263             : 
    1264             :         /* TODO: When we implement HSM, add a hook here not to pull
    1265             :          * the actual file off tape, when this option is passed from
    1266             :          * the client */
    1267      267306 :         if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
    1268             :                 /* no-op */
    1269             :         }
    1270             : 
    1271             :         /* TODO: If (unlikely) Linux does a good compressed
    1272             :          * filesystem, we might need an ioctl call for this */
    1273      267306 :         if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
    1274             :                 /* no-op */
    1275             :         }
    1276             : 
    1277      267306 :         if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
    1278           2 :                 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
    1279             :         }
    1280             : 
    1281             :         /* Open the file with sync, if they asked for it, but
    1282             :            'strict sync = no' turns this client request into a no-op */
    1283             :         if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
    1284             :                 flags |= O_SYNC;
    1285             :         }
    1286             : 
    1287             : 
    1288             :         /* other create options are not allowed */
    1289      399414 :         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
    1290      132108 :             !(access_mask & SEC_STD_DELETE)) {
    1291          35 :                 DEBUG(3,(__location__ ": Invalid delete_on_close option 0x%08x with access_mask 0x%08x for %s\n",
    1292             :                          create_options, access_mask, io->ntcreatex.in.fname));
    1293          35 :                 return NT_STATUS_INVALID_PARAMETER;
    1294             :         }
    1295             : 
    1296      267271 :         if (access_mask & SEC_MASK_INVALID) {
    1297         309 :                 return NT_STATUS_ACCESS_DENIED;
    1298             :         }
    1299             : 
    1300             :         /* what does this bit really mean?? */
    1301      469267 :         if (req->ctx->protocol >= PROTOCOL_SMB2_02 &&
    1302      202305 :             access_mask == SEC_STD_SYNCHRONIZE) {
    1303           4 :                 return NT_STATUS_ACCESS_DENIED;
    1304             :         }
    1305             : 
    1306             :         /* cope with non-zero root_fid */
    1307      266958 :         if (io->ntcreatex.in.root_fid.ntvfs != NULL) {
    1308       16656 :                 f = pvfs_find_fd(pvfs, req, io->ntcreatex.in.root_fid.ntvfs);
    1309       16656 :                 if (f == NULL) {
    1310           0 :                         return NT_STATUS_INVALID_HANDLE;
    1311             :                 }
    1312       16656 :                 if (f->handle->fd != -1) {
    1313           0 :                         return NT_STATUS_INVALID_DEVICE_REQUEST;
    1314             :                 }
    1315       33312 :                 io->ntcreatex.in.fname = talloc_asprintf(req, "%s\\%s", 
    1316       16656 :                                                          f->handle->name->original_name,
    1317             :                                                          io->ntcreatex.in.fname);
    1318       16656 :                 NT_STATUS_HAVE_NO_MEMORY(io->ntcreatex.in.fname);                    
    1319             :         }
    1320             : 
    1321      266958 :         if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
    1322             :                                           FILE_ATTRIBUTE_VOLUME| 
    1323             :                                           (~FILE_ATTRIBUTE_ALL_MASK))) {
    1324          29 :                 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
    1325             :                          io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
    1326          29 :                 return NT_STATUS_INVALID_PARAMETER;
    1327             :         }
    1328             : 
    1329             :         /* we ignore some file_attr bits */
    1330      266929 :         io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED | 
    1331             :                                         FILE_ATTRIBUTE_COMPRESSED |
    1332             :                                         FILE_ATTRIBUTE_REPARSE_POINT |
    1333             :                                         FILE_ATTRIBUTE_SPARSE |
    1334             :                                         FILE_ATTRIBUTE_NORMAL);
    1335             : 
    1336             :         /* resolve the cifs name to a posix name */
    1337      266929 :         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
    1338             :                                    PVFS_RESOLVE_STREAMS, &name);
    1339      266929 :         if (!NT_STATUS_IS_OK(status)) {
    1340         111 :                 return status;
    1341             :         }
    1342             : 
    1343             :         /* if the client specified that it must not be a directory then
    1344             :            check that it isn't */
    1345      273426 :         if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
    1346        6608 :             (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
    1347         230 :                 return NT_STATUS_FILE_IS_A_DIRECTORY;
    1348             :         }
    1349             : 
    1350             :         /* if the client specified that it must be a directory then
    1351             :            check that it is */
    1352      359098 :         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
    1353       92529 :             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
    1354         113 :                 return NT_STATUS_NOT_A_DIRECTORY;
    1355             :         }
    1356             : 
    1357             :         /* directory opens are handled separately */
    1358      526549 :         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
    1359      260097 :             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
    1360       11145 :                 return pvfs_open_directory(pvfs, req, name, io);
    1361             :         }
    1362             : 
    1363             :         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
    1364             :            open doesn't match */
    1365      255330 :         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
    1366             : 
    1367      255330 :         switch (io->generic.in.open_disposition) {
    1368        3516 :         case NTCREATEX_DISP_SUPERSEDE:
    1369             :         case NTCREATEX_DISP_OVERWRITE_IF:
    1370        3516 :                 if (name->stream_name == NULL) {
    1371        3504 :                         flags = O_TRUNC;
    1372             :                 } else {
    1373          12 :                         stream_truncate = true;
    1374             :                 }
    1375        3516 :                 create_action = NTCREATEX_ACTION_TRUNCATED;
    1376        3516 :                 break;
    1377             : 
    1378      147932 :         case NTCREATEX_DISP_OPEN:
    1379      147932 :                 if (!name->stream_exists) {
    1380       66162 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1381             :                 }
    1382       81770 :                 flags = 0;
    1383       81770 :                 break;
    1384             : 
    1385         799 :         case NTCREATEX_DISP_OVERWRITE:
    1386         799 :                 if (!name->stream_exists) {
    1387           5 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1388             :                 }
    1389         794 :                 if (name->stream_name == NULL) {
    1390         794 :                         flags = O_TRUNC;
    1391             :                 } else {
    1392           0 :                         stream_truncate = true;
    1393             :                 }
    1394         794 :                 create_action = NTCREATEX_ACTION_TRUNCATED;
    1395         794 :                 break;
    1396             : 
    1397       82974 :         case NTCREATEX_DISP_CREATE:
    1398       82974 :                 if (name->stream_exists) {
    1399         151 :                         return NT_STATUS_OBJECT_NAME_COLLISION;
    1400             :                 }
    1401       82823 :                 flags = 0;
    1402       82823 :                 break;
    1403             : 
    1404       20103 :         case NTCREATEX_DISP_OPEN_IF:
    1405       20103 :                 flags = 0;
    1406       20103 :                 break;
    1407             : 
    1408           6 :         default:
    1409           6 :                 DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
    1410             :                          io->generic.in.open_disposition, name->original_name));
    1411           6 :                 return NT_STATUS_INVALID_PARAMETER;
    1412             :         }
    1413             : 
    1414             :         /* handle creating a new file separately */
    1415      189006 :         if (!name->exists) {
    1416       96994 :                 status = pvfs_create_file(pvfs, req, name, io);
    1417       96994 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
    1418       96994 :                         return status;
    1419             :                 }
    1420             : 
    1421             :                 /* we've hit a race - the file was created during this call */
    1422           0 :                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
    1423           0 :                         return status;
    1424             :                 }
    1425             : 
    1426             :                 /* try re-resolving the name */
    1427           0 :                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
    1428           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1429           0 :                         return status;
    1430             :                 }
    1431             :                 /* fall through to a normal open */
    1432             :         }
    1433             : 
    1434       92521 :         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
    1435         509 :             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
    1436           4 :                 return NT_STATUS_CANNOT_DELETE;
    1437             :         }
    1438             : 
    1439             :         /* check the security descriptor */
    1440       92008 :         status = pvfs_access_check(pvfs, req, name, &access_mask);
    1441       92008 :         NT_STATUS_NOT_OK_RETURN(status);
    1442             : 
    1443       91973 :         if (io->generic.in.query_maximal_access) {
    1444          12 :                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
    1445             :                                                      &io->generic.out.maximal_access);
    1446          12 :                 NT_STATUS_NOT_OK_RETURN(status);
    1447             :         }
    1448             : 
    1449       91973 :         if (io->generic.in.query_on_disk_id) {
    1450          10 :                 ZERO_ARRAY(io->generic.out.on_disk_id);
    1451          10 :                 SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
    1452          10 :                 SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
    1453             :         }
    1454             : 
    1455       91973 :         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
    1456       91973 :         NT_STATUS_NOT_OK_RETURN(status);
    1457             : 
    1458       91973 :         f = talloc(h, struct pvfs_file);
    1459       91973 :         if (f == NULL) {
    1460           0 :                 return NT_STATUS_NO_MEMORY;
    1461             :         }
    1462             : 
    1463       91973 :         f->handle = talloc(f, struct pvfs_file_handle);
    1464       91973 :         if (f->handle == NULL) {
    1465           0 :                 return NT_STATUS_NO_MEMORY;
    1466             :         }
    1467             : 
    1468       91973 :         f->ntvfs         = h;
    1469       91973 :         f->pvfs          = pvfs;
    1470       91973 :         f->pending_list  = NULL;
    1471       91973 :         f->lock_count    = 0;
    1472       91973 :         f->share_access  = io->generic.in.share_access;
    1473       91973 :         f->access_mask   = access_mask;
    1474       91973 :         f->impersonation = io->generic.in.impersonation;
    1475       91973 :         f->notify_buffer = NULL;
    1476       91973 :         f->search        = NULL;
    1477             : 
    1478       91973 :         f->handle->pvfs              = pvfs;
    1479       91973 :         f->handle->fd                = -1;
    1480       91973 :         f->handle->name              = talloc_steal(f->handle, name);
    1481       91973 :         f->handle->create_options    = io->generic.in.create_options;
    1482       91973 :         f->handle->private_flags     = io->generic.in.private_flags;
    1483       91973 :         f->handle->seek_offset       = 0;
    1484       91973 :         f->handle->position          = 0;
    1485       91973 :         f->handle->mode              = 0;
    1486       91973 :         f->handle->oplock            = NULL;
    1487       91973 :         f->handle->have_opendb_entry = false;
    1488       91973 :         ZERO_STRUCT(f->handle->write_time);
    1489       91973 :         f->handle->open_completed    = false;
    1490             : 
    1491             :         /* form the lock context used for byte range locking and
    1492             :            opendb locking */
    1493       91973 :         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
    1494       91973 :         if (!NT_STATUS_IS_OK(status)) {
    1495           0 :                 return status;
    1496             :         }
    1497             : 
    1498       91973 :         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
    1499       91973 :         if (!NT_STATUS_IS_OK(status)) {
    1500           0 :                 return status;
    1501             :         }
    1502             : 
    1503             :         /* get a lock on this file before the actual open */
    1504       91973 :         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
    1505       91973 :         if (lck == NULL) {
    1506           0 :                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
    1507             :                          name->full_name));
    1508             :                 /* we were supposed to do a blocking lock, so something
    1509             :                    is badly wrong! */
    1510           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1511             :         }
    1512             : 
    1513       91973 :         DLIST_ADD(pvfs->files.list, f);
    1514             : 
    1515             :         /* setup a destructor to avoid file descriptor leaks on
    1516             :            abnormal termination */
    1517       91973 :         talloc_set_destructor(f, pvfs_fnum_destructor);
    1518       91973 :         talloc_set_destructor(f->handle, pvfs_handle_destructor);
    1519             : 
    1520             :         /* 
    1521             :          * Only SMB2 takes care of the delete_on_close,
    1522             :          * on existing files
    1523             :          */
    1524      157892 :         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
    1525       65919 :             req->ctx->protocol >= PROTOCOL_SMB2_02) {
    1526       65895 :                 del_on_close = true;
    1527             :         } else {
    1528       26078 :                 del_on_close = false;
    1529             :         }
    1530             : 
    1531       91973 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
    1532           0 :                 oplock_level = OPLOCK_NONE;
    1533       91973 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
    1534          88 :                 oplock_level = OPLOCK_BATCH;
    1535       91885 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
    1536          50 :                 oplock_level = OPLOCK_EXCLUSIVE;
    1537             :         }
    1538             : 
    1539       91973 :         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
    1540       91912 :                 allow_level_II_oplock = true;
    1541             :         }
    1542             : 
    1543             :         /* see if we are allowed to open at the same time as existing opens */
    1544       91973 :         status = odb_can_open(lck, name->stream_id,
    1545             :                               share_access, access_mask, del_on_close,
    1546             :                               io->generic.in.open_disposition, false);
    1547             : 
    1548             :         /*
    1549             :          * on a sharing violation we need to retry when the file is closed by
    1550             :          * the other user, or after 1 second
    1551             :          * on a non granted oplock we need to retry when the file is closed by
    1552             :          * the other user, or after 30 seconds
    1553             :         */
    1554      181031 :         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    1555       92044 :              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
    1556        2967 :             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
    1557        2967 :                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
    1558             :         }
    1559             : 
    1560       89006 :         if (!NT_STATUS_IS_OK(status)) {
    1561           6 :                 talloc_free(lck);
    1562           6 :                 return status;
    1563             :         }
    1564             : 
    1565       89000 :         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
    1566       16969 :                 flags |= O_RDWR;
    1567             :         } else {
    1568       72031 :                 flags |= O_RDONLY;
    1569             :         }
    1570             : 
    1571             :         /* do the actual open */
    1572       89000 :         fd = pvfs_sys_open(pvfs, f->handle->name->full_name, flags | O_NONBLOCK, 0, name->allow_override);
    1573       89000 :         if (fd == -1) {
    1574           0 :                 status = pvfs_map_errno(f->pvfs, errno);
    1575             : 
    1576           0 :                 DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n", 
    1577             :                          nt_errstr(status), f->handle->name->full_name, errno));
    1578             :                 /*
    1579             :                  * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
    1580             :                  */
    1581           0 :                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
    1582           0 :                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
    1583           0 :                         return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
    1584             :                 }
    1585             : 
    1586           0 :                 talloc_free(lck);
    1587           0 :                 return status;
    1588             :         }
    1589             : 
    1590       89000 :         f->handle->fd = fd;
    1591             : 
    1592       89000 :         status = brlock_count(f->pvfs->brl_context, f->brl_handle, &count);
    1593       89000 :         if (!NT_STATUS_IS_OK(status)) {
    1594           0 :                 talloc_free(lck);
    1595           0 :                 return status;
    1596             :         }
    1597             : 
    1598       89000 :         if (count != 0) {
    1599          91 :                 oplock_level = OPLOCK_NONE;
    1600             :         }
    1601             : 
    1602             :         /* now really mark the file as open */
    1603      266962 :         status = odb_open_file(lck, f->handle, name->full_name,
    1604      177981 :                                &f->handle->fd, name->dos.write_time,
    1605             :                                allow_level_II_oplock,
    1606             :                                oplock_level, &oplock_granted);
    1607             : 
    1608       89000 :         if (!NT_STATUS_IS_OK(status)) {
    1609           0 :                 talloc_free(lck);
    1610           0 :                 return status;
    1611             :         }
    1612             : 
    1613       89000 :         f->handle->have_opendb_entry = true;
    1614             : 
    1615       89000 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
    1616           0 :                 oplock_granted = OPLOCK_BATCH;
    1617       89000 :         } else if (oplock_granted != OPLOCK_NONE) {
    1618          77 :                 status = pvfs_setup_oplock(f, oplock_granted);
    1619          77 :                 if (!NT_STATUS_IS_OK(status)) {
    1620           0 :                         talloc_free(lck);
    1621           0 :                         return status;
    1622             :                 }
    1623             :         }
    1624             : 
    1625       89000 :         stream_existed = name->stream_exists;
    1626             : 
    1627             :         /* if this was a stream create then create the stream as well */
    1628       89000 :         if (!name->stream_exists) {
    1629          25 :                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
    1630          25 :                 if (!NT_STATUS_IS_OK(status)) {
    1631           0 :                         talloc_free(lck);
    1632           0 :                         return status;
    1633             :                 }
    1634          25 :                 if (stream_truncate) {
    1635           3 :                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
    1636           3 :                         if (!NT_STATUS_IS_OK(status)) {
    1637           0 :                                 talloc_free(lck);
    1638           0 :                                 return status;
    1639             :                         }
    1640             :                 }
    1641             :         }
    1642             : 
    1643             :         /* re-resolve the open fd */
    1644       89000 :         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
    1645       89000 :         if (!NT_STATUS_IS_OK(status)) {
    1646           0 :                 talloc_free(lck);
    1647           0 :                 return status;
    1648             :         }
    1649             : 
    1650      177907 :         if (f->handle->name->stream_id == 0 &&
    1651      177044 :             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
    1652       88137 :              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
    1653             :                 /* for overwrite we may need to replace file permissions */
    1654        1380 :                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
    1655        1380 :                 mode_t mode = pvfs_fileperms(pvfs, attrib);
    1656        2753 :                 if (f->handle->name->st.st_mode != mode &&
    1657        2095 :                     f->handle->name->dos.attrib != attrib &&
    1658         715 :                     pvfs_sys_fchmod(pvfs, fd, mode, name->allow_override) == -1) {
    1659           0 :                         talloc_free(lck);
    1660           0 :                         return pvfs_map_errno(pvfs, errno);
    1661             :                 }
    1662        1380 :                 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
    1663        1380 :                 name->dos.attrib = attrib;
    1664        1380 :                 status = pvfs_dosattrib_save(pvfs, name, fd);
    1665        1380 :                 if (!NT_STATUS_IS_OK(status)) {
    1666           0 :                         talloc_free(lck);
    1667           0 :                         return status;
    1668             :                 }
    1669             :         }
    1670             :             
    1671       89000 :         talloc_free(lck);
    1672             : 
    1673       89000 :         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
    1674       89000 :         NT_STATUS_NOT_OK_RETURN(status);
    1675             : 
    1676             :         /* mark the open as having completed fully, so delete on close
    1677             :            can now be used */
    1678       89000 :         f->handle->open_completed     = true;
    1679             : 
    1680       89000 :         io->generic.out.oplock_level  = oplock_granted;
    1681       89000 :         io->generic.out.file.ntvfs    = h;
    1682       89000 :         io->generic.out.create_action = stream_existed?
    1683       89000 :                 create_action:NTCREATEX_ACTION_CREATED;
    1684             :         
    1685       89000 :         io->generic.out.create_time   = name->dos.create_time;
    1686       89000 :         io->generic.out.access_time   = name->dos.access_time;
    1687       89000 :         io->generic.out.write_time    = name->dos.write_time;
    1688       89000 :         io->generic.out.change_time   = name->dos.change_time;
    1689       89000 :         io->generic.out.attrib        = name->dos.attrib;
    1690       89000 :         io->generic.out.alloc_size    = name->dos.alloc_size;
    1691       89000 :         io->generic.out.size          = name->st.st_size;
    1692       89000 :         io->generic.out.file_type     = FILE_TYPE_DISK;
    1693       89000 :         io->generic.out.ipc_state     = 0;
    1694       89000 :         io->generic.out.is_directory  = 0;
    1695             : 
    1696       89000 :         return NT_STATUS_OK;
    1697             : }
    1698             : 
    1699             : 
    1700             : /*
    1701             :   close a file
    1702             : */
    1703      393473 : NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
    1704             :                     struct ntvfs_request *req, union smb_close *io)
    1705             : {
    1706      393473 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1707             :                                   struct pvfs_state);
    1708             :         struct pvfs_file *f;
    1709             : 
    1710      393473 :         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
    1711           1 :                 return NT_STATUS_DOS(ERRSRV, ERRerror);
    1712             :         }
    1713             : 
    1714      393472 :         if (io->generic.level != RAW_CLOSE_GENERIC) {
    1715      196736 :                 return ntvfs_map_close(ntvfs, req, io);
    1716             :         }
    1717             : 
    1718      196736 :         f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
    1719      196736 :         if (!f) {
    1720           0 :                 return NT_STATUS_INVALID_HANDLE;
    1721             :         }
    1722             : 
    1723      196736 :         if (!null_time(io->generic.in.write_time)) {
    1724           1 :                 f->handle->write_time.update_forced = false;
    1725           1 :                 f->handle->write_time.update_on_close = true;
    1726           1 :                 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
    1727             :         }
    1728             : 
    1729      196736 :         if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
    1730             :                 struct pvfs_filename *name;
    1731             :                 NTSTATUS status;
    1732           2 :                 struct pvfs_file_handle *h = f->handle;
    1733             : 
    1734           2 :                 status = pvfs_resolve_name_handle(pvfs, h);
    1735           2 :                 if (!NT_STATUS_IS_OK(status)) {
    1736           0 :                         return status;
    1737             :                 }
    1738           2 :                 name = h->name;
    1739             : 
    1740           2 :                 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
    1741           2 :                 io->generic.out.create_time = name->dos.create_time;
    1742           2 :                 io->generic.out.access_time = name->dos.access_time;
    1743           2 :                 io->generic.out.write_time  = name->dos.write_time;
    1744           2 :                 io->generic.out.change_time = name->dos.change_time;
    1745           2 :                 io->generic.out.alloc_size  = name->dos.alloc_size;
    1746           2 :                 io->generic.out.size        = name->st.st_size;
    1747           2 :                 io->generic.out.file_attr   = name->dos.attrib;           
    1748             :         } else {
    1749      196734 :                 ZERO_STRUCT(io->generic.out);
    1750             :         }
    1751             : 
    1752      196736 :         talloc_free(f);
    1753             : 
    1754      196736 :         return NT_STATUS_OK;
    1755             : }
    1756             : 
    1757             : 
    1758             : /*
    1759             :   logoff - close all file descriptors open by a vuid
    1760             : */
    1761          21 : NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
    1762             :                      struct ntvfs_request *req)
    1763             : {
    1764          21 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1765             :                                   struct pvfs_state);
    1766             :         struct pvfs_file *f, *next;
    1767             : 
    1768             :         /* If pvfs is NULL, we never logged on, and no files are open. */
    1769          21 :         if(pvfs == NULL) {
    1770           0 :                 return NT_STATUS_OK;
    1771             :         }
    1772             : 
    1773          21 :         for (f=pvfs->files.list;f;f=next) {
    1774           0 :                 next = f->next;
    1775           0 :                 if (f->ntvfs->session_info == req->session_info) {
    1776           0 :                         talloc_free(f);
    1777             :                 }
    1778             :         }
    1779             : 
    1780          21 :         return NT_STATUS_OK;
    1781             : }
    1782             : 
    1783             : 
    1784             : /*
    1785             :   exit - close files for the current pid
    1786             : */
    1787         521 : NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
    1788             :                    struct ntvfs_request *req)
    1789             : {
    1790         521 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1791             :                                   struct pvfs_state);
    1792             :         struct pvfs_file *f, *next;
    1793             : 
    1794         564 :         for (f=pvfs->files.list;f;f=next) {
    1795          43 :                 next = f->next;
    1796          85 :                 if (f->ntvfs->session_info == req->session_info &&
    1797          42 :                     f->ntvfs->smbpid == req->smbpid) {
    1798          40 :                         talloc_free(f);
    1799             :                 }
    1800             :         }
    1801             : 
    1802         521 :         return NT_STATUS_OK;
    1803             : }
    1804             : 
    1805             : 
    1806             : /*
    1807             :   change the delete on close flag on an already open file
    1808             : */
    1809         316 : NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
    1810             :                                   struct ntvfs_request *req, 
    1811             :                                   struct pvfs_file *f, bool del_on_close)
    1812             : {
    1813             :         struct odb_lock *lck;
    1814             :         NTSTATUS status;
    1815             : 
    1816         316 :         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
    1817           3 :                 return NT_STATUS_CANNOT_DELETE;
    1818             :         }
    1819             :         
    1820         572 :         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
    1821         259 :             !pvfs_directory_empty(pvfs, f->handle->name)) {
    1822           4 :                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
    1823             :         }
    1824             : 
    1825         309 :         if (del_on_close) {
    1826         288 :                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1827             :         } else {
    1828          21 :                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1829             :         }
    1830             :         
    1831         309 :         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
    1832         309 :         if (lck == NULL) {
    1833           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1834             :         }
    1835             : 
    1836         309 :         status = odb_set_delete_on_close(lck, del_on_close);
    1837             : 
    1838         309 :         talloc_free(lck);
    1839             : 
    1840         309 :         return status;
    1841             : }
    1842             : 
    1843             : 
    1844             : /*
    1845             :   determine if a file can be deleted, or if it is prevented by an
    1846             :   already open file
    1847             : */
    1848       31063 : NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
    1849             :                          struct ntvfs_request *req,
    1850             :                          struct pvfs_filename *name,
    1851             :                          struct odb_lock **lckp)
    1852             : {
    1853             :         NTSTATUS status;
    1854             :         DATA_BLOB key;
    1855             :         struct odb_lock *lck;
    1856             :         uint32_t share_access;
    1857             :         uint32_t access_mask;
    1858             :         bool delete_on_close;
    1859             : 
    1860       31063 :         status = pvfs_locking_key(name, name, &key);
    1861       31063 :         if (!NT_STATUS_IS_OK(status)) {
    1862           0 :                 return NT_STATUS_NO_MEMORY;
    1863             :         }
    1864             : 
    1865       31063 :         lck = odb_lock(req, pvfs->odb_context, &key);
    1866       31063 :         if (lck == NULL) {
    1867           0 :                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
    1868           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1869             :         }
    1870             : 
    1871       31063 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    1872             :                           NTCREATEX_SHARE_ACCESS_WRITE |
    1873             :                           NTCREATEX_SHARE_ACCESS_DELETE;
    1874       31063 :         access_mask     = SEC_STD_DELETE;
    1875       31063 :         delete_on_close = true;
    1876             : 
    1877       31063 :         status = odb_can_open(lck, name->stream_id,
    1878             :                               share_access, access_mask, delete_on_close,
    1879             :                               NTCREATEX_DISP_OPEN, false);
    1880             : 
    1881       31063 :         if (NT_STATUS_IS_OK(status)) {
    1882       31024 :                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
    1883             :         }
    1884             : 
    1885             :         /*
    1886             :          * if it's a sharing violation or we got no oplock
    1887             :          * only keep the lock if the caller requested access
    1888             :          * to the lock
    1889             :          */
    1890       62091 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    1891       31031 :             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    1892          76 :                 if (lckp) {
    1893          37 :                         *lckp = lck;
    1894             :                 } else {
    1895           1 :                         talloc_free(lck);
    1896             :                 }
    1897       31025 :         } else if (!NT_STATUS_IS_OK(status)) {
    1898           1 :                 talloc_free(lck);
    1899           1 :                 if (lckp) {
    1900           0 :                         *lckp = NULL;
    1901             :                 }
    1902       31024 :         } else if (lckp) {
    1903       31021 :                 *lckp = lck;
    1904             :         }
    1905             : 
    1906       31063 :         return status;
    1907             : }
    1908             : 
    1909             : /*
    1910             :   determine if a file can be renamed, or if it is prevented by an
    1911             :   already open file
    1912             : */
    1913         113 : NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
    1914             :                          struct ntvfs_request *req,
    1915             :                          struct pvfs_filename *name,
    1916             :                          struct odb_lock **lckp)
    1917             : {
    1918             :         NTSTATUS status;
    1919             :         DATA_BLOB key;
    1920             :         struct odb_lock *lck;
    1921             :         uint32_t share_access;
    1922             :         uint32_t access_mask;
    1923             :         bool delete_on_close;
    1924             : 
    1925         113 :         status = pvfs_locking_key(name, name, &key);
    1926         113 :         if (!NT_STATUS_IS_OK(status)) {
    1927           0 :                 return NT_STATUS_NO_MEMORY;
    1928             :         }
    1929             : 
    1930         113 :         lck = odb_lock(req, pvfs->odb_context, &key);
    1931         113 :         if (lck == NULL) {
    1932           0 :                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
    1933           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1934             :         }
    1935             : 
    1936         113 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    1937             :                           NTCREATEX_SHARE_ACCESS_WRITE;
    1938         113 :         access_mask     = SEC_STD_DELETE;
    1939         113 :         delete_on_close = false;
    1940             : 
    1941         113 :         status = odb_can_open(lck, name->stream_id,
    1942             :                               share_access, access_mask, delete_on_close,
    1943             :                               NTCREATEX_DISP_OPEN, false);
    1944             : 
    1945             :         /*
    1946             :          * if it's a sharing violation or we got no oplock
    1947             :          * only keep the lock if the caller requested access
    1948             :          * to the lock
    1949             :          */
    1950         214 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    1951         102 :             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    1952          30 :                 if (lckp) {
    1953          15 :                         *lckp = lck;
    1954             :                 } else {
    1955           0 :                         talloc_free(lck);
    1956             :                 }
    1957          98 :         } else if (!NT_STATUS_IS_OK(status)) {
    1958           0 :                 talloc_free(lck);
    1959           0 :                 if (lckp) {
    1960           0 :                         *lckp = NULL;
    1961             :                 }
    1962          98 :         } else if (lckp) {
    1963          98 :                 *lckp = lck;
    1964             :         }
    1965             : 
    1966         113 :         return status;
    1967             : }
    1968             : 
    1969             : /*
    1970             :   determine if the file size of a file can be changed,
    1971             :   or if it is prevented by an already open file
    1972             : */
    1973          13 : NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
    1974             :                                    struct ntvfs_request *req,
    1975             :                                    struct pvfs_filename *name,
    1976             :                                    struct odb_lock **lckp)
    1977             : {
    1978             :         NTSTATUS status;
    1979             :         DATA_BLOB key;
    1980             :         struct odb_lock *lck;
    1981             :         uint32_t share_access;
    1982             :         uint32_t access_mask;
    1983             :         bool break_to_none;
    1984             :         bool delete_on_close;
    1985             : 
    1986          13 :         status = pvfs_locking_key(name, name, &key);
    1987          13 :         if (!NT_STATUS_IS_OK(status)) {
    1988           0 :                 return NT_STATUS_NO_MEMORY;
    1989             :         }
    1990             : 
    1991          13 :         lck = odb_lock(req, pvfs->odb_context, &key);
    1992          13 :         if (lck == NULL) {
    1993           0 :                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
    1994           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1995             :         }
    1996             : 
    1997          13 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    1998             :                           NTCREATEX_SHARE_ACCESS_WRITE |
    1999             :                           NTCREATEX_SHARE_ACCESS_DELETE;
    2000             :         /*
    2001             :          * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
    2002             :          * a comment that this seemed to be wrong, but matched windows
    2003             :          * behaviour. It now appears that this windows behaviour is
    2004             :          * just a bug.
    2005             :          */
    2006          13 :         access_mask     = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
    2007          13 :         delete_on_close = false;
    2008          13 :         break_to_none   = true;
    2009             : 
    2010          13 :         status = odb_can_open(lck, name->stream_id,
    2011             :                               share_access, access_mask, delete_on_close,
    2012             :                               NTCREATEX_DISP_OPEN, break_to_none);
    2013             : 
    2014             :         /*
    2015             :          * if it's a sharing violation or we got no oplock
    2016             :          * only keep the lock if the caller requested access
    2017             :          * to the lock
    2018             :          */
    2019          24 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    2020          11 :             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    2021          10 :                 if (lckp) {
    2022           5 :                         *lckp = lck;
    2023             :                 } else {
    2024           0 :                         talloc_free(lck);
    2025             :                 }
    2026           8 :         } else if (!NT_STATUS_IS_OK(status)) {
    2027           0 :                 talloc_free(lck);
    2028           0 :                 if (lckp) {
    2029           0 :                         *lckp = NULL;
    2030             :                 }
    2031           8 :         } else if (lckp) {
    2032           8 :                 *lckp = lck;
    2033             :         }
    2034             : 
    2035          13 :         return status;
    2036             : }
    2037             : 
    2038             : /*
    2039             :   determine if file meta data can be accessed, or if it is prevented by an
    2040             :   already open file
    2041             : */
    2042        5074 : NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
    2043             :                        struct ntvfs_request *req,
    2044             :                        struct pvfs_filename *name)
    2045             : {
    2046             :         NTSTATUS status;
    2047             :         DATA_BLOB key;
    2048             :         struct odb_lock *lck;
    2049             :         uint32_t share_access;
    2050             :         uint32_t access_mask;
    2051             :         bool delete_on_close;
    2052             : 
    2053        5074 :         status = pvfs_locking_key(name, name, &key);
    2054        5074 :         if (!NT_STATUS_IS_OK(status)) {
    2055           0 :                 return NT_STATUS_NO_MEMORY;
    2056             :         }
    2057             : 
    2058        5074 :         lck = odb_lock(req, pvfs->odb_context, &key);
    2059        5074 :         if (lck == NULL) {
    2060           0 :                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
    2061           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2062             :         }
    2063             : 
    2064        5074 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    2065             :                           NTCREATEX_SHARE_ACCESS_WRITE;
    2066        5074 :         access_mask     = SEC_FILE_READ_ATTRIBUTE;
    2067        5074 :         delete_on_close = false;
    2068             : 
    2069        5074 :         status = odb_can_open(lck, name->stream_id,
    2070             :                               share_access, access_mask, delete_on_close,
    2071             :                               NTCREATEX_DISP_OPEN, false);
    2072             : 
    2073        5074 :         if (!NT_STATUS_IS_OK(status)) {
    2074          32 :                 talloc_free(lck);
    2075             :         }
    2076             : 
    2077        5074 :         return status;
    2078             : }
    2079             : 
    2080             : 
    2081             : /*
    2082             :   determine if delete on close is set on 
    2083             : */
    2084        1024 : bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
    2085             : {
    2086             :         NTSTATUS status;
    2087             :         bool del_on_close;
    2088             : 
    2089        1024 :         status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
    2090             :                                     &del_on_close, NULL);
    2091        1024 :         if (!NT_STATUS_IS_OK(status)) {
    2092           0 :                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
    2093           0 :                 return false;
    2094             :         }
    2095             : 
    2096        1024 :         return del_on_close;
    2097             : }

Generated by: LCOV version 1.13