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