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