LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_open.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 803 1055 76.1 %
Date: 2024-05-31 13:13:24 Functions: 26 26 100.0 %

          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      304893 : struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
      34             :                                struct ntvfs_request *req, struct ntvfs_handle *h)
      35             : {
      36           0 :         void *p;
      37           0 :         struct pvfs_file *f;
      38             : 
      39      304893 :         p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
      40      304893 :         if (!p) return NULL;
      41             : 
      42      304893 :         f = talloc_get_type(p, struct pvfs_file);
      43      304893 :         if (!f) return NULL;
      44             : 
      45      304893 :         return f;
      46             : }
      47             : 
      48             : /*
      49             :   cleanup a open directory handle
      50             : */
      51       16337 : static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
      52             : {
      53       16337 :         if (h->have_opendb_entry) {
      54           0 :                 struct odb_lock *lck;
      55           0 :                 NTSTATUS status;
      56       16337 :                 const char *delete_path = NULL;
      57             : 
      58       16337 :                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
      59       16337 :                 if (lck == NULL) {
      60           0 :                         DEBUG(0,("Unable to lock opendb for close\n"));
      61           0 :                         return 0;
      62             :                 }
      63             : 
      64       16337 :                 status = odb_close_file(lck, h, &delete_path);
      65       16337 :                 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       16337 :                 if (h->name->stream_name == NULL && delete_path) {
      71         413 :                         status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
      72         413 :                         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         413 :                         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       16337 :                 talloc_free(lck);
      83             :         }
      84             : 
      85       16337 :         return 0;
      86             : }
      87             : 
      88             : /*
      89             :   cleanup a open directory fnum
      90             : */
      91       16337 : static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
      92             : {
      93       16337 :         DLIST_REMOVE(f->pvfs->files.list, f);
      94       16337 :         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
      95             : 
      96       16337 :         return 0;
      97             : }
      98             : 
      99             : /*
     100             :   setup any EAs and the ACL on newly created files/directories
     101             : */
     102      101687 : 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      101687 :         NTSTATUS status = NT_STATUS_OK;
     110             : 
     111             :         /* setup any EAs that were asked for */
     112      101687 :         if (io->ntcreatex.in.ea_list) {
     113       66310 :                 status = pvfs_setfileinfo_ea_set(pvfs, name, fd, 
     114       66310 :                                                  io->ntcreatex.in.ea_list->num_eas,
     115       66310 :                                                  io->ntcreatex.in.ea_list->eas);
     116       66310 :                 if (!NT_STATUS_IS_OK(status)) {
     117           0 :                         return status;
     118             :                 }
     119             :         }
     120             : 
     121             :         /* setup an initial sec_desc if requested */
     122      101687 :         if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
     123           0 :                 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         393 :                 set.set_secdesc.in.file.ntvfs = f->ntvfs;
     132         393 :                 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
     133         393 :                 set.set_secdesc.in.sd = sd;
     134             : 
     135         393 :                 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
     136             :         }
     137             : 
     138      101687 :         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      889020 : NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
     146             :                           TALLOC_CTX *mem_ctx, DATA_BLOB *key)
     147             : {
     148           0 :         struct {
     149             :                 dev_t device;
     150             :                 ino_t inode;
     151             :         } lock_context;
     152      889020 :         ZERO_STRUCT(lock_context);
     153             : 
     154      889020 :         lock_context.device = name->st.st_dev;
     155      889020 :         lock_context.inode = name->st.st_ino;
     156             : 
     157      889020 :         *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
     158      889020 :         if (key->data == NULL) {
     159           0 :                 return NT_STATUS_NO_MEMORY;
     160             :         }
     161             :         
     162      889020 :         return NT_STATUS_OK;
     163             : }
     164             : 
     165             : 
     166             : /*
     167             :   open a directory
     168             : */
     169       16494 : 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           0 :         struct pvfs_file *f;
     175           0 :         struct ntvfs_handle *h;
     176           0 :         NTSTATUS status;
     177           0 :         uint32_t create_action;
     178       16494 :         uint32_t access_mask = io->generic.in.access_mask;
     179           0 :         struct odb_lock *lck;
     180           0 :         bool del_on_close;
     181           0 :         uint32_t create_options;
     182           0 :         uint32_t share_access;
     183           0 :         bool forced;
     184       16494 :         struct security_descriptor *sd = NULL;
     185             : 
     186       16494 :         create_options = io->generic.in.create_options;
     187       16494 :         share_access   = io->generic.in.share_access;
     188             : 
     189       16494 :         forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
     190             : 
     191       16494 :         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       16487 :         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
     202           0 :                 return NT_STATUS_NOT_A_DIRECTORY;
     203             :         }
     204             : 
     205             :         /* found with gentest */
     206       16487 :         if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
     207          54 :             (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
     208          51 :             (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       16487 :         switch (io->generic.in.open_disposition) {
     215        8611 :         case NTCREATEX_DISP_OPEN_IF:
     216        8611 :                 break;
     217             : 
     218        7512 :         case NTCREATEX_DISP_OPEN:
     219        7512 :                 if (!name->exists) {
     220         106 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     221             :                 }
     222        7406 :                 break;
     223             : 
     224         353 :         case NTCREATEX_DISP_CREATE:
     225         353 :                 if (name->exists) {
     226          15 :                         return NT_STATUS_OBJECT_NAME_COLLISION;
     227             :                 }
     228         338 :                 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       16355 :         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
     240       16355 :         NT_STATUS_NOT_OK_RETURN(status);
     241             : 
     242       16355 :         f = talloc(h, struct pvfs_file);
     243       16355 :         if (f == NULL) {
     244           0 :                 return NT_STATUS_NO_MEMORY;
     245             :         }
     246             : 
     247       16355 :         f->handle = talloc(f, struct pvfs_file_handle);
     248       16355 :         if (f->handle == NULL) {
     249           0 :                 return NT_STATUS_NO_MEMORY;
     250             :         }
     251             : 
     252       16355 :         if (name->exists) {
     253             :                 /* check the security descriptor */
     254       11686 :                 status = pvfs_access_check(pvfs, req, name, &access_mask);
     255             :         } else {                
     256        4669 :                 sd = io->ntcreatex.in.sec_desc;
     257        4669 :                 status = pvfs_access_check_create(pvfs, req, name, &access_mask, true, &sd);
     258             :         }
     259       16355 :         NT_STATUS_NOT_OK_RETURN(status);
     260             : 
     261       16355 :         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       16355 :         f->ntvfs         = h;
     268       16355 :         f->pvfs          = pvfs;
     269       16355 :         f->pending_list  = NULL;
     270       16355 :         f->lock_count    = 0;
     271       16355 :         f->share_access  = io->generic.in.share_access;
     272       16355 :         f->impersonation = io->generic.in.impersonation;
     273       16355 :         f->access_mask   = access_mask;
     274       16355 :         f->brl_handle         = NULL;
     275       16355 :         f->notify_buffer = NULL;
     276       16355 :         f->search        = NULL;
     277             : 
     278       16355 :         f->handle->pvfs              = pvfs;
     279       16355 :         f->handle->name              = talloc_steal(f->handle, name);
     280       16355 :         f->handle->fd                = -1;
     281       16355 :         f->handle->odb_locking_key   = data_blob(NULL, 0);
     282       16355 :         f->handle->create_options    = io->generic.in.create_options;
     283       16355 :         f->handle->private_flags     = io->generic.in.private_flags;
     284       16355 :         f->handle->seek_offset       = 0;
     285       16355 :         f->handle->position          = 0;
     286       16355 :         f->handle->mode              = 0;
     287       16355 :         f->handle->oplock            = NULL;
     288       16355 :         ZERO_STRUCT(f->handle->write_time);
     289       16355 :         f->handle->open_completed    = false;
     290             : 
     291       16515 :         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
     292         160 :             pvfs_directory_empty(pvfs, f->handle->name)) {
     293         155 :                 del_on_close = true;
     294             :         } else {
     295       16200 :                 del_on_close = false;
     296             :         }
     297             : 
     298       16355 :         if (name->exists) {
     299             :                 /* form the lock context used for opendb locking */
     300       11686 :                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
     301       11686 :                 if (!NT_STATUS_IS_OK(status)) {
     302           0 :                         return status;
     303             :                 }
     304             : 
     305             :                 /* get a lock on this file before the actual open */
     306       11686 :                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
     307       11686 :                 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       11686 :                 status = odb_can_open(lck, name->stream_id,
     317             :                                       share_access, access_mask, del_on_close,
     318             :                                       io->generic.in.open_disposition, false);
     319       11686 :                 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       11668 :                 status = odb_open_file(lck, f->handle, name->full_name,
     326       11668 :                                        NULL, name->dos.write_time,
     327             :                                        false, OPLOCK_NONE, NULL);
     328             : 
     329       11668 :                 if (!NT_STATUS_IS_OK(status)) {
     330           0 :                         talloc_free(lck);
     331           0 :                         return status;
     332             :                 }
     333             : 
     334       11668 :                 f->handle->have_opendb_entry = true;
     335             :         }
     336             : 
     337       16337 :         DLIST_ADD(pvfs->files.list, f);
     338             : 
     339             :         /* setup destructors to avoid leaks on abnormal termination */
     340       16337 :         talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
     341       16337 :         talloc_set_destructor(f, pvfs_dir_fnum_destructor);
     342             : 
     343       16337 :         if (!name->exists) {
     344        4669 :                 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
     345        4669 :                 mode_t mode = pvfs_fileperms(pvfs, attrib);
     346             : 
     347        4669 :                 if (pvfs_sys_mkdir(pvfs, name->full_name, mode, name->allow_override) == -1) {
     348           0 :                         return pvfs_map_errno(pvfs,errno);
     349             :                 }
     350             : 
     351        4669 :                 pvfs_xattr_unlink_hook(pvfs, name->full_name);
     352             : 
     353        4669 :                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
     354        4669 :                 if (!NT_STATUS_IS_OK(status)) {
     355           0 :                         goto cleanup_delete;
     356             :                 }
     357             : 
     358        4669 :                 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io, sd);
     359        4669 :                 if (!NT_STATUS_IS_OK(status)) {
     360           0 :                         goto cleanup_delete;
     361             :                 }
     362             : 
     363             :                 /* form the lock context used for opendb locking */
     364        4669 :                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
     365        4669 :                 if (!NT_STATUS_IS_OK(status)) {
     366           0 :                         return status;
     367             :                 }
     368             : 
     369        4669 :                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
     370        4669 :                 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        4669 :                 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        4669 :                 if (!NT_STATUS_IS_OK(status)) {
     383           0 :                         goto cleanup_delete;
     384             :                 }
     385             : 
     386        4669 :                 status = odb_open_file(lck, f->handle, name->full_name,
     387        4669 :                                        NULL, name->dos.write_time,
     388             :                                        false, OPLOCK_NONE, NULL);
     389             : 
     390        4669 :                 if (!NT_STATUS_IS_OK(status)) {
     391           0 :                         goto cleanup_delete;
     392             :                 }
     393             : 
     394        4669 :                 f->handle->have_opendb_entry = true;
     395             : 
     396        4669 :                 create_action = NTCREATEX_ACTION_CREATED;
     397             : 
     398        4669 :                 notify_trigger(pvfs->notify_context, 
     399             :                                NOTIFY_ACTION_ADDED, 
     400             :                                FILE_NOTIFY_CHANGE_DIR_NAME,
     401        4669 :                                name->full_name);
     402             :         } else {
     403       11668 :                 create_action = NTCREATEX_ACTION_EXISTED;
     404             :         }
     405             : 
     406       16337 :         if (!name->exists) {
     407           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     408             :         }
     409             : 
     410       16337 :         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       16337 :         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
     418       16337 :         if (!NT_STATUS_IS_OK(status)) {
     419           0 :                 goto cleanup_delete;
     420             :         }
     421             : 
     422       16337 :         f->handle->open_completed = true;
     423             : 
     424       16337 :         io->generic.out.oplock_level  = OPLOCK_NONE;
     425       16337 :         io->generic.out.file.ntvfs    = h;
     426       16337 :         io->generic.out.create_action = create_action;
     427       16337 :         io->generic.out.create_time   = name->dos.create_time;
     428       16337 :         io->generic.out.access_time   = name->dos.access_time;
     429       16337 :         io->generic.out.write_time    = name->dos.write_time;
     430       16337 :         io->generic.out.change_time   = name->dos.change_time;
     431       16337 :         io->generic.out.attrib        = name->dos.attrib;
     432       16337 :         io->generic.out.alloc_size    = name->dos.alloc_size;
     433       16337 :         io->generic.out.size          = name->st.st_size;
     434       16337 :         io->generic.out.file_type     = FILE_TYPE_DISK;
     435       16337 :         io->generic.out.ipc_state     = 0;
     436       16337 :         io->generic.out.is_directory  = 1;
     437             : 
     438       16337 :         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      189137 : static int pvfs_handle_destructor(struct pvfs_file_handle *h)
     449             : {
     450      189137 :         talloc_free(h->write_time.update_event);
     451      189137 :         h->write_time.update_event = NULL;
     452             : 
     453      189137 :         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
     454       65993 :             h->name->stream_name) {
     455           0 :                 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      189137 :         if (h->fd != -1) {
     464      186176 :                 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      186176 :                 h->fd = -1;
     469             :         }
     470             : 
     471      189137 :         if (!h->write_time.update_forced &&
     472      188846 :             h->write_time.update_on_close &&
     473        9258 :             h->write_time.close_time == 0) {
     474           0 :                 struct timeval tv;
     475        9257 :                 tv = timeval_current();
     476        9257 :                 h->write_time.close_time = timeval_to_nttime(&tv);
     477             :         }
     478             : 
     479      189137 :         if (h->have_opendb_entry) {
     480           0 :                 struct odb_lock *lck;
     481           0 :                 NTSTATUS status;
     482      186176 :                 const char *delete_path = NULL;
     483             : 
     484      186176 :                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
     485      186176 :                 if (lck == NULL) {
     486           0 :                         DEBUG(0,("Unable to lock opendb for close\n"));
     487           0 :                         return 0;
     488             :                 }
     489             : 
     490      186176 :                 if (h->write_time.update_forced) {
     491         291 :                         status = odb_get_file_infos(h->pvfs->odb_context,
     492             :                                                     &h->odb_locking_key,
     493             :                                                     NULL,
     494             :                                                     &h->write_time.close_time);
     495         291 :                         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         291 :                         h->write_time.update_forced = false;
     501         291 :                         h->write_time.update_on_close = true;
     502      185885 :                 } else if (h->write_time.update_on_close) {
     503        9258 :                         status = odb_set_write_time(lck, h->write_time.close_time, true);
     504        9258 :                         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      186176 :                 status = odb_close_file(lck, h, &delete_path);
     511      186176 :                 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      186176 :                 if (h->name->stream_name == NULL &&
     517      186070 :                     h->open_completed && delete_path) {
     518       65953 :                         status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
     519       65953 :                         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       65953 :                         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       65953 :                                 notify_trigger(h->pvfs->notify_context,
     528             :                                                NOTIFY_ACTION_REMOVED,
     529             :                                                FILE_NOTIFY_CHANGE_FILE_NAME,
     530             :                                                delete_path);
     531             :                         }
     532       65953 :                         h->write_time.update_on_close = false;
     533             :                 }
     534             : 
     535      186176 :                 talloc_free(lck);
     536             :         }
     537             : 
     538      189137 :         if (h->write_time.update_on_close) {
     539           0 :                 struct timeval tv[2];
     540             : 
     541        9542 :                 nttime_to_timeval(&tv[0], h->name->dos.access_time);
     542        9542 :                 nttime_to_timeval(&tv[1], h->write_time.close_time);
     543             : 
     544        9542 :                 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
     545        9542 :                         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      189137 :         return 0;
     553             : }
     554             : 
     555             : 
     556             : /*
     557             :   destroy a struct pvfs_file
     558             : */
     559      189137 : static int pvfs_fnum_destructor(struct pvfs_file *f)
     560             : {
     561      189137 :         DLIST_REMOVE(f->pvfs->files.list, f);
     562      189137 :         pvfs_lock_close(f->pvfs, f);
     563      189137 :         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
     564             : 
     565      189137 :         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      189137 : 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           0 :         DATA_BLOB odb_key, key;
     581           0 :         NTSTATUS status;
     582           0 :         struct brl_handle *h;
     583             : 
     584      189137 :         status = pvfs_locking_key(name, mem_ctx, &odb_key);
     585      189137 :         NT_STATUS_NOT_OK_RETURN(status);
     586             : 
     587      189137 :         if (name->stream_name == NULL) {
     588      189014 :                 key = odb_key;
     589             :         } else {
     590         123 :                 key = data_blob_talloc(mem_ctx, NULL, 
     591             :                                        odb_key.length + strlen(name->stream_name) + 1);
     592         123 :                 NT_STATUS_HAVE_NO_MEMORY(key.data);
     593         123 :                 memcpy(key.data, odb_key.data, odb_key.length);
     594         123 :                 memcpy(key.data + odb_key.length, 
     595         123 :                        name->stream_name, strlen(name->stream_name) + 1);
     596         123 :                 data_blob_free(&odb_key);
     597             :         }
     598             : 
     599      189137 :         h = brlock_create_handle(mem_ctx, ntvfs, &key);
     600      189137 :         NT_STATUS_HAVE_NO_MEMORY(h);
     601             : 
     602      189137 :         *_h = h;
     603      189137 :         return NT_STATUS_OK;
     604             : }
     605             : 
     606             : /*
     607             :   create a new file
     608             : */
     609       97024 : 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           0 :         struct pvfs_file *f;
     615           0 :         NTSTATUS status;
     616           0 :         struct ntvfs_handle *h;
     617           0 :         int flags, fd;
     618           0 :         struct odb_lock *lck;
     619       97024 :         uint32_t create_options = io->generic.in.create_options;
     620       97024 :         uint32_t share_access = io->generic.in.share_access;
     621       97024 :         uint32_t access_mask = io->generic.in.access_mask;
     622           0 :         mode_t mode;
     623           0 :         uint32_t attrib;
     624           0 :         bool del_on_close;
     625           0 :         struct pvfs_filename *parent;
     626       97024 :         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
     627       97024 :         bool allow_level_II_oplock = false;
     628       97024 :         struct security_descriptor *sd = NULL;
     629             : 
     630       97024 :         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       97024 :         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       97023 :         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
     643          32 :             (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       97020 :         sd = io->ntcreatex.in.sec_desc;
     650       97020 :         status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd);
     651       97020 :         NT_STATUS_NOT_OK_RETURN(status);
     652             : 
     653             :         /* check that the parent isn't opened with delete on close set */
     654       97020 :         status = pvfs_resolve_parent(pvfs, req, name, &parent);
     655       97020 :         if (NT_STATUS_IS_OK(status)) {
     656           0 :                 DATA_BLOB locking_key;
     657       97020 :                 status = pvfs_locking_key(parent, req, &locking_key);
     658       97022 :                 NT_STATUS_NOT_OK_RETURN(status);
     659       97020 :                 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
     660             :                                             &del_on_close, NULL);
     661       97020 :                 NT_STATUS_NOT_OK_RETURN(status);
     662       97020 :                 if (del_on_close) {
     663           2 :                         return NT_STATUS_DELETE_PENDING;
     664             :                 }
     665             :         }
     666             : 
     667       97018 :         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
     668       92665 :                 flags = O_RDWR;
     669             :         } else {
     670        4353 :                 flags = O_RDONLY;
     671             :         }
     672             : 
     673       97018 :         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
     674       97018 :         NT_STATUS_NOT_OK_RETURN(status);
     675             : 
     676       97018 :         f = talloc(h, struct pvfs_file);
     677       97018 :         NT_STATUS_HAVE_NO_MEMORY(f);
     678             : 
     679       97018 :         f->handle = talloc(f, struct pvfs_file_handle);
     680       97018 :         NT_STATUS_HAVE_NO_MEMORY(f->handle);
     681             : 
     682       97018 :         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
     683       97018 :         mode = pvfs_fileperms(pvfs, attrib);
     684             : 
     685             :         /* create the file */
     686       97018 :         fd = pvfs_sys_open(pvfs, name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode, name->allow_override);
     687       97018 :         if (fd == -1) {
     688           0 :                 return pvfs_map_errno(pvfs, errno);
     689             :         }
     690             : 
     691       97018 :         pvfs_xattr_unlink_hook(pvfs, name->full_name);
     692             : 
     693             :         /* if this was a stream create then create the stream as well */
     694       97018 :         if (name->stream_name) {
     695          22 :                 status = pvfs_stream_create(pvfs, name, fd);
     696          22 :                 if (!NT_STATUS_IS_OK(status)) {
     697           0 :                         close(fd);
     698           0 :                         return status;
     699             :                 }
     700             :         }
     701             : 
     702             :         /* re-resolve the open fd */
     703       97018 :         status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
     704       97018 :         if (!NT_STATUS_IS_OK(status)) {
     705           0 :                 close(fd);
     706           0 :                 return status;
     707             :         }
     708             : 
     709             :         /* support initial alloc sizes */
     710       97018 :         name->dos.alloc_size = io->ntcreatex.in.alloc_size;
     711       97018 :         name->dos.attrib = attrib;
     712       97018 :         status = pvfs_dosattrib_save(pvfs, name, fd);
     713       97018 :         if (!NT_STATUS_IS_OK(status)) {
     714           0 :                 goto cleanup_delete;
     715             :         }
     716             : 
     717             : 
     718       97018 :         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd);
     719       97018 :         if (!NT_STATUS_IS_OK(status)) {
     720           0 :                 goto cleanup_delete;
     721             :         }
     722             : 
     723       97018 :         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       97018 :         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       97018 :         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
     740       97018 :         if (!NT_STATUS_IS_OK(status)) {
     741           0 :                 goto cleanup_delete;
     742             :         }
     743             : 
     744       97018 :         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
     745       97018 :         if (!NT_STATUS_IS_OK(status)) {
     746           0 :                 goto cleanup_delete;
     747             :         }
     748             : 
     749             :         /* grab a lock on the open file record */
     750       97018 :         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
     751       97018 :         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       97018 :         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
     761          20 :                 del_on_close = true;
     762             :         } else {
     763       96998 :                 del_on_close = false;
     764             :         }
     765             : 
     766       97018 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
     767           0 :                 oplock_level = OPLOCK_NONE;
     768       97018 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
     769          65 :                 oplock_level = OPLOCK_BATCH;
     770       96953 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
     771          22 :                 oplock_level = OPLOCK_EXCLUSIVE;
     772             :         }
     773             : 
     774       97018 :         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
     775       96745 :                 allow_level_II_oplock = true;
     776             :         }
     777             : 
     778       97018 :         status = odb_can_open(lck, name->stream_id,
     779             :                               share_access, access_mask, del_on_close,
     780             :                               io->generic.in.open_disposition, false);
     781       97018 :         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       97018 :         f->ntvfs             = h;
     791       97018 :         f->pvfs              = pvfs;
     792       97018 :         f->pending_list      = NULL;
     793       97018 :         f->lock_count        = 0;
     794       97018 :         f->share_access      = io->generic.in.share_access;
     795       97018 :         f->access_mask       = access_mask;
     796       97018 :         f->impersonation     = io->generic.in.impersonation;
     797       97018 :         f->notify_buffer     = NULL;
     798       97018 :         f->search            = NULL;
     799             : 
     800       97018 :         f->handle->pvfs              = pvfs;
     801       97018 :         f->handle->name              = talloc_steal(f->handle, name);
     802       97018 :         f->handle->fd                = fd;
     803       97018 :         f->handle->create_options    = io->generic.in.create_options;
     804       97018 :         f->handle->private_flags     = io->generic.in.private_flags;
     805       97018 :         f->handle->seek_offset       = 0;
     806       97018 :         f->handle->position          = 0;
     807       97018 :         f->handle->mode              = 0;
     808       97018 :         f->handle->oplock            = NULL;
     809       97018 :         f->handle->have_opendb_entry = true;
     810       97018 :         ZERO_STRUCT(f->handle->write_time);
     811       97018 :         f->handle->open_completed    = false;
     812             : 
     813       97018 :         status = odb_open_file(lck, f->handle, name->full_name,
     814       97018 :                                &f->handle->fd, name->dos.write_time,
     815             :                                allow_level_II_oplock,
     816             :                                oplock_level, &oplock_granted);
     817       97018 :         talloc_free(lck);
     818       97018 :         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       97018 :         DLIST_ADD(pvfs->files.list, f);
     827             : 
     828             :         /* setup a destructor to avoid file descriptor leaks on
     829             :            abnormal termination */
     830       97018 :         talloc_set_destructor(f, pvfs_fnum_destructor);
     831       97018 :         talloc_set_destructor(f->handle, pvfs_handle_destructor);
     832             : 
     833       97018 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
     834           0 :                 oplock_granted = OPLOCK_BATCH;
     835       97018 :         } 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       97018 :         io->generic.out.oplock_level  = oplock_granted;
     843       97018 :         io->generic.out.file.ntvfs    = f->ntvfs;
     844       97018 :         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
     845       97018 :         io->generic.out.create_time   = name->dos.create_time;
     846       97018 :         io->generic.out.access_time   = name->dos.access_time;
     847       97018 :         io->generic.out.write_time    = name->dos.write_time;
     848       97018 :         io->generic.out.change_time   = name->dos.change_time;
     849       97018 :         io->generic.out.attrib        = name->dos.attrib;
     850       97018 :         io->generic.out.alloc_size    = name->dos.alloc_size;
     851       97018 :         io->generic.out.size          = name->st.st_size;
     852       97018 :         io->generic.out.file_type     = FILE_TYPE_DISK;
     853       97018 :         io->generic.out.ipc_state     = 0;
     854       97018 :         io->generic.out.is_directory  = 0;
     855             : 
     856             :         /* success - keep the file handle */
     857       97018 :         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
     858       97018 :         if (!NT_STATUS_IS_OK(status)) {
     859           0 :                 goto cleanup_delete;
     860             :         }
     861             : 
     862       97018 :         f->handle->open_completed = true;
     863             : 
     864       97018 :         notify_trigger(pvfs->notify_context, 
     865             :                        NOTIFY_ACTION_ADDED, 
     866             :                        FILE_NOTIFY_CHANGE_FILE_NAME,
     867       97018 :                        name->full_name);
     868             : 
     869       97018 :         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        2909 : static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
     896             : {
     897        2909 :         struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
     898             :                                   struct pvfs_state);
     899        2909 :         if (r->odb_locking_key.data) {
     900           0 :                 struct odb_lock *lck;
     901        2825 :                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
     902        2825 :                 if (lck != NULL) {
     903        2825 :                         odb_remove_pending(lck, r);
     904             :                 }
     905        2825 :                 talloc_free(lck);
     906             :         }
     907        2909 :         return 0;
     908             : }
     909             : 
     910        2869 : static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
     911             : {
     912        2869 :         struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
     913             : 
     914        2869 :         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          84 :                 data_blob_free(&r->odb_locking_key);
     921             :         }
     922             : 
     923        2869 :         r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
     924        2869 : }
     925             : 
     926             : /*
     927             :   setup for a retry of a request that was rejected
     928             :   by odb_can_open()
     929             : */
     930        2909 : 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        2909 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     944             :                                   struct pvfs_state);
     945           0 :         struct pvfs_odb_retry *r;
     946           0 :         struct pvfs_wait *wait_handle;
     947           0 :         NTSTATUS status;
     948             : 
     949        2909 :         r = talloc(req, struct pvfs_odb_retry);
     950        2909 :         NT_STATUS_HAVE_NO_MEMORY(r);
     951             : 
     952        2909 :         r->ntvfs = ntvfs;
     953        2909 :         r->req = req;
     954        2909 :         r->io = io;
     955        2909 :         r->private_data = private_data;
     956        2909 :         r->callback = callback;
     957        2909 :         r->odb_locking_key = odb_get_key(r, lck);
     958        2909 :         if (r->odb_locking_key.data == NULL) {
     959           0 :                 return NT_STATUS_NO_MEMORY;
     960             :         }
     961             : 
     962             :         /* setup a pending lock */
     963        2909 :         status = odb_open_file_pending(lck, r);
     964        2909 :         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        2909 :         } else if (!NT_STATUS_IS_OK(status)) {
     971           0 :                 return status;
     972             :         }
     973             : 
     974        2909 :         talloc_free(lck);
     975             : 
     976        2909 :         talloc_set_destructor(r, pvfs_odb_retry_destructor);
     977             : 
     978        2909 :         wait_handle = pvfs_wait_message(pvfs, req,
     979             :                                         MSG_PVFS_RETRY_OPEN, end_time,
     980             :                                         pvfs_odb_retry_callback, r);
     981        2909 :         if (wait_handle == NULL) {
     982           0 :                 return NT_STATUS_NO_MEMORY;
     983             :         }
     984             : 
     985        2909 :         talloc_steal(r, wait_handle);
     986             : 
     987        2909 :         return NT_STATUS_OK;
     988             : }
     989             : 
     990             : /*
     991             :   retry an open after a sharing violation
     992             : */
     993        2812 : 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        2812 :         union smb_open *io = talloc_get_type(_io, union smb_open);
    1001        2812 :         struct timeval *final_timeout = NULL;
    1002           0 :         NTSTATUS status;
    1003             : 
    1004        2812 :         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        2812 :         if (reason == PVFS_WAIT_CANCEL) {
    1012        2748 :                 return;
    1013             :         }
    1014             : 
    1015        2811 :         if (reason == PVFS_WAIT_TIMEOUT) {
    1016        2740 :                 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        2740 :                 talloc_free(r);
    1029        2740 :                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
    1030        2740 :                 req->async_states->send_fn(req);
    1031        2740 :                 return;
    1032             :         }
    1033             : 
    1034          71 : retry:
    1035          71 :         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          71 :         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
    1041             : 
    1042          71 :         status = pvfs_open(ntvfs, req, io);
    1043          71 :         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           7 :                 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           0 :         struct pvfs_file *f2;
    1073           0 :         struct pvfs_filename *name;
    1074           0 :         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        1156 :                 if (f2 != f &&
    1088         388 :                     f2->ntvfs->session_info == req->session_info &&
    1089         388 :                     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         115 :         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        2955 : 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        2955 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1153             :                                   struct pvfs_state);
    1154           0 :         NTSTATUS status;
    1155           0 :         struct timeval end_time;
    1156        2955 :         struct timeval *final_timeout = NULL;
    1157             : 
    1158        2955 :         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        2852 :         talloc_free(f);
    1170             : 
    1171        2852 :         if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
    1172        2782 :                 end_time = timeval_add(&req->statistics.request_time,
    1173             :                                        0, pvfs->sharing_violation_delay);
    1174          70 :         } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    1175          70 :                 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        2852 :         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      489370 : NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
    1205             :                    struct ntvfs_request *req, union smb_open *io)
    1206             : {
    1207      489370 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1208             :                                   struct pvfs_state);
    1209      489370 :         int flags = 0;
    1210           0 :         struct pvfs_filename *name;
    1211           0 :         struct pvfs_file *f;
    1212           0 :         struct ntvfs_handle *h;
    1213           0 :         NTSTATUS status;
    1214           0 :         int fd, count;
    1215           0 :         struct odb_lock *lck;
    1216           0 :         uint32_t create_options;
    1217           0 :         uint32_t create_options_must_ignore_mask;
    1218           0 :         uint32_t share_access;
    1219           0 :         uint32_t access_mask;
    1220      489370 :         uint32_t create_action = NTCREATEX_ACTION_EXISTED;
    1221           0 :         bool del_on_close;
    1222      489370 :         bool stream_existed, stream_truncate=false;
    1223      489370 :         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
    1224      489370 :         bool allow_level_II_oplock = false;
    1225             : 
    1226             :         /* use the generic mapping code to avoid implementing all the
    1227             :            different open calls. */
    1228      489370 :         if (io->generic.level != RAW_OPEN_GENERIC &&
    1229      216583 :             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
    1230      216486 :                 return ntvfs_map_open(ntvfs, req, io);
    1231             :         }
    1232             : 
    1233      272884 :         ZERO_STRUCT(io->generic.out);
    1234             : 
    1235      272884 :         create_options = io->generic.in.create_options;
    1236      272884 :         share_access   = io->generic.in.share_access;
    1237      272884 :         access_mask    = io->generic.in.access_mask;
    1238             : 
    1239      272884 :         if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
    1240           0 :                 DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
    1241             :                          share_access, io->ntcreatex.in.fname));
    1242           0 :                 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      272884 :         create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
    1250      272884 :         create_options &= ~create_options_must_ignore_mask;
    1251             : 
    1252      272884 :         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      272880 :         if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
    1259          22 :                 DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
    1260             :                          create_options, io->ntcreatex.in.fname));
    1261          22 :                 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      272858 :         if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
    1268             :                 /* no-op */
    1269           0 :         }
    1270             : 
    1271             :         /* TODO: If (unlikely) Linux does a good compressed
    1272             :          * filesystem, we might need an ioctl call for this */
    1273      272858 :         if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
    1274             :                 /* no-op */
    1275           0 :         }
    1276             : 
    1277      272858 :         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      272858 :         if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && pvfs->flags & PVFS_FLAG_STRICT_SYNC) {
    1284           6 :                 flags |= O_SYNC;
    1285             :         }
    1286             : 
    1287             : 
    1288             :         /* other create options are not allowed */
    1289      272858 :         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
    1290      132162 :             !(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      272823 :         if (access_mask & SEC_MASK_INVALID) {
    1297         309 :                 return NT_STATUS_ACCESS_DENIED;
    1298             :         }
    1299             : 
    1300             :         /* what does this bit really mean?? */
    1301      272514 :         if (req->ctx->protocol >= PROTOCOL_SMB2_02 &&
    1302      207886 :             access_mask == SEC_STD_SYNCHRONIZE) {
    1303           5 :                 return NT_STATUS_ACCESS_DENIED;
    1304             :         }
    1305             : 
    1306             :         /* cope with non-zero root_fid */
    1307      272509 :         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      272509 :         if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
    1322             :                                           FILE_ATTRIBUTE_VOLUME| 
    1323             :                                           (~FILE_ATTRIBUTE_ALL_MASK))) {
    1324          27 :                 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
    1325             :                          io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
    1326          27 :                 return NT_STATUS_INVALID_PARAMETER;
    1327             :         }
    1328             : 
    1329             :         /* we ignore some file_attr bits */
    1330      272482 :         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      272482 :         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
    1338             :                                    PVFS_RESOLVE_STREAMS, &name);
    1339      272482 :         if (!NT_STATUS_IS_OK(status)) {
    1340         113 :                 return status;
    1341             :         }
    1342             : 
    1343             :         /* if the client specified that it must not be a directory then
    1344             :            check that it isn't */
    1345      272369 :         if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
    1346       11945 :             (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
    1347         235 :                 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      272134 :         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
    1353       92681 :             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
    1354         118 :                 return NT_STATUS_NOT_A_DIRECTORY;
    1355             :         }
    1356             : 
    1357             :         /* directory opens are handled separately */
    1358      272016 :         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
    1359      260306 :             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
    1360       16494 :                 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      255522 :         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
    1366             : 
    1367      255522 :         switch (io->generic.in.open_disposition) {
    1368        3549 :         case NTCREATEX_DISP_SUPERSEDE:
    1369             :         case NTCREATEX_DISP_OVERWRITE_IF:
    1370        3549 :                 if (name->stream_name == NULL) {
    1371        3537 :                         flags |= O_TRUNC;
    1372             :                 } else {
    1373          12 :                         stream_truncate = true;
    1374             :                 }
    1375        3549 :                 create_action = NTCREATEX_ACTION_TRUNCATED;
    1376        3549 :                 break;
    1377             : 
    1378      148081 :         case NTCREATEX_DISP_OPEN:
    1379      148081 :                 if (!name->stream_exists) {
    1380       66177 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1381             :                 }
    1382       81904 :                 break;
    1383             : 
    1384         799 :         case NTCREATEX_DISP_OVERWRITE:
    1385         799 :                 if (!name->stream_exists) {
    1386           5 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1387             :                 }
    1388         794 :                 if (name->stream_name == NULL) {
    1389         794 :                         flags |= O_TRUNC;
    1390             :                 } else {
    1391           0 :                         stream_truncate = true;
    1392             :                 }
    1393         794 :                 create_action = NTCREATEX_ACTION_TRUNCATED;
    1394         794 :                 break;
    1395             : 
    1396       82999 :         case NTCREATEX_DISP_CREATE:
    1397       82999 :                 if (name->stream_exists) {
    1398         151 :                         return NT_STATUS_OBJECT_NAME_COLLISION;
    1399             :                 }
    1400       82848 :                 break;
    1401             : 
    1402       20088 :         case NTCREATEX_DISP_OPEN_IF:
    1403       20088 :                 break;
    1404             : 
    1405           6 :         default:
    1406           6 :                 DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
    1407             :                          io->generic.in.open_disposition, name->original_name));
    1408           6 :                 return NT_STATUS_INVALID_PARAMETER;
    1409             :         }
    1410             : 
    1411             :         /* handle creating a new file separately */
    1412      189183 :         if (!name->exists) {
    1413       97024 :                 status = pvfs_create_file(pvfs, req, name, io);
    1414       97024 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
    1415       97024 :                         return status;
    1416             :                 }
    1417             : 
    1418             :                 /* we've hit a race - the file was created during this call */
    1419           0 :                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
    1420           0 :                         return status;
    1421             :                 }
    1422             : 
    1423             :                 /* try re-resolving the name */
    1424           0 :                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
    1425           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1426           0 :                         return status;
    1427             :                 }
    1428             :                 /* fall through to a normal open */
    1429             :         }
    1430             : 
    1431       92159 :         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
    1432         512 :             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
    1433           5 :                 return NT_STATUS_CANNOT_DELETE;
    1434             :         }
    1435             : 
    1436             :         /* check the security descriptor */
    1437       92154 :         status = pvfs_access_check(pvfs, req, name, &access_mask);
    1438       92154 :         NT_STATUS_NOT_OK_RETURN(status);
    1439             : 
    1440       92119 :         if (io->generic.in.query_maximal_access) {
    1441          12 :                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
    1442             :                                                      &io->generic.out.maximal_access);
    1443          12 :                 NT_STATUS_NOT_OK_RETURN(status);
    1444             :         }
    1445             : 
    1446       92119 :         if (io->generic.in.query_on_disk_id) {
    1447          10 :                 ZERO_ARRAY(io->generic.out.on_disk_id);
    1448          10 :                 SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
    1449          10 :                 SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
    1450             :         }
    1451             : 
    1452       92119 :         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
    1453       92119 :         NT_STATUS_NOT_OK_RETURN(status);
    1454             : 
    1455       92119 :         f = talloc(h, struct pvfs_file);
    1456       92119 :         if (f == NULL) {
    1457           0 :                 return NT_STATUS_NO_MEMORY;
    1458             :         }
    1459             : 
    1460       92119 :         f->handle = talloc(f, struct pvfs_file_handle);
    1461       92119 :         if (f->handle == NULL) {
    1462           0 :                 return NT_STATUS_NO_MEMORY;
    1463             :         }
    1464             : 
    1465       92119 :         f->ntvfs         = h;
    1466       92119 :         f->pvfs          = pvfs;
    1467       92119 :         f->pending_list  = NULL;
    1468       92119 :         f->lock_count    = 0;
    1469       92119 :         f->share_access  = io->generic.in.share_access;
    1470       92119 :         f->access_mask   = access_mask;
    1471       92119 :         f->impersonation = io->generic.in.impersonation;
    1472       92119 :         f->notify_buffer = NULL;
    1473       92119 :         f->search        = NULL;
    1474             : 
    1475       92119 :         f->handle->pvfs              = pvfs;
    1476       92119 :         f->handle->fd                = -1;
    1477       92119 :         f->handle->name              = talloc_steal(f->handle, name);
    1478       92119 :         f->handle->create_options    = io->generic.in.create_options;
    1479       92119 :         f->handle->private_flags     = io->generic.in.private_flags;
    1480       92119 :         f->handle->seek_offset       = 0;
    1481       92119 :         f->handle->position          = 0;
    1482       92119 :         f->handle->mode              = 0;
    1483       92119 :         f->handle->oplock            = NULL;
    1484       92119 :         f->handle->have_opendb_entry = false;
    1485       92119 :         ZERO_STRUCT(f->handle->write_time);
    1486       92119 :         f->handle->open_completed    = false;
    1487             : 
    1488             :         /* form the lock context used for byte range locking and
    1489             :            opendb locking */
    1490       92119 :         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
    1491       92119 :         if (!NT_STATUS_IS_OK(status)) {
    1492           0 :                 return status;
    1493             :         }
    1494             : 
    1495       92119 :         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
    1496       92119 :         if (!NT_STATUS_IS_OK(status)) {
    1497           0 :                 return status;
    1498             :         }
    1499             : 
    1500             :         /* get a lock on this file before the actual open */
    1501       92119 :         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
    1502       92119 :         if (lck == NULL) {
    1503           0 :                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
    1504             :                          name->full_name));
    1505             :                 /* we were supposed to do a blocking lock, so something
    1506             :                    is badly wrong! */
    1507           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1508             :         }
    1509             : 
    1510       92119 :         DLIST_ADD(pvfs->files.list, f);
    1511             : 
    1512             :         /* setup a destructor to avoid file descriptor leaks on
    1513             :            abnormal termination */
    1514       92119 :         talloc_set_destructor(f, pvfs_fnum_destructor);
    1515       92119 :         talloc_set_destructor(f->handle, pvfs_handle_destructor);
    1516             : 
    1517             :         /* 
    1518             :          * Only SMB2 takes care of the delete_on_close,
    1519             :          * on existing files
    1520             :          */
    1521       92119 :         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
    1522       65949 :             req->ctx->protocol >= PROTOCOL_SMB2_02) {
    1523       65925 :                 del_on_close = true;
    1524             :         } else {
    1525       26194 :                 del_on_close = false;
    1526             :         }
    1527             : 
    1528       92119 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
    1529           0 :                 oplock_level = OPLOCK_NONE;
    1530       92119 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
    1531          88 :                 oplock_level = OPLOCK_BATCH;
    1532       92031 :         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
    1533          50 :                 oplock_level = OPLOCK_EXCLUSIVE;
    1534             :         }
    1535             : 
    1536       92119 :         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
    1537       92059 :                 allow_level_II_oplock = true;
    1538             :         }
    1539             : 
    1540             :         /* see if we are allowed to open at the same time as existing opens */
    1541       92119 :         status = odb_can_open(lck, name->stream_id,
    1542             :                               share_access, access_mask, del_on_close,
    1543             :                               io->generic.in.open_disposition, false);
    1544             : 
    1545             :         /*
    1546             :          * on a sharing violation we need to retry when the file is closed by
    1547             :          * the other user, or after 1 second
    1548             :          * on a non granted oplock we need to retry when the file is closed by
    1549             :          * the other user, or after 30 seconds
    1550             :         */
    1551       92119 :         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    1552       89234 :              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
    1553        2955 :             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
    1554        2955 :                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
    1555             :         }
    1556             : 
    1557       89164 :         if (!NT_STATUS_IS_OK(status)) {
    1558           6 :                 talloc_free(lck);
    1559           6 :                 return status;
    1560             :         }
    1561             : 
    1562       89158 :         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
    1563       16998 :                 flags |= O_RDWR;
    1564             :         } else {
    1565       72160 :                 flags |= O_RDONLY;
    1566             :         }
    1567             : 
    1568             :         /* do the actual open */
    1569       89158 :         fd = pvfs_sys_open(pvfs, f->handle->name->full_name, flags | O_NONBLOCK, 0, name->allow_override);
    1570       89158 :         if (fd == -1) {
    1571           0 :                 status = pvfs_map_errno(f->pvfs, errno);
    1572             : 
    1573           0 :                 DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n", 
    1574             :                          nt_errstr(status), f->handle->name->full_name, errno));
    1575             :                 /*
    1576             :                  * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
    1577             :                  */
    1578           0 :                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
    1579           0 :                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
    1580           0 :                         return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
    1581             :                 }
    1582             : 
    1583           0 :                 talloc_free(lck);
    1584           0 :                 return status;
    1585             :         }
    1586             : 
    1587       89158 :         f->handle->fd = fd;
    1588             : 
    1589       89158 :         status = brlock_count(f->pvfs->brl_context, f->brl_handle, &count);
    1590       89158 :         if (!NT_STATUS_IS_OK(status)) {
    1591           0 :                 talloc_free(lck);
    1592           0 :                 return status;
    1593             :         }
    1594             : 
    1595       89158 :         if (count != 0) {
    1596          79 :                 oplock_level = OPLOCK_NONE;
    1597             :         }
    1598             : 
    1599             :         /* now really mark the file as open */
    1600       89158 :         status = odb_open_file(lck, f->handle, name->full_name,
    1601       89158 :                                &f->handle->fd, name->dos.write_time,
    1602             :                                allow_level_II_oplock,
    1603             :                                oplock_level, &oplock_granted);
    1604             : 
    1605       89158 :         if (!NT_STATUS_IS_OK(status)) {
    1606           0 :                 talloc_free(lck);
    1607           0 :                 return status;
    1608             :         }
    1609             : 
    1610       89158 :         f->handle->have_opendb_entry = true;
    1611             : 
    1612       89158 :         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
    1613           0 :                 oplock_granted = OPLOCK_BATCH;
    1614       89158 :         } else if (oplock_granted != OPLOCK_NONE) {
    1615          77 :                 status = pvfs_setup_oplock(f, oplock_granted);
    1616          77 :                 if (!NT_STATUS_IS_OK(status)) {
    1617           0 :                         talloc_free(lck);
    1618           0 :                         return status;
    1619             :                 }
    1620             :         }
    1621             : 
    1622       89158 :         stream_existed = name->stream_exists;
    1623             : 
    1624             :         /* if this was a stream create then create the stream as well */
    1625       89158 :         if (!name->stream_exists) {
    1626          27 :                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
    1627          27 :                 if (!NT_STATUS_IS_OK(status)) {
    1628           0 :                         talloc_free(lck);
    1629           0 :                         return status;
    1630             :                 }
    1631          27 :                 if (stream_truncate) {
    1632           3 :                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
    1633           3 :                         if (!NT_STATUS_IS_OK(status)) {
    1634           0 :                                 talloc_free(lck);
    1635           0 :                                 return status;
    1636             :                         }
    1637             :                 }
    1638             :         }
    1639             : 
    1640             :         /* re-resolve the open fd */
    1641       89158 :         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
    1642       89158 :         if (!NT_STATUS_IS_OK(status)) {
    1643           0 :                 talloc_free(lck);
    1644           0 :                 return status;
    1645             :         }
    1646             : 
    1647       89158 :         if (f->handle->name->stream_id == 0 &&
    1648       89074 :             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
    1649       88285 :              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
    1650             :                 /* for overwrite we may need to replace file permissions */
    1651        1406 :                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
    1652        1406 :                 mode_t mode = pvfs_fileperms(pvfs, attrib);
    1653        1406 :                 if (f->handle->name->st.st_mode != mode &&
    1654        2122 :                     f->handle->name->dos.attrib != attrib &&
    1655         716 :                     pvfs_sys_fchmod(pvfs, fd, mode, name->allow_override) == -1) {
    1656           0 :                         talloc_free(lck);
    1657           0 :                         return pvfs_map_errno(pvfs, errno);
    1658             :                 }
    1659        1406 :                 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
    1660        1406 :                 name->dos.attrib = attrib;
    1661        1406 :                 status = pvfs_dosattrib_save(pvfs, name, fd);
    1662        1406 :                 if (!NT_STATUS_IS_OK(status)) {
    1663           0 :                         talloc_free(lck);
    1664           0 :                         return status;
    1665             :                 }
    1666             :         }
    1667             :             
    1668       89158 :         talloc_free(lck);
    1669             : 
    1670       89158 :         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
    1671       89158 :         NT_STATUS_NOT_OK_RETURN(status);
    1672             : 
    1673             :         /* mark the open as having completed fully, so delete on close
    1674             :            can now be used */
    1675       89158 :         f->handle->open_completed     = true;
    1676             : 
    1677       89158 :         io->generic.out.oplock_level  = oplock_granted;
    1678       89158 :         io->generic.out.file.ntvfs    = h;
    1679       89158 :         io->generic.out.create_action = stream_existed?
    1680       89158 :                 create_action:NTCREATEX_ACTION_CREATED;
    1681             :         
    1682       89158 :         io->generic.out.create_time   = name->dos.create_time;
    1683       89158 :         io->generic.out.access_time   = name->dos.access_time;
    1684       89158 :         io->generic.out.write_time    = name->dos.write_time;
    1685       89158 :         io->generic.out.change_time   = name->dos.change_time;
    1686       89158 :         io->generic.out.attrib        = name->dos.attrib;
    1687       89158 :         io->generic.out.alloc_size    = name->dos.alloc_size;
    1688       89158 :         io->generic.out.size          = name->st.st_size;
    1689       89158 :         io->generic.out.file_type     = FILE_TYPE_DISK;
    1690       89158 :         io->generic.out.ipc_state     = 0;
    1691       89158 :         io->generic.out.is_directory  = 0;
    1692             : 
    1693       89158 :         return NT_STATUS_OK;
    1694             : }
    1695             : 
    1696             : 
    1697             : /*
    1698             :   close a file
    1699             : */
    1700      404557 : NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
    1701             :                     struct ntvfs_request *req, union smb_close *io)
    1702             : {
    1703      404557 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1704             :                                   struct pvfs_state);
    1705           0 :         struct pvfs_file *f;
    1706             : 
    1707      404557 :         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
    1708           1 :                 return NT_STATUS_DOS(ERRSRV, ERRerror);
    1709             :         }
    1710             : 
    1711      404556 :         if (io->generic.level != RAW_CLOSE_GENERIC) {
    1712      202278 :                 return ntvfs_map_close(ntvfs, req, io);
    1713             :         }
    1714             : 
    1715      202278 :         f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
    1716      202278 :         if (!f) {
    1717           0 :                 return NT_STATUS_INVALID_HANDLE;
    1718             :         }
    1719             : 
    1720      202278 :         if (!null_time(io->generic.in.write_time)) {
    1721           1 :                 f->handle->write_time.update_forced = false;
    1722           1 :                 f->handle->write_time.update_on_close = true;
    1723           1 :                 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
    1724             :         }
    1725             : 
    1726      202278 :         if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
    1727           0 :                 struct pvfs_filename *name;
    1728           0 :                 NTSTATUS status;
    1729           2 :                 struct pvfs_file_handle *h = f->handle;
    1730             : 
    1731           2 :                 status = pvfs_resolve_name_handle(pvfs, h);
    1732           2 :                 if (!NT_STATUS_IS_OK(status)) {
    1733           0 :                         return status;
    1734             :                 }
    1735           2 :                 name = h->name;
    1736             : 
    1737           2 :                 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
    1738           2 :                 io->generic.out.create_time = name->dos.create_time;
    1739           2 :                 io->generic.out.access_time = name->dos.access_time;
    1740           2 :                 io->generic.out.write_time  = name->dos.write_time;
    1741           2 :                 io->generic.out.change_time = name->dos.change_time;
    1742           2 :                 io->generic.out.alloc_size  = name->dos.alloc_size;
    1743           2 :                 io->generic.out.size        = name->st.st_size;
    1744           2 :                 io->generic.out.file_attr   = name->dos.attrib;           
    1745             :         } else {
    1746      202276 :                 ZERO_STRUCT(io->generic.out);
    1747             :         }
    1748             : 
    1749      202278 :         talloc_free(f);
    1750             : 
    1751      202278 :         return NT_STATUS_OK;
    1752             : }
    1753             : 
    1754             : 
    1755             : /*
    1756             :   logoff - close all file descriptors open by a vuid
    1757             : */
    1758          21 : NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
    1759             :                      struct ntvfs_request *req)
    1760             : {
    1761          21 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1762             :                                   struct pvfs_state);
    1763           0 :         struct pvfs_file *f, *next;
    1764             : 
    1765             :         /* If pvfs is NULL, we never logged on, and no files are open. */
    1766          21 :         if(pvfs == NULL) {
    1767           0 :                 return NT_STATUS_OK;
    1768             :         }
    1769             : 
    1770          21 :         for (f=pvfs->files.list;f;f=next) {
    1771           0 :                 next = f->next;
    1772           0 :                 if (f->ntvfs->session_info == req->session_info) {
    1773           0 :                         talloc_free(f);
    1774             :                 }
    1775             :         }
    1776             : 
    1777          21 :         return NT_STATUS_OK;
    1778             : }
    1779             : 
    1780             : 
    1781             : /*
    1782             :   exit - close files for the current pid
    1783             : */
    1784         523 : NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
    1785             :                    struct ntvfs_request *req)
    1786             : {
    1787         523 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
    1788             :                                   struct pvfs_state);
    1789           0 :         struct pvfs_file *f, *next;
    1790             : 
    1791         566 :         for (f=pvfs->files.list;f;f=next) {
    1792          43 :                 next = f->next;
    1793          43 :                 if (f->ntvfs->session_info == req->session_info &&
    1794          42 :                     f->ntvfs->smbpid == req->smbpid) {
    1795          40 :                         talloc_free(f);
    1796             :                 }
    1797             :         }
    1798             : 
    1799         523 :         return NT_STATUS_OK;
    1800             : }
    1801             : 
    1802             : 
    1803             : /*
    1804             :   change the delete on close flag on an already open file
    1805             : */
    1806         324 : NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
    1807             :                                   struct ntvfs_request *req, 
    1808             :                                   struct pvfs_file *f, bool del_on_close)
    1809             : {
    1810           0 :         struct odb_lock *lck;
    1811           0 :         NTSTATUS status;
    1812             : 
    1813         324 :         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
    1814           3 :                 return NT_STATUS_CANNOT_DELETE;
    1815             :         }
    1816             :         
    1817         321 :         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
    1818         267 :             !pvfs_directory_empty(pvfs, f->handle->name)) {
    1819           4 :                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
    1820             :         }
    1821             : 
    1822         317 :         if (del_on_close) {
    1823         296 :                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1824             :         } else {
    1825          21 :                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
    1826             :         }
    1827             :         
    1828         317 :         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
    1829         317 :         if (lck == NULL) {
    1830           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1831             :         }
    1832             : 
    1833         317 :         status = odb_set_delete_on_close(lck, del_on_close);
    1834             : 
    1835         317 :         talloc_free(lck);
    1836             : 
    1837         317 :         return status;
    1838             : }
    1839             : 
    1840             : 
    1841             : /*
    1842             :   determine if a file can be deleted, or if it is prevented by an
    1843             :   already open file
    1844             : */
    1845       31060 : NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
    1846             :                          struct ntvfs_request *req,
    1847             :                          struct pvfs_filename *name,
    1848             :                          struct odb_lock **lckp)
    1849             : {
    1850           0 :         NTSTATUS status;
    1851           0 :         DATA_BLOB key;
    1852           0 :         struct odb_lock *lck;
    1853           0 :         uint32_t share_access;
    1854           0 :         uint32_t access_mask;
    1855           0 :         bool delete_on_close;
    1856             : 
    1857       31060 :         status = pvfs_locking_key(name, name, &key);
    1858       31060 :         if (!NT_STATUS_IS_OK(status)) {
    1859           0 :                 return NT_STATUS_NO_MEMORY;
    1860             :         }
    1861             : 
    1862       31060 :         lck = odb_lock(req, pvfs->odb_context, &key);
    1863       31060 :         if (lck == NULL) {
    1864           0 :                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
    1865           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1866             :         }
    1867             : 
    1868       31060 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    1869             :                           NTCREATEX_SHARE_ACCESS_WRITE |
    1870             :                           NTCREATEX_SHARE_ACCESS_DELETE;
    1871       31060 :         access_mask     = SEC_STD_DELETE;
    1872       31060 :         delete_on_close = true;
    1873             : 
    1874       31060 :         status = odb_can_open(lck, name->stream_id,
    1875             :                               share_access, access_mask, delete_on_close,
    1876             :                               NTCREATEX_DISP_OPEN, false);
    1877             : 
    1878       31060 :         if (NT_STATUS_IS_OK(status)) {
    1879       31021 :                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
    1880             :         }
    1881             : 
    1882             :         /*
    1883             :          * if it's a sharing violation or we got no oplock
    1884             :          * only keep the lock if the caller requested access
    1885             :          * to the lock
    1886             :          */
    1887       31060 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    1888       31028 :             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    1889          38 :                 if (lckp) {
    1890          37 :                         *lckp = lck;
    1891             :                 } else {
    1892           1 :                         talloc_free(lck);
    1893             :                 }
    1894       31022 :         } else if (!NT_STATUS_IS_OK(status)) {
    1895           1 :                 talloc_free(lck);
    1896           1 :                 if (lckp) {
    1897           0 :                         *lckp = NULL;
    1898             :                 }
    1899       31021 :         } else if (lckp) {
    1900       31019 :                 *lckp = lck;
    1901             :         }
    1902             : 
    1903       31060 :         return status;
    1904             : }
    1905             : 
    1906             : /*
    1907             :   determine if a file can be renamed, or if it is prevented by an
    1908             :   already open file
    1909             : */
    1910         115 : NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
    1911             :                          struct ntvfs_request *req,
    1912             :                          struct pvfs_filename *name,
    1913             :                          struct odb_lock **lckp)
    1914             : {
    1915           0 :         NTSTATUS status;
    1916           0 :         DATA_BLOB key;
    1917           0 :         struct odb_lock *lck;
    1918           0 :         uint32_t share_access;
    1919           0 :         uint32_t access_mask;
    1920           0 :         bool delete_on_close;
    1921             : 
    1922         115 :         status = pvfs_locking_key(name, name, &key);
    1923         115 :         if (!NT_STATUS_IS_OK(status)) {
    1924           0 :                 return NT_STATUS_NO_MEMORY;
    1925             :         }
    1926             : 
    1927         115 :         lck = odb_lock(req, pvfs->odb_context, &key);
    1928         115 :         if (lck == NULL) {
    1929           0 :                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
    1930           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1931             :         }
    1932             : 
    1933         115 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    1934             :                           NTCREATEX_SHARE_ACCESS_WRITE;
    1935         115 :         access_mask     = SEC_STD_DELETE;
    1936         115 :         delete_on_close = false;
    1937             : 
    1938         115 :         status = odb_can_open(lck, name->stream_id,
    1939             :                               share_access, access_mask, delete_on_close,
    1940             :                               NTCREATEX_DISP_OPEN, false);
    1941             : 
    1942             :         /*
    1943             :          * if it's a sharing violation or we got no oplock
    1944             :          * only keep the lock if the caller requested access
    1945             :          * to the lock
    1946             :          */
    1947         115 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    1948         104 :             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    1949          15 :                 if (lckp) {
    1950          15 :                         *lckp = lck;
    1951             :                 } else {
    1952           0 :                         talloc_free(lck);
    1953             :                 }
    1954         100 :         } else if (!NT_STATUS_IS_OK(status)) {
    1955           0 :                 talloc_free(lck);
    1956           0 :                 if (lckp) {
    1957           0 :                         *lckp = NULL;
    1958             :                 }
    1959         100 :         } else if (lckp) {
    1960         100 :                 *lckp = lck;
    1961             :         }
    1962             : 
    1963         115 :         return status;
    1964             : }
    1965             : 
    1966             : /*
    1967             :   determine if the file size of a file can be changed,
    1968             :   or if it is prevented by an already open file
    1969             : */
    1970          13 : NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
    1971             :                                    struct ntvfs_request *req,
    1972             :                                    struct pvfs_filename *name,
    1973             :                                    struct odb_lock **lckp)
    1974             : {
    1975           0 :         NTSTATUS status;
    1976           0 :         DATA_BLOB key;
    1977           0 :         struct odb_lock *lck;
    1978           0 :         uint32_t share_access;
    1979           0 :         uint32_t access_mask;
    1980           0 :         bool break_to_none;
    1981           0 :         bool delete_on_close;
    1982             : 
    1983          13 :         status = pvfs_locking_key(name, name, &key);
    1984          13 :         if (!NT_STATUS_IS_OK(status)) {
    1985           0 :                 return NT_STATUS_NO_MEMORY;
    1986             :         }
    1987             : 
    1988          13 :         lck = odb_lock(req, pvfs->odb_context, &key);
    1989          13 :         if (lck == NULL) {
    1990           0 :                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
    1991           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1992             :         }
    1993             : 
    1994          13 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    1995             :                           NTCREATEX_SHARE_ACCESS_WRITE |
    1996             :                           NTCREATEX_SHARE_ACCESS_DELETE;
    1997             :         /*
    1998             :          * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
    1999             :          * a comment that this seemed to be wrong, but matched windows
    2000             :          * behaviour. It now appears that this windows behaviour is
    2001             :          * just a bug.
    2002             :          */
    2003          13 :         access_mask     = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
    2004          13 :         delete_on_close = false;
    2005          13 :         break_to_none   = true;
    2006             : 
    2007          13 :         status = odb_can_open(lck, name->stream_id,
    2008             :                               share_access, access_mask, delete_on_close,
    2009             :                               NTCREATEX_DISP_OPEN, break_to_none);
    2010             : 
    2011             :         /*
    2012             :          * if it's a sharing violation or we got no oplock
    2013             :          * only keep the lock if the caller requested access
    2014             :          * to the lock
    2015             :          */
    2016          13 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
    2017          11 :             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
    2018           5 :                 if (lckp) {
    2019           5 :                         *lckp = lck;
    2020             :                 } else {
    2021           0 :                         talloc_free(lck);
    2022             :                 }
    2023           8 :         } else if (!NT_STATUS_IS_OK(status)) {
    2024           0 :                 talloc_free(lck);
    2025           0 :                 if (lckp) {
    2026           0 :                         *lckp = NULL;
    2027             :                 }
    2028           8 :         } else if (lckp) {
    2029           8 :                 *lckp = lck;
    2030             :         }
    2031             : 
    2032          13 :         return status;
    2033             : }
    2034             : 
    2035             : /*
    2036             :   determine if file meta data can be accessed, or if it is prevented by an
    2037             :   already open file
    2038             : */
    2039        5078 : NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
    2040             :                        struct ntvfs_request *req,
    2041             :                        struct pvfs_filename *name)
    2042             : {
    2043           0 :         NTSTATUS status;
    2044           0 :         DATA_BLOB key;
    2045           0 :         struct odb_lock *lck;
    2046           0 :         uint32_t share_access;
    2047           0 :         uint32_t access_mask;
    2048           0 :         bool delete_on_close;
    2049             : 
    2050        5078 :         status = pvfs_locking_key(name, name, &key);
    2051        5078 :         if (!NT_STATUS_IS_OK(status)) {
    2052           0 :                 return NT_STATUS_NO_MEMORY;
    2053             :         }
    2054             : 
    2055        5078 :         lck = odb_lock(req, pvfs->odb_context, &key);
    2056        5078 :         if (lck == NULL) {
    2057           0 :                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
    2058           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2059             :         }
    2060             : 
    2061        5078 :         share_access    = NTCREATEX_SHARE_ACCESS_READ |
    2062             :                           NTCREATEX_SHARE_ACCESS_WRITE;
    2063        5078 :         access_mask     = SEC_FILE_READ_ATTRIBUTE;
    2064        5078 :         delete_on_close = false;
    2065             : 
    2066        5078 :         status = odb_can_open(lck, name->stream_id,
    2067             :                               share_access, access_mask, delete_on_close,
    2068             :                               NTCREATEX_DISP_OPEN, false);
    2069             : 
    2070        5078 :         if (!NT_STATUS_IS_OK(status)) {
    2071          32 :                 talloc_free(lck);
    2072             :         }
    2073             : 
    2074        5078 :         return status;
    2075             : }
    2076             : 
    2077             : 
    2078             : /*
    2079             :   determine if delete on close is set on 
    2080             : */
    2081        1073 : bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
    2082             : {
    2083           0 :         NTSTATUS status;
    2084           0 :         bool del_on_close;
    2085             : 
    2086        1073 :         status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
    2087             :                                     &del_on_close, NULL);
    2088        1073 :         if (!NT_STATUS_IS_OK(status)) {
    2089           0 :                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
    2090           0 :                 return false;
    2091             :         }
    2092             : 
    2093        1073 :         return del_on_close;
    2094             : }

Generated by: LCOV version 1.14