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