Ignore and handle more NT Create & X options.
[kai/samba.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 {
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         if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1210                 return NT_STATUS_NOT_SUPPORTED;
1211         }
1212
1213         /* TODO: When we implement HSM, add a hook here not to pull
1214          * the actual file off tape, when this option is passed from
1215          * the client */
1216         if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1217                 /* no-op */
1218         }
1219
1220         /* These options are ignored */
1221         if (create_options & (NTCREATEX_OPTIONS_FREE_SPACE_QUERY | NTCREATEX_OPTIONS_OPFILTER)) {
1222                 /* no-op */
1223         }
1224
1225         /* other create options are not allowed */
1226         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1227             !(access_mask & SEC_STD_DELETE)) {
1228                 return NT_STATUS_INVALID_PARAMETER;
1229         }
1230
1231         if (access_mask & SEC_MASK_INVALID) {
1232                 return NT_STATUS_ACCESS_DENIED;
1233         }
1234
1235         /* what does this bit really mean?? */
1236         if (req->ctx->protocol == PROTOCOL_SMB2 &&
1237             access_mask == SEC_STD_SYNCHRONIZE) {
1238                 return NT_STATUS_ACCESS_DENIED;
1239         }
1240
1241         if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1242                                           FILE_ATTRIBUTE_VOLUME| 
1243                                           (~FILE_ATTRIBUTE_ALL_MASK))) {
1244                 return NT_STATUS_INVALID_PARAMETER;
1245         }
1246
1247         /* we ignore some file_attr bits */
1248         io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED | 
1249                                         FILE_ATTRIBUTE_COMPRESSED |
1250                                         FILE_ATTRIBUTE_REPARSE_POINT |
1251                                         FILE_ATTRIBUTE_SPARSE |
1252                                         FILE_ATTRIBUTE_NORMAL);
1253
1254         /* resolve the cifs name to a posix name */
1255         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
1256                                    PVFS_RESOLVE_STREAMS, &name);
1257         if (!NT_STATUS_IS_OK(status)) {
1258                 return status;
1259         }
1260
1261         /* if the client specified that it must not be a directory then
1262            check that it isn't */
1263         if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1264             (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1265                 return NT_STATUS_FILE_IS_A_DIRECTORY;
1266         }
1267
1268         /* if the client specified that it must be a directory then
1269            check that it is */
1270         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1271             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1272                 return NT_STATUS_NOT_A_DIRECTORY;
1273         }
1274
1275         /* directory opens are handled separately */
1276         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1277             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1278                 return pvfs_open_directory(pvfs, req, name, io);
1279         }
1280
1281         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1282            open doesn't match */
1283         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1284
1285         flags = 0;
1286
1287         switch (io->generic.in.open_disposition) {
1288         case NTCREATEX_DISP_SUPERSEDE:
1289         case NTCREATEX_DISP_OVERWRITE_IF:
1290                 if (name->stream_name == NULL) {
1291                         flags = O_TRUNC;
1292                 } else {
1293                         stream_truncate = true;
1294                 }
1295                 create_action = NTCREATEX_ACTION_TRUNCATED;
1296                 break;
1297
1298         case NTCREATEX_DISP_OPEN:
1299                 if (!name->stream_exists) {
1300                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1301                 }
1302                 flags = 0;
1303                 break;
1304
1305         case NTCREATEX_DISP_OVERWRITE:
1306                 if (!name->stream_exists) {
1307                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1308                 }
1309                 if (name->stream_name == NULL) {
1310                         flags = O_TRUNC;
1311                 } else {
1312                         stream_truncate = true;
1313                 }
1314                 create_action = NTCREATEX_ACTION_TRUNCATED;
1315                 break;
1316
1317         case NTCREATEX_DISP_CREATE:
1318                 if (name->stream_exists) {
1319                         return NT_STATUS_OBJECT_NAME_COLLISION;
1320                 }
1321                 flags = 0;
1322                 break;
1323
1324         case NTCREATEX_DISP_OPEN_IF:
1325                 flags = 0;
1326                 break;
1327
1328         default:
1329                 return NT_STATUS_INVALID_PARAMETER;
1330         }
1331
1332         /* handle creating a new file separately */
1333         if (!name->exists) {
1334                 status = pvfs_create_file(pvfs, req, name, io);
1335                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1336                         return status;
1337                 }
1338
1339                 /* we've hit a race - the file was created during this call */
1340                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1341                         return status;
1342                 }
1343
1344                 /* try re-resolving the name */
1345                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1346                 if (!NT_STATUS_IS_OK(status)) {
1347                         return status;
1348                 }
1349                 /* fall through to a normal open */
1350         }
1351
1352         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1353             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1354                 return NT_STATUS_CANNOT_DELETE;
1355         }
1356
1357         /* check the security descriptor */
1358         status = pvfs_access_check(pvfs, req, name, &access_mask);
1359         NT_STATUS_NOT_OK_RETURN(status);
1360
1361         if (io->generic.in.query_maximal_access) {
1362                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
1363                                                      &io->generic.out.maximal_access);
1364                 NT_STATUS_NOT_OK_RETURN(status);
1365         }
1366
1367         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1368         NT_STATUS_NOT_OK_RETURN(status);
1369
1370         f = talloc(h, struct pvfs_file);
1371         if (f == NULL) {
1372                 return NT_STATUS_NO_MEMORY;
1373         }
1374
1375         f->handle = talloc(f, struct pvfs_file_handle);
1376         if (f->handle == NULL) {
1377                 return NT_STATUS_NO_MEMORY;
1378         }
1379
1380         f->ntvfs         = h;
1381         f->pvfs          = pvfs;
1382         f->pending_list  = NULL;
1383         f->lock_count    = 0;
1384         f->share_access  = io->generic.in.share_access;
1385         f->access_mask   = access_mask;
1386         f->impersonation = io->generic.in.impersonation;
1387         f->notify_buffer = NULL;
1388         f->search        = NULL;
1389
1390         f->handle->pvfs              = pvfs;
1391         f->handle->fd                = -1;
1392         f->handle->name              = talloc_steal(f->handle, name);
1393         f->handle->create_options    = io->generic.in.create_options;
1394         f->handle->seek_offset       = 0;
1395         f->handle->position          = 0;
1396         f->handle->mode              = 0;
1397         f->handle->oplock            = NULL;
1398         f->handle->have_opendb_entry = false;
1399         ZERO_STRUCT(f->handle->write_time);
1400         f->handle->open_completed    = false;
1401
1402         /* form the lock context used for byte range locking and
1403            opendb locking */
1404         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1405         if (!NT_STATUS_IS_OK(status)) {
1406                 return status;
1407         }
1408
1409         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1410         if (!NT_STATUS_IS_OK(status)) {
1411                 return status;
1412         }
1413
1414         /* get a lock on this file before the actual open */
1415         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1416         if (lck == NULL) {
1417                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1418                          name->full_name));
1419                 /* we were supposed to do a blocking lock, so something
1420                    is badly wrong! */
1421                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1422         }
1423
1424         DLIST_ADD(pvfs->files.list, f);
1425
1426         /* setup a destructor to avoid file descriptor leaks on
1427            abnormal termination */
1428         talloc_set_destructor(f, pvfs_fnum_destructor);
1429         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1430
1431         /* 
1432          * Only SMB2 takes care of the delete_on_close,
1433          * on existing files
1434          */
1435         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1436             req->ctx->protocol == PROTOCOL_SMB2) {
1437                 del_on_close = true;
1438         } else {
1439                 del_on_close = false;
1440         }
1441
1442         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1443                 oplock_level = OPLOCK_NONE;
1444         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1445                 oplock_level = OPLOCK_BATCH;
1446         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1447                 oplock_level = OPLOCK_EXCLUSIVE;
1448         }
1449
1450         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1451                 allow_level_II_oplock = true;
1452         }
1453
1454         /* see if we are allowed to open at the same time as existing opens */
1455         status = odb_can_open(lck, name->stream_id,
1456                               share_access, access_mask, del_on_close,
1457                               io->generic.in.open_disposition, false);
1458
1459         /*
1460          * on a sharing violation we need to retry when the file is closed by
1461          * the other user, or after 1 second
1462          * on a non granted oplock we need to retry when the file is closed by
1463          * the other user, or after 30 seconds
1464         */
1465         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1466              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1467             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1468                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1469         }
1470
1471         if (!NT_STATUS_IS_OK(status)) {
1472                 talloc_free(lck);
1473                 return status;
1474         }
1475
1476         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1477                 flags |= O_RDWR;
1478         } else {
1479                 flags |= O_RDONLY;
1480         }
1481
1482         /* do the actual open */
1483         fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1484         if (fd == -1) {
1485                 status = pvfs_map_errno(f->pvfs, errno);
1486
1487                 /*
1488                  * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1489                  */
1490                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1491                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1492                         return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1493                 }
1494
1495                 talloc_free(lck);
1496                 return status;
1497         }
1498
1499         f->handle->fd = fd;
1500
1501         /* now really mark the file as open */
1502         status = odb_open_file(lck, f->handle, name->full_name,
1503                                &f->handle->fd, name->dos.write_time,
1504                                allow_level_II_oplock,
1505                                oplock_level, &oplock_granted);
1506
1507         if (!NT_STATUS_IS_OK(status)) {
1508                 talloc_free(lck);
1509                 return status;
1510         }
1511
1512         f->handle->have_opendb_entry = true;
1513
1514         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1515                 oplock_granted = OPLOCK_BATCH;
1516         } else if (oplock_granted != OPLOCK_NONE) {
1517                 status = pvfs_setup_oplock(f, oplock_granted);
1518                 if (!NT_STATUS_IS_OK(status)) {
1519                         talloc_free(lck);
1520                         return status;
1521                 }
1522         }
1523
1524         stream_existed = name->stream_exists;
1525
1526         /* if this was a stream create then create the stream as well */
1527         if (!name->stream_exists) {
1528                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1529                 if (!NT_STATUS_IS_OK(status)) {
1530                         talloc_free(lck);
1531                         return status;
1532                 }
1533                 if (stream_truncate) {
1534                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1535                         if (!NT_STATUS_IS_OK(status)) {
1536                                 talloc_free(lck);
1537                                 return status;
1538                         }
1539                 }
1540         }
1541
1542         /* re-resolve the open fd */
1543         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1544         if (!NT_STATUS_IS_OK(status)) {
1545                 talloc_free(lck);
1546                 return status;
1547         }
1548
1549         if (f->handle->name->stream_id == 0 &&
1550             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1551              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1552                 /* for overwrite we need to replace file permissions */
1553                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1554                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1555                 if (fchmod(fd, mode) == -1) {
1556                         talloc_free(lck);
1557                         return pvfs_map_errno(pvfs, errno);
1558                 }
1559                 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1560                 name->dos.attrib = attrib;
1561                 status = pvfs_dosattrib_save(pvfs, name, fd);
1562                 if (!NT_STATUS_IS_OK(status)) {
1563                         talloc_free(lck);
1564                         return status;
1565                 }
1566         }
1567             
1568         talloc_free(lck);
1569
1570         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1571         NT_STATUS_NOT_OK_RETURN(status);
1572
1573         /* mark the open as having completed fully, so delete on close
1574            can now be used */
1575         f->handle->open_completed     = true;
1576
1577         io->generic.out.oplock_level  = oplock_granted;
1578         io->generic.out.file.ntvfs    = h;
1579         io->generic.out.create_action = stream_existed?
1580                 create_action:NTCREATEX_ACTION_CREATED;
1581         
1582         io->generic.out.create_time   = name->dos.create_time;
1583         io->generic.out.access_time   = name->dos.access_time;
1584         io->generic.out.write_time    = name->dos.write_time;
1585         io->generic.out.change_time   = name->dos.change_time;
1586         io->generic.out.attrib        = name->dos.attrib;
1587         io->generic.out.alloc_size    = name->dos.alloc_size;
1588         io->generic.out.size          = name->st.st_size;
1589         io->generic.out.file_type     = FILE_TYPE_DISK;
1590         io->generic.out.ipc_state     = 0;
1591         io->generic.out.is_directory  = 0;
1592
1593         return NT_STATUS_OK;
1594 }
1595
1596
1597 /*
1598   close a file
1599 */
1600 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1601                     struct ntvfs_request *req, union smb_close *io)
1602 {
1603         struct pvfs_state *pvfs = ntvfs->private_data;
1604         struct pvfs_file *f;
1605
1606         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1607                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1608         }
1609
1610         if (io->generic.level != RAW_CLOSE_GENERIC) {
1611                 return ntvfs_map_close(ntvfs, req, io);
1612         }
1613
1614         f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1615         if (!f) {
1616                 return NT_STATUS_INVALID_HANDLE;
1617         }
1618
1619         if (!null_time(io->generic.in.write_time)) {
1620                 f->handle->write_time.update_forced = false;
1621                 f->handle->write_time.update_on_close = true;
1622                 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1623         }
1624
1625         if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1626                 struct pvfs_filename *name;
1627                 NTSTATUS status;
1628                 struct pvfs_file_handle *h = f->handle;
1629
1630                 status = pvfs_resolve_name_handle(pvfs, h);
1631                 if (!NT_STATUS_IS_OK(status)) {
1632                         return status;
1633                 }
1634                 name = h->name;
1635
1636                 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1637                 io->generic.out.create_time = name->dos.create_time;
1638                 io->generic.out.access_time = name->dos.access_time;
1639                 io->generic.out.write_time  = name->dos.write_time;
1640                 io->generic.out.change_time = name->dos.change_time;
1641                 io->generic.out.alloc_size  = name->dos.alloc_size;
1642                 io->generic.out.size        = name->st.st_size;
1643                 io->generic.out.file_attr   = name->dos.attrib;         
1644         } else {
1645                 ZERO_STRUCT(io->generic.out);
1646         }
1647
1648         talloc_free(f);
1649
1650         return NT_STATUS_OK;
1651 }
1652
1653
1654 /*
1655   logoff - close all file descriptors open by a vuid
1656 */
1657 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1658                      struct ntvfs_request *req)
1659 {
1660         struct pvfs_state *pvfs = ntvfs->private_data;
1661         struct pvfs_file *f, *next;
1662
1663         for (f=pvfs->files.list;f;f=next) {
1664                 next = f->next;
1665                 if (f->ntvfs->session_info == req->session_info) {
1666                         talloc_free(f);
1667                 }
1668         }
1669
1670         return NT_STATUS_OK;
1671 }
1672
1673
1674 /*
1675   exit - close files for the current pid
1676 */
1677 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1678                    struct ntvfs_request *req)
1679 {
1680         struct pvfs_state *pvfs = ntvfs->private_data;
1681         struct pvfs_file *f, *next;
1682
1683         for (f=pvfs->files.list;f;f=next) {
1684                 next = f->next;
1685                 if (f->ntvfs->session_info == req->session_info &&
1686                     f->ntvfs->smbpid == req->smbpid) {
1687                         talloc_free(f);
1688                 }
1689         }
1690
1691         return NT_STATUS_OK;
1692 }
1693
1694
1695 /*
1696   change the delete on close flag on an already open file
1697 */
1698 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1699                                   struct ntvfs_request *req, 
1700                                   struct pvfs_file *f, bool del_on_close)
1701 {
1702         struct odb_lock *lck;
1703         NTSTATUS status;
1704
1705         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1706                 return NT_STATUS_CANNOT_DELETE;
1707         }
1708         
1709         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1710             !pvfs_directory_empty(pvfs, f->handle->name)) {
1711                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1712         }
1713
1714         if (del_on_close) {
1715                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1716         } else {
1717                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1718         }
1719         
1720         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1721         if (lck == NULL) {
1722                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1723         }
1724
1725         status = odb_set_delete_on_close(lck, del_on_close);
1726
1727         talloc_free(lck);
1728
1729         return status;
1730 }
1731
1732
1733 /*
1734   determine if a file can be deleted, or if it is prevented by an
1735   already open file
1736 */
1737 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1738                          struct ntvfs_request *req,
1739                          struct pvfs_filename *name,
1740                          struct odb_lock **lckp)
1741 {
1742         NTSTATUS status;
1743         DATA_BLOB key;
1744         struct odb_lock *lck;
1745         uint32_t share_access;
1746         uint32_t access_mask;
1747         bool delete_on_close;
1748
1749         status = pvfs_locking_key(name, name, &key);
1750         if (!NT_STATUS_IS_OK(status)) {
1751                 return NT_STATUS_NO_MEMORY;
1752         }
1753
1754         lck = odb_lock(req, pvfs->odb_context, &key);
1755         if (lck == NULL) {
1756                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1757                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1758         }
1759
1760         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1761                           NTCREATEX_SHARE_ACCESS_WRITE |
1762                           NTCREATEX_SHARE_ACCESS_DELETE;
1763         access_mask     = SEC_STD_DELETE;
1764         delete_on_close = true;
1765
1766         status = odb_can_open(lck, name->stream_id,
1767                               share_access, access_mask, delete_on_close,
1768                               NTCREATEX_DISP_OPEN, false);
1769
1770         if (NT_STATUS_IS_OK(status)) {
1771                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1772         }
1773
1774         /*
1775          * if it's a sharing violation or we got no oplock
1776          * only keep the lock if the caller requested access
1777          * to the lock
1778          */
1779         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1780             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1781                 if (lckp) {
1782                         *lckp = lck;
1783                 } else {
1784                         talloc_free(lck);
1785                 }
1786         } else if (!NT_STATUS_IS_OK(status)) {
1787                 talloc_free(lck);
1788                 if (lckp) {
1789                         *lckp = NULL;
1790                 }
1791         } else if (lckp) {
1792                 *lckp = lck;
1793         }
1794
1795         return status;
1796 }
1797
1798 /*
1799   determine if a file can be renamed, or if it is prevented by an
1800   already open file
1801 */
1802 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1803                          struct ntvfs_request *req,
1804                          struct pvfs_filename *name,
1805                          struct odb_lock **lckp)
1806 {
1807         NTSTATUS status;
1808         DATA_BLOB key;
1809         struct odb_lock *lck;
1810         uint32_t share_access;
1811         uint32_t access_mask;
1812         bool delete_on_close;
1813
1814         status = pvfs_locking_key(name, name, &key);
1815         if (!NT_STATUS_IS_OK(status)) {
1816                 return NT_STATUS_NO_MEMORY;
1817         }
1818
1819         lck = odb_lock(req, pvfs->odb_context, &key);
1820         if (lck == NULL) {
1821                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1822                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1823         }
1824
1825         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1826                           NTCREATEX_SHARE_ACCESS_WRITE;
1827         access_mask     = SEC_STD_DELETE;
1828         delete_on_close = false;
1829
1830         status = odb_can_open(lck, name->stream_id,
1831                               share_access, access_mask, delete_on_close,
1832                               NTCREATEX_DISP_OPEN, false);
1833
1834         /*
1835          * if it's a sharing violation or we got no oplock
1836          * only keep the lock if the caller requested access
1837          * to the lock
1838          */
1839         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1840             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1841                 if (lckp) {
1842                         *lckp = lck;
1843                 } else {
1844                         talloc_free(lck);
1845                 }
1846         } else if (!NT_STATUS_IS_OK(status)) {
1847                 talloc_free(lck);
1848                 if (lckp) {
1849                         *lckp = NULL;
1850                 }
1851         } else if (lckp) {
1852                 *lckp = lck;
1853         }
1854
1855         return status;
1856 }
1857
1858 /*
1859   determine if the file size of a file can be changed,
1860   or if it is prevented by an already open file
1861 */
1862 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1863                                    struct ntvfs_request *req,
1864                                    struct pvfs_filename *name,
1865                                    struct odb_lock **lckp)
1866 {
1867         NTSTATUS status;
1868         DATA_BLOB key;
1869         struct odb_lock *lck;
1870         uint32_t share_access;
1871         uint32_t access_mask;
1872         bool break_to_none;
1873         bool delete_on_close;
1874
1875         status = pvfs_locking_key(name, name, &key);
1876         if (!NT_STATUS_IS_OK(status)) {
1877                 return NT_STATUS_NO_MEMORY;
1878         }
1879
1880         lck = odb_lock(req, pvfs->odb_context, &key);
1881         if (lck == NULL) {
1882                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1883                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1884         }
1885
1886         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1887                           NTCREATEX_SHARE_ACCESS_WRITE |
1888                           NTCREATEX_SHARE_ACCESS_DELETE;
1889         /*
1890          * I would have thought that we would need to pass
1891          * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1892          *
1893          * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1894          * to set the filesize.
1895          *
1896          * --metze
1897          */
1898         access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
1899         delete_on_close = false;
1900         break_to_none   = true;
1901
1902         status = odb_can_open(lck, name->stream_id,
1903                               share_access, access_mask, delete_on_close,
1904                               NTCREATEX_DISP_OPEN, break_to_none);
1905
1906         /*
1907          * if it's a sharing violation or we got no oplock
1908          * only keep the lock if the caller requested access
1909          * to the lock
1910          */
1911         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1912             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1913                 if (lckp) {
1914                         *lckp = lck;
1915                 } else {
1916                         talloc_free(lck);
1917                 }
1918         } else if (!NT_STATUS_IS_OK(status)) {
1919                 talloc_free(lck);
1920                 if (lckp) {
1921                         *lckp = NULL;
1922                 }
1923         } else if (lckp) {
1924                 *lckp = lck;
1925         }
1926
1927         return status;
1928 }
1929
1930 /*
1931   determine if file meta data can be accessed, or if it is prevented by an
1932   already open file
1933 */
1934 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1935                        struct ntvfs_request *req,
1936                        struct pvfs_filename *name)
1937 {
1938         NTSTATUS status;
1939         DATA_BLOB key;
1940         struct odb_lock *lck;
1941         uint32_t share_access;
1942         uint32_t access_mask;
1943         bool delete_on_close;
1944
1945         status = pvfs_locking_key(name, name, &key);
1946         if (!NT_STATUS_IS_OK(status)) {
1947                 return NT_STATUS_NO_MEMORY;
1948         }
1949
1950         lck = odb_lock(req, pvfs->odb_context, &key);
1951         if (lck == NULL) {
1952                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1953                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1954         }
1955
1956         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1957                           NTCREATEX_SHARE_ACCESS_WRITE;
1958         access_mask     = SEC_FILE_READ_ATTRIBUTE;
1959         delete_on_close = false;
1960
1961         status = odb_can_open(lck, name->stream_id,
1962                               share_access, access_mask, delete_on_close,
1963                               NTCREATEX_DISP_OPEN, false);
1964
1965         if (!NT_STATUS_IS_OK(status)) {
1966                 talloc_free(lck);
1967         }
1968
1969         return status;
1970 }
1971
1972
1973 /*
1974   determine if delete on close is set on 
1975 */
1976 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1977 {
1978         NTSTATUS status;
1979         bool del_on_close;
1980
1981         status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
1982                                     &del_on_close, NULL);
1983         if (!NT_STATUS_IS_OK(status)) {
1984                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1985                 return false;
1986         }
1987
1988         return del_on_close;
1989 }