pvfs_open: fix odb_can_open() callers after prototype change
[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         int open_count;
54         char *path = NULL;
55
56         if (h->name->stream_name == NULL && 
57             pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
58             open_count == 1) {
59                 NTSTATUS status;
60                 status = pvfs_xattr_unlink_hook(h->pvfs, path);
61                 if (!NT_STATUS_IS_OK(status)) {
62                         DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
63                                  path, nt_errstr(status)));
64                 }
65                 if (rmdir(path) != 0) {
66                         DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", 
67                                  path, strerror(errno)));
68                 }
69         }
70
71         talloc_free(path);
72
73         if (h->have_opendb_entry) {
74                 struct odb_lock *lck;
75                 NTSTATUS status;
76
77                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
78                 if (lck == NULL) {
79                         DEBUG(0,("Unable to lock opendb for close\n"));
80                         return 0;
81                 }
82
83                 status = odb_close_file(lck, h);
84                 if (!NT_STATUS_IS_OK(status)) {
85                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
86                                  h->name->full_name, nt_errstr(status)));
87                 }
88
89                 talloc_free(lck);
90         }
91
92         return 0;
93 }
94
95 /*
96   cleanup a open directory fnum
97 */
98 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
99 {
100         DLIST_REMOVE(f->pvfs->files.list, f);
101         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
102
103         return 0;
104 }
105
106 /*
107   setup any EAs and the ACL on newly created files/directories
108 */
109 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
110                                         struct ntvfs_request *req,
111                                         struct pvfs_filename *name,
112                                         int fd, struct pvfs_file *f,
113                                         union smb_open *io)
114 {
115         NTSTATUS status;
116
117         /* setup any EAs that were asked for */
118         if (io->ntcreatex.in.ea_list) {
119                 status = pvfs_setfileinfo_ea_set(pvfs, name, fd, 
120                                                  io->ntcreatex.in.ea_list->num_eas,
121                                                  io->ntcreatex.in.ea_list->eas);
122                 if (!NT_STATUS_IS_OK(status)) {
123                         return status;
124                 }
125         }
126
127         /* setup an initial sec_desc if requested */
128         if (io->ntcreatex.in.sec_desc) {
129                 union smb_setfileinfo set;
130 /* 
131  * TODO: set the full ACL! 
132  *       - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
133  *         when a SACL is present on the sd,
134  *         but the user doesn't have SeSecurityPrivilege
135  *       - w2k3 allows it
136  */
137                 set.set_secdesc.in.file.ntvfs = f->ntvfs;
138                 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
139                 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
140
141                 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
142         } else {
143                 /* otherwise setup an inherited acl from the parent */
144                 status = pvfs_acl_inherit(pvfs, req, name, fd);
145         }
146
147         return status;
148 }
149
150 /*
151   form the lock context used for opendb locking. Note that we must
152   zero here to take account of possible padding on some architectures
153 */
154 static NTSTATUS pvfs_locking_key(struct pvfs_filename *name, 
155                                  TALLOC_CTX *mem_ctx, DATA_BLOB *key)
156 {
157         struct {
158                 dev_t device;
159                 ino_t inode;
160         } lock_context;
161         ZERO_STRUCT(lock_context);
162
163         lock_context.device = name->st.st_dev;
164         lock_context.inode = name->st.st_ino;
165
166         *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
167         if (key->data == NULL) {
168                 return NT_STATUS_NO_MEMORY;
169         }
170         
171         return NT_STATUS_OK;
172 }
173
174
175 /*
176   open a directory
177 */
178 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, 
179                                     struct ntvfs_request *req, 
180                                     struct pvfs_filename *name, 
181                                     union smb_open *io)
182 {
183         struct pvfs_file *f;
184         struct ntvfs_handle *h;
185         NTSTATUS status;
186         uint32_t create_action;
187         uint32_t access_mask = io->generic.in.access_mask;
188         struct odb_lock *lck;
189         bool del_on_close;
190         uint32_t create_options;
191         uint32_t share_access;
192
193         create_options = io->generic.in.create_options;
194         share_access   = io->generic.in.share_access;
195
196         if (name->stream_name) {
197                 return NT_STATUS_NOT_A_DIRECTORY;
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         switch (io->generic.in.open_disposition) {
207         case NTCREATEX_DISP_OPEN_IF:
208                 break;
209
210         case NTCREATEX_DISP_OPEN:
211                 if (!name->exists) {
212                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
213                 }
214                 break;
215
216         case NTCREATEX_DISP_CREATE:
217                 if (name->exists) {
218                         return NT_STATUS_OBJECT_NAME_COLLISION;
219                 }
220                 break;
221
222         case NTCREATEX_DISP_OVERWRITE_IF:
223         case NTCREATEX_DISP_OVERWRITE:
224         case NTCREATEX_DISP_SUPERSEDE:
225         default:
226                 return NT_STATUS_INVALID_PARAMETER;
227         }
228
229         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
230         NT_STATUS_NOT_OK_RETURN(status);
231
232         f = talloc(h, struct pvfs_file);
233         if (f == NULL) {
234                 return NT_STATUS_NO_MEMORY;
235         }
236
237         f->handle = talloc(f, struct pvfs_file_handle);
238         if (f->handle == NULL) {
239                 return NT_STATUS_NO_MEMORY;
240         }
241
242         if (name->exists) {
243                 /* check the security descriptor */
244                 status = pvfs_access_check(pvfs, req, name, &access_mask);
245         } else {
246                 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
247         }
248         if (!NT_STATUS_IS_OK(status)) {
249                 return status;
250         }
251
252         f->ntvfs         = h;
253         f->pvfs          = pvfs;
254         f->pending_list  = NULL;
255         f->lock_count    = 0;
256         f->share_access  = io->generic.in.share_access;
257         f->impersonation = io->generic.in.impersonation;
258         f->access_mask   = access_mask;
259         f->brl_handle    = NULL;
260         f->notify_buffer = NULL;
261         f->search        = NULL;
262
263         f->handle->pvfs              = pvfs;
264         f->handle->name              = talloc_steal(f->handle, name);
265         f->handle->fd                = -1;
266         f->handle->odb_locking_key   = data_blob(NULL, 0);
267         f->handle->create_options    = io->generic.in.create_options;
268         f->handle->seek_offset       = 0;
269         f->handle->position          = 0;
270         f->handle->mode              = 0;
271         f->handle->sticky_write_time = false;
272         f->handle->open_completed    = false;
273
274         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
275             pvfs_directory_empty(pvfs, f->handle->name)) {
276                 del_on_close = true;
277         } else {
278                 del_on_close = false;
279         }
280
281         if (name->exists) {
282                 /* form the lock context used for opendb locking */
283                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
284                 if (!NT_STATUS_IS_OK(status)) {
285                         return status;
286                 }
287
288                 /* get a lock on this file before the actual open */
289                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
290                 if (lck == NULL) {
291                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
292                                  name->full_name));
293                         /* we were supposed to do a blocking lock, so something
294                            is badly wrong! */
295                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
296                 }
297                 
298                 /* see if we are allowed to open at the same time as existing opens */
299                 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
300                                        share_access, access_mask, del_on_close, 
301                                        io->generic.in.open_disposition,
302                                        false, OPLOCK_NONE, NULL);
303
304                 if (!NT_STATUS_IS_OK(status)) {
305                         talloc_free(lck);
306                         return status;
307                 }
308
309                 f->handle->have_opendb_entry = true;
310         }
311
312         DLIST_ADD(pvfs->files.list, f);
313
314         /* setup destructors to avoid leaks on abnormal termination */
315         talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
316         talloc_set_destructor(f, pvfs_dir_fnum_destructor);
317
318         if (!name->exists) {
319                 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
320                 mode_t mode = pvfs_fileperms(pvfs, attrib);
321
322                 if (mkdir(name->full_name, mode) == -1) {
323                         return pvfs_map_errno(pvfs,errno);
324                 }
325
326                 pvfs_xattr_unlink_hook(pvfs, name->full_name);
327
328                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
329                 if (!NT_STATUS_IS_OK(status)) {
330                         goto cleanup_delete;
331                 }
332
333                 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
334                 if (!NT_STATUS_IS_OK(status)) {
335                         goto cleanup_delete;
336                 }
337
338                 /* form the lock context used for opendb locking */
339                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
340                 if (!NT_STATUS_IS_OK(status)) {
341                         return status;
342                 }
343
344                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
345                 if (lck == NULL) {
346                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
347                                  name->full_name));
348                         /* we were supposed to do a blocking lock, so something
349                            is badly wrong! */
350                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
351                 }
352
353                 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
354                                        share_access, access_mask, del_on_close, 
355                                        io->generic.in.open_disposition,
356                                        false, OPLOCK_NONE, NULL);
357
358                 if (!NT_STATUS_IS_OK(status)) {
359                         goto cleanup_delete;
360                 }
361
362                 f->handle->have_opendb_entry = true;
363
364                 create_action = NTCREATEX_ACTION_CREATED;
365
366                 notify_trigger(pvfs->notify_context, 
367                                NOTIFY_ACTION_ADDED, 
368                                FILE_NOTIFY_CHANGE_DIR_NAME,
369                                name->full_name);
370         } else {
371                 create_action = NTCREATEX_ACTION_EXISTED;
372         }
373
374         if (!name->exists) {
375                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
376         }
377
378         /* the open succeeded, keep this handle permanently */
379         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
380         if (!NT_STATUS_IS_OK(status)) {
381                 goto cleanup_delete;
382         }
383
384         f->handle->open_completed = true;
385
386         io->generic.out.oplock_level  = OPLOCK_NONE;
387         io->generic.out.file.ntvfs    = h;
388         io->generic.out.create_action = create_action;
389         io->generic.out.create_time   = name->dos.create_time;
390         io->generic.out.access_time   = name->dos.access_time;
391         io->generic.out.write_time    = name->dos.write_time;
392         io->generic.out.change_time   = name->dos.change_time;
393         io->generic.out.attrib        = name->dos.attrib;
394         io->generic.out.alloc_size    = name->dos.alloc_size;
395         io->generic.out.size          = name->st.st_size;
396         io->generic.out.file_type     = FILE_TYPE_DISK;
397         io->generic.out.ipc_state     = 0;
398         io->generic.out.is_directory  = 1;
399
400         return NT_STATUS_OK;
401
402 cleanup_delete:
403         rmdir(name->full_name);
404         return status;
405 }
406
407 /*
408   destroy a struct pvfs_file_handle
409 */
410 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
411 {
412         int open_count;
413         char *path = NULL;
414
415         /* the write time is no longer sticky */
416         if (h->sticky_write_time) {
417                 NTSTATUS status;
418                 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
419                 if (NT_STATUS_IS_OK(status)) {
420                         h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
421                         pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
422                 }
423         }
424         
425         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
426             h->name->stream_name) {
427                 NTSTATUS status;
428                 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
429                 if (!NT_STATUS_IS_OK(status)) {
430                         DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
431                                  h->name->stream_name, h->name->full_name));
432                 }
433         }
434
435         if (h->fd != -1) {
436                 if (close(h->fd) != 0) {
437                         DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
438                                  h->fd, h->name->full_name, strerror(errno)));
439                 }
440                 h->fd = -1;
441         }
442
443         if (h->name->stream_name == NULL && 
444             h->open_completed &&
445             pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
446             open_count == 1) {
447                 NTSTATUS status;
448                 status = pvfs_xattr_unlink_hook(h->pvfs, path);
449                 if (!NT_STATUS_IS_OK(status)) {
450                         DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
451                                  path, nt_errstr(status)));
452                 }
453                 if (unlink(path) != 0) {
454                         DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", 
455                                  path, strerror(errno)));
456                 } else {
457                         notify_trigger(h->pvfs->notify_context, 
458                                        NOTIFY_ACTION_REMOVED, 
459                                        FILE_NOTIFY_CHANGE_FILE_NAME,
460                                        path);
461                 }
462         }
463
464         talloc_free(path);
465
466         if (h->have_opendb_entry) {
467                 struct odb_lock *lck;
468                 NTSTATUS status;
469
470                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
471                 if (lck == NULL) {
472                         DEBUG(0,("Unable to lock opendb for close\n"));
473                         return 0;
474                 }
475
476                 status = odb_close_file(lck, h);
477                 if (!NT_STATUS_IS_OK(status)) {
478                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
479                                  h->name->full_name, nt_errstr(status)));
480                 }
481
482                 talloc_free(lck);
483         }
484
485         return 0;
486 }
487
488
489 /*
490   destroy a struct pvfs_file
491 */
492 static int pvfs_fnum_destructor(struct pvfs_file *f)
493 {
494         DLIST_REMOVE(f->pvfs->files.list, f);
495         pvfs_lock_close(f->pvfs, f);
496         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
497
498         return 0;
499 }
500
501
502 /*
503   form the lock context used for byte range locking. This is separate
504   from the locking key used for opendb locking as it needs to take
505   account of file streams (each stream is a separate byte range
506   locking space)
507 */
508 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
509                                         struct pvfs_filename *name,
510                                         struct ntvfs_handle *ntvfs,
511                                         struct brl_handle **_h)
512 {
513         DATA_BLOB odb_key, key;
514         NTSTATUS status;
515         struct brl_handle *h;
516
517         status = pvfs_locking_key(name, mem_ctx, &odb_key);
518         NT_STATUS_NOT_OK_RETURN(status);
519
520         if (name->stream_name == NULL) {
521                 key = odb_key;
522         } else {
523                 key = data_blob_talloc(mem_ctx, NULL, 
524                                        odb_key.length + strlen(name->stream_name) + 1);
525                 NT_STATUS_HAVE_NO_MEMORY(key.data);
526                 memcpy(key.data, odb_key.data, odb_key.length);
527                 memcpy(key.data + odb_key.length, 
528                        name->stream_name, strlen(name->stream_name) + 1);
529                 data_blob_free(&odb_key);
530         }
531
532         h = brl_create_handle(mem_ctx, ntvfs, &key);
533         NT_STATUS_HAVE_NO_MEMORY(h);
534
535         *_h = h;
536         return NT_STATUS_OK;
537 }
538
539 /*
540   create a new file
541 */
542 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 
543                                  struct ntvfs_request *req, 
544                                  struct pvfs_filename *name, 
545                                  union smb_open *io)
546 {
547         struct pvfs_file *f;
548         NTSTATUS status;
549         struct ntvfs_handle *h;
550         int flags, fd;
551         struct odb_lock *lck;
552         uint32_t create_options = io->generic.in.create_options;
553         uint32_t share_access = io->generic.in.share_access;
554         uint32_t access_mask = io->generic.in.access_mask;
555         mode_t mode;
556         uint32_t attrib;
557         bool del_on_close;
558         struct pvfs_filename *parent;
559         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
560
561         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
562             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
563                 return NT_STATUS_CANNOT_DELETE;
564         }
565         
566         status = pvfs_access_check_create(pvfs, req, name, &access_mask);
567         NT_STATUS_NOT_OK_RETURN(status);
568
569         /* check that the parent isn't opened with delete on close set */
570         status = pvfs_resolve_parent(pvfs, req, name, &parent);
571         if (NT_STATUS_IS_OK(status)) {
572                 DATA_BLOB locking_key;
573                 status = pvfs_locking_key(parent, req, &locking_key);
574                 NT_STATUS_NOT_OK_RETURN(status);
575                 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, 
576                                                  &del_on_close, NULL, NULL);
577                 NT_STATUS_NOT_OK_RETURN(status);
578                 if (del_on_close) {
579                         return NT_STATUS_DELETE_PENDING;
580                 }
581         }
582
583         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
584                 flags = O_RDWR;
585         } else {
586                 flags = O_RDONLY;
587         }
588
589         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
590         NT_STATUS_NOT_OK_RETURN(status);
591
592         f = talloc(h, struct pvfs_file);
593         NT_STATUS_HAVE_NO_MEMORY(f);
594
595         f->handle = talloc(f, struct pvfs_file_handle);
596         NT_STATUS_HAVE_NO_MEMORY(f->handle);
597
598         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
599         mode = pvfs_fileperms(pvfs, attrib);
600
601         /* create the file */
602         fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
603         if (fd == -1) {
604                 return pvfs_map_errno(pvfs, errno);
605         }
606
607         pvfs_xattr_unlink_hook(pvfs, name->full_name);
608
609         /* if this was a stream create then create the stream as well */
610         if (name->stream_name) {
611                 status = pvfs_stream_create(pvfs, name, fd);
612                 if (!NT_STATUS_IS_OK(status)) {
613                         close(fd);
614                         return status;
615                 }
616         }
617
618         /* re-resolve the open fd */
619         status = pvfs_resolve_name_fd(pvfs, fd, name);
620         if (!NT_STATUS_IS_OK(status)) {
621                 close(fd);
622                 return status;
623         }
624
625         name->dos.attrib = attrib;
626         status = pvfs_dosattrib_save(pvfs, name, fd);
627         if (!NT_STATUS_IS_OK(status)) {
628                 goto cleanup_delete;
629         }
630
631
632         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
633         if (!NT_STATUS_IS_OK(status)) {
634                 goto cleanup_delete;
635         }
636
637         /* form the lock context used for byte range locking and
638            opendb locking */
639         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
640         if (!NT_STATUS_IS_OK(status)) {
641                 goto cleanup_delete;
642         }
643
644         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
645         if (!NT_STATUS_IS_OK(status)) {
646                 goto cleanup_delete;
647         }
648
649         /* grab a lock on the open file record */
650         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
651         if (lck == NULL) {
652                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
653                          name->full_name));
654                 /* we were supposed to do a blocking lock, so something
655                    is badly wrong! */
656                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
657                 goto cleanup_delete;
658         }
659
660         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
661                 del_on_close = true;
662         } else {
663                 del_on_close = false;
664         }
665
666         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
667                 oplock_level = OPLOCK_NONE;
668         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
669                 oplock_level = OPLOCK_BATCH;
670         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
671                 oplock_level = OPLOCK_EXCLUSIVE;
672         }
673
674         status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
675                                share_access, access_mask, del_on_close, 
676                                io->generic.in.open_disposition,
677                                false, oplock_level, &oplock_granted);
678         talloc_free(lck);
679         if (!NT_STATUS_IS_OK(status)) {
680                 /* bad news, we must have hit a race - we don't delete the file
681                    here as the most likely scenario is that someone else created 
682                    the file at the same time */
683                 close(fd);
684                 return status;
685         }
686
687         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
688                 oplock_granted = OPLOCK_BATCH;
689         }
690
691         f->ntvfs             = h;
692         f->pvfs              = pvfs;
693         f->pending_list      = NULL;
694         f->lock_count        = 0;
695         f->share_access      = io->generic.in.share_access;
696         f->access_mask       = access_mask;
697         f->impersonation     = io->generic.in.impersonation;
698         f->notify_buffer     = NULL;
699         f->search            = NULL;
700
701         f->handle->pvfs              = pvfs;
702         f->handle->name              = talloc_steal(f->handle, name);
703         f->handle->fd                = fd;
704         f->handle->create_options    = io->generic.in.create_options;
705         f->handle->seek_offset       = 0;
706         f->handle->position          = 0;
707         f->handle->mode              = 0;
708         f->handle->have_opendb_entry = true;
709         f->handle->sticky_write_time = false;
710         f->handle->open_completed    = false;
711
712         DLIST_ADD(pvfs->files.list, f);
713
714         /* setup a destructor to avoid file descriptor leaks on
715            abnormal termination */
716         talloc_set_destructor(f, pvfs_fnum_destructor);
717         talloc_set_destructor(f->handle, pvfs_handle_destructor);
718
719         io->generic.out.oplock_level  = oplock_granted;
720         io->generic.out.file.ntvfs    = f->ntvfs;
721         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
722         io->generic.out.create_time   = name->dos.create_time;
723         io->generic.out.access_time   = name->dos.access_time;
724         io->generic.out.write_time    = name->dos.write_time;
725         io->generic.out.change_time   = name->dos.change_time;
726         io->generic.out.attrib        = name->dos.attrib;
727         io->generic.out.alloc_size    = name->dos.alloc_size;
728         io->generic.out.size          = name->st.st_size;
729         io->generic.out.file_type     = FILE_TYPE_DISK;
730         io->generic.out.ipc_state     = 0;
731         io->generic.out.is_directory  = 0;
732
733         /* success - keep the file handle */
734         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
735         if (!NT_STATUS_IS_OK(status)) {
736                 goto cleanup_delete;
737         }
738
739         f->handle->open_completed = true;
740
741         notify_trigger(pvfs->notify_context, 
742                        NOTIFY_ACTION_ADDED, 
743                        FILE_NOTIFY_CHANGE_FILE_NAME,
744                        name->full_name);
745
746         return NT_STATUS_OK;
747
748 cleanup_delete:
749         close(fd);
750         unlink(name->full_name);
751         return status;
752 }
753
754
755 /*
756   state of a pending open retry
757 */
758 struct pvfs_open_retry {
759         struct ntvfs_module_context *ntvfs;
760         struct ntvfs_request *req;
761         union smb_open *io;
762         struct pvfs_wait *wait_handle;
763         DATA_BLOB odb_locking_key;
764 };
765
766 /* destroy a pending open request */
767 static int pvfs_retry_destructor(struct pvfs_open_retry *r)
768 {
769         struct pvfs_state *pvfs = r->ntvfs->private_data;
770         if (r->odb_locking_key.data) {
771                 struct odb_lock *lck;
772                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
773                 if (lck != NULL) {
774                         odb_remove_pending(lck, r);
775                 }
776                 talloc_free(lck);
777         }
778         return 0;
779 }
780
781 /*
782   retry an open
783 */
784 static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
785 {
786         struct pvfs_open_retry *r = private;
787         struct ntvfs_module_context *ntvfs = r->ntvfs;
788         struct ntvfs_request *req = r->req;
789         union smb_open *io = r->io;
790         NTSTATUS status;
791
792         /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
793            just a bug in their server, but we better do the same */
794         if (reason == PVFS_WAIT_CANCEL) {
795                 return;
796         }
797
798         talloc_free(r->wait_handle);
799
800         if (reason == PVFS_WAIT_TIMEOUT) {
801                 /* if it timed out, then give the failure
802                    immediately */
803                 talloc_free(r);
804                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
805                 req->async_states->send_fn(req);
806                 return;
807         }
808
809         /* the pending odb entry is already removed. We use a null locking
810            key to indicate this */
811         data_blob_free(&r->odb_locking_key);
812         talloc_free(r);
813
814         /* try the open again, which could trigger another retry setup
815            if it wants to, so we have to unmark the async flag so we
816            will know if it does a second async reply */
817         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
818
819         status = pvfs_open(ntvfs, req, io);
820         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
821                 /* the 2nd try also replied async, so we don't send
822                    the reply yet */
823                 return;
824         }
825
826         /* re-mark it async, just in case someone up the chain does
827            paranoid checking */
828         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
829
830         /* send the reply up the chain */
831         req->async_states->status = status;
832         req->async_states->send_fn(req);
833 }
834
835
836 /*
837   special handling for openx DENY_DOS semantics
838
839   This function attempts a reference open using an existing handle. If its allowed,
840   then it returns NT_STATUS_OK, otherwise it returns any other code and normal
841   open processing continues.
842 */
843 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
844                                    struct ntvfs_request *req, union smb_open *io,
845                                    struct pvfs_file *f, struct odb_lock *lck)
846 {
847         struct pvfs_state *pvfs = ntvfs->private_data;
848         struct pvfs_file *f2;
849         struct pvfs_filename *name;
850         NTSTATUS status;
851
852         /* search for an existing open with the right parameters. Note
853            the magic ntcreatex options flag, which is set in the
854            generic mapping code. This might look ugly, but its
855            actually pretty much now w2k does it internally as well. 
856            
857            If you look at the BASE-DENYDOS test you will see that a
858            DENY_DOS is a very special case, and in the right
859            circumstances you actually get the _same_ handle back
860            twice, rather than a new handle.
861         */
862         for (f2=pvfs->files.list;f2;f2=f2->next) {
863                 if (f2 != f &&
864                     f2->ntvfs->session_info == req->session_info &&
865                     f2->ntvfs->smbpid == req->smbpid &&
866                     (f2->handle->create_options & 
867                      (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
868                       NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
869                     (f2->access_mask & SEC_FILE_WRITE_DATA) &&
870                     strcasecmp_m(f2->handle->name->original_name, 
871                                io->generic.in.fname)==0) {
872                         break;
873                 }
874         }
875
876         if (!f2) {
877                 return NT_STATUS_SHARING_VIOLATION;
878         }
879
880         /* quite an insane set of semantics ... */
881         if (is_exe_filename(io->generic.in.fname) &&
882             (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
883                 return NT_STATUS_SHARING_VIOLATION;
884         }
885
886         /*
887           setup a reference to the existing handle
888          */
889         talloc_free(f->handle);
890         f->handle = talloc_reference(f, f2->handle);
891
892         talloc_free(lck);
893
894         name = f->handle->name;
895
896         io->generic.out.oplock_level  = OPLOCK_NONE;
897         io->generic.out.file.ntvfs    = f->ntvfs;
898         io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
899         io->generic.out.create_time   = name->dos.create_time;
900         io->generic.out.access_time   = name->dos.access_time;
901         io->generic.out.write_time    = name->dos.write_time;
902         io->generic.out.change_time   = name->dos.change_time;
903         io->generic.out.attrib        = name->dos.attrib;
904         io->generic.out.alloc_size    = name->dos.alloc_size;
905         io->generic.out.size          = name->st.st_size;
906         io->generic.out.file_type     = FILE_TYPE_DISK;
907         io->generic.out.ipc_state     = 0;
908         io->generic.out.is_directory  = 0;
909  
910         status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
911         NT_STATUS_NOT_OK_RETURN(status);
912
913         return NT_STATUS_OK;
914 }
915
916
917
918 /*
919   setup for a open retry after a sharing violation
920 */
921 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
922                                       struct ntvfs_request *req, 
923                                       union smb_open *io,
924                                       struct pvfs_file *f,
925                                       struct odb_lock *lck)
926 {
927         struct pvfs_state *pvfs = ntvfs->private_data;
928         struct pvfs_open_retry *r;
929         NTSTATUS status;
930         struct timeval end_time;
931
932         if (io->generic.in.create_options & 
933             (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
934                 /* see if we can satisfy the request using the special DENY_DOS
935                    code */
936                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
937                 if (NT_STATUS_IS_OK(status)) {
938                         return status;
939                 }
940         }
941
942         r = talloc(req, struct pvfs_open_retry);
943         if (r == NULL) {
944                 return NT_STATUS_NO_MEMORY;
945         }
946
947         r->ntvfs = ntvfs;
948         r->req = req;
949         r->io = io;
950         r->odb_locking_key = data_blob_talloc(r, 
951                                               f->handle->odb_locking_key.data, 
952                                               f->handle->odb_locking_key.length);
953
954         end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
955
956         /* setup a pending lock */
957         status = odb_open_file_pending(lck, r);
958         if (!NT_STATUS_IS_OK(status)) {
959                 return status;
960         }
961
962         talloc_free(lck);
963         talloc_free(f);
964
965         talloc_set_destructor(r, pvfs_retry_destructor);
966
967         r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, end_time, 
968                                            pvfs_open_retry, r);
969         if (r->wait_handle == NULL) {
970                 return NT_STATUS_NO_MEMORY;
971         }
972
973         talloc_steal(pvfs, r);
974
975         return NT_STATUS_OK;
976 }
977
978 /*
979   open a file
980 */
981 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
982                    struct ntvfs_request *req, union smb_open *io)
983 {
984         struct pvfs_state *pvfs = ntvfs->private_data;
985         int flags;
986         struct pvfs_filename *name;
987         struct pvfs_file *f;
988         struct ntvfs_handle *h;
989         NTSTATUS status;
990         int fd;
991         struct odb_lock *lck;
992         uint32_t create_options;
993         uint32_t share_access;
994         uint32_t access_mask;
995         bool del_on_close;
996         bool stream_existed, stream_truncate=false;
997         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
998
999         /* use the generic mapping code to avoid implementing all the
1000            different open calls. */
1001         if (io->generic.level != RAW_OPEN_GENERIC &&
1002             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1003                 return ntvfs_map_open(ntvfs, req, io);
1004         }
1005
1006         /* resolve the cifs name to a posix name */
1007         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
1008                                    PVFS_RESOLVE_STREAMS, &name);
1009         if (!NT_STATUS_IS_OK(status)) {
1010                 return status;
1011         }
1012
1013         /* directory opens are handled separately */
1014         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1015             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1016                 return pvfs_open_directory(pvfs, req, name, io);
1017         }
1018
1019         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1020            open doesn't match */
1021         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1022
1023         create_options = io->generic.in.create_options;
1024         share_access   = io->generic.in.share_access;
1025         access_mask    = io->generic.in.access_mask;
1026
1027         /* certain create options are not allowed */
1028         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1029             !(access_mask & SEC_STD_DELETE)) {
1030                 return NT_STATUS_INVALID_PARAMETER;
1031         }
1032
1033         flags = 0;
1034
1035         switch (io->generic.in.open_disposition) {
1036         case NTCREATEX_DISP_SUPERSEDE:
1037         case NTCREATEX_DISP_OVERWRITE_IF:
1038                 if (name->stream_name == NULL) {
1039                         flags = O_TRUNC;
1040                 } else {
1041                         stream_truncate = true;
1042                 }
1043                 break;
1044
1045         case NTCREATEX_DISP_OPEN:
1046                 if (!name->stream_exists) {
1047                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1048                 }
1049                 flags = 0;
1050                 break;
1051
1052         case NTCREATEX_DISP_OVERWRITE:
1053                 if (!name->stream_exists) {
1054                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1055                 }
1056                 if (name->stream_name == NULL) {
1057                         flags = O_TRUNC;
1058                 } else {
1059                         stream_truncate = true;
1060                 }
1061                 break;
1062
1063         case NTCREATEX_DISP_CREATE:
1064                 if (name->stream_exists) {
1065                         return NT_STATUS_OBJECT_NAME_COLLISION;
1066                 }
1067                 flags = 0;
1068                 break;
1069
1070         case NTCREATEX_DISP_OPEN_IF:
1071                 flags = 0;
1072                 break;
1073
1074         default:
1075                 return NT_STATUS_INVALID_PARAMETER;
1076         }
1077
1078         /* handle creating a new file separately */
1079         if (!name->exists) {
1080                 status = pvfs_create_file(pvfs, req, name, io);
1081                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1082                         return status;
1083                 }
1084
1085                 /* we've hit a race - the file was created during this call */
1086                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1087                         return status;
1088                 }
1089
1090                 /* try re-resolving the name */
1091                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1092                 if (!NT_STATUS_IS_OK(status)) {
1093                         return status;
1094                 }
1095                 /* fall through to a normal open */
1096         }
1097
1098         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1099             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1100                 return NT_STATUS_CANNOT_DELETE;
1101         }
1102
1103         /* check the security descriptor */
1104         status = pvfs_access_check(pvfs, req, name, &access_mask);
1105         if (!NT_STATUS_IS_OK(status)) {
1106                 return status;
1107         }
1108
1109         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1110         NT_STATUS_NOT_OK_RETURN(status);
1111
1112         f = talloc(h, struct pvfs_file);
1113         if (f == NULL) {
1114                 return NT_STATUS_NO_MEMORY;
1115         }
1116
1117         f->handle = talloc(f, struct pvfs_file_handle);
1118         if (f->handle == NULL) {
1119                 return NT_STATUS_NO_MEMORY;
1120         }
1121
1122         f->ntvfs         = h;
1123         f->pvfs          = pvfs;
1124         f->pending_list  = NULL;
1125         f->lock_count    = 0;
1126         f->share_access  = io->generic.in.share_access;
1127         f->access_mask   = access_mask;
1128         f->impersonation = io->generic.in.impersonation;
1129         f->notify_buffer = NULL;
1130         f->search        = NULL;
1131
1132         f->handle->pvfs              = pvfs;
1133         f->handle->fd                = -1;
1134         f->handle->name              = talloc_steal(f->handle, name);
1135         f->handle->create_options    = io->generic.in.create_options;
1136         f->handle->seek_offset       = 0;
1137         f->handle->position          = 0;
1138         f->handle->mode              = 0;
1139         f->handle->have_opendb_entry = false;
1140         f->handle->sticky_write_time = false;
1141         f->handle->open_completed    = false;
1142
1143         /* form the lock context used for byte range locking and
1144            opendb locking */
1145         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1146         if (!NT_STATUS_IS_OK(status)) {
1147                 return status;
1148         }
1149
1150         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1151         if (!NT_STATUS_IS_OK(status)) {
1152                 return status;
1153         }
1154
1155         /* get a lock on this file before the actual open */
1156         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1157         if (lck == NULL) {
1158                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1159                          name->full_name));
1160                 /* we were supposed to do a blocking lock, so something
1161                    is badly wrong! */
1162                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1163         }
1164
1165         DLIST_ADD(pvfs->files.list, f);
1166
1167         /* setup a destructor to avoid file descriptor leaks on
1168            abnormal termination */
1169         talloc_set_destructor(f, pvfs_fnum_destructor);
1170         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1171
1172         /* 
1173          * Only SMB2 takes care of the delete_on_close,
1174          * on existing files
1175          */
1176         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1177             req->ctx->protocol == PROTOCOL_SMB2) {
1178                 del_on_close = true;
1179         } else {
1180                 del_on_close = false;
1181         }
1182
1183         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1184                 oplock_level = OPLOCK_NONE;
1185         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1186                 oplock_level = OPLOCK_BATCH;
1187         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1188                 oplock_level = OPLOCK_EXCLUSIVE;
1189         }
1190
1191         /* see if we are allowed to open at the same time as existing opens */
1192         status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1193                                share_access, access_mask, del_on_close,
1194                                io->generic.in.open_disposition,
1195                                false, oplock_level, &oplock_granted);
1196
1197         /* on a sharing violation we need to retry when the file is closed by 
1198            the other user, or after 1 second */
1199         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1200             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1201                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1202         }
1203
1204         if (!NT_STATUS_IS_OK(status)) {
1205                 talloc_free(lck);
1206                 return status;
1207         }
1208
1209         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1210                 oplock_granted = OPLOCK_BATCH;
1211         }
1212
1213         f->handle->have_opendb_entry = true;
1214
1215         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1216                 flags |= O_RDWR;
1217         } else {
1218                 flags |= O_RDONLY;
1219         }
1220
1221         /* do the actual open */
1222         fd = open(f->handle->name->full_name, flags);
1223         if (fd == -1) {
1224                 talloc_free(lck);
1225                 return pvfs_map_errno(f->pvfs, errno);
1226         }
1227
1228         f->handle->fd = fd;
1229
1230         stream_existed = name->stream_exists;
1231
1232         /* if this was a stream create then create the stream as well */
1233         if (!name->stream_exists) {
1234                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1235                 if (!NT_STATUS_IS_OK(status)) {
1236                         talloc_free(lck);
1237                         return status;
1238                 }
1239                 if (stream_truncate) {
1240                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1241                         if (!NT_STATUS_IS_OK(status)) {
1242                                 talloc_free(lck);
1243                                 return status;
1244                         }
1245                 }
1246         }
1247
1248         /* re-resolve the open fd */
1249         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1250         if (!NT_STATUS_IS_OK(status)) {
1251                 talloc_free(lck);
1252                 return status;
1253         }
1254
1255         if (f->handle->name->stream_id == 0 &&
1256             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1257              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1258                 /* for overwrite we need to replace file permissions */
1259                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1260                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1261                 if (fchmod(fd, mode) == -1) {
1262                         talloc_free(lck);
1263                         return pvfs_map_errno(pvfs, errno);
1264                 }
1265                 name->dos.attrib = attrib;
1266                 status = pvfs_dosattrib_save(pvfs, name, fd);
1267                 if (!NT_STATUS_IS_OK(status)) {
1268                         talloc_free(lck);
1269                         return status;
1270                 }
1271         }
1272             
1273         talloc_free(lck);
1274
1275         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1276         NT_STATUS_NOT_OK_RETURN(status);
1277
1278         /* mark the open as having completed fully, so delete on close
1279            can now be used */
1280         f->handle->open_completed     = true;
1281
1282         io->generic.out.oplock_level  = oplock_granted;
1283         io->generic.out.file.ntvfs    = h;
1284         io->generic.out.create_action = stream_existed?
1285                 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1286         io->generic.out.create_time   = name->dos.create_time;
1287         io->generic.out.access_time   = name->dos.access_time;
1288         io->generic.out.write_time    = name->dos.write_time;
1289         io->generic.out.change_time   = name->dos.change_time;
1290         io->generic.out.attrib        = name->dos.attrib;
1291         io->generic.out.alloc_size    = name->dos.alloc_size;
1292         io->generic.out.size          = name->st.st_size;
1293         io->generic.out.file_type     = FILE_TYPE_DISK;
1294         io->generic.out.ipc_state     = 0;
1295         io->generic.out.is_directory  = 0;
1296
1297         return NT_STATUS_OK;
1298 }
1299
1300
1301 /*
1302   close a file
1303 */
1304 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1305                     struct ntvfs_request *req, union smb_close *io)
1306 {
1307         struct pvfs_state *pvfs = ntvfs->private_data;
1308         struct pvfs_file *f;
1309         struct utimbuf unix_times;
1310
1311         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1312                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1313         }
1314
1315         if (io->generic.level != RAW_CLOSE_CLOSE) {
1316                 return ntvfs_map_close(ntvfs, req, io);
1317         }
1318
1319         f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1320         if (!f) {
1321                 return NT_STATUS_INVALID_HANDLE;
1322         }
1323
1324         if (!null_time(io->close.in.write_time)) {
1325                 unix_times.actime = 0;
1326                 unix_times.modtime = io->close.in.write_time;
1327                 utime(f->handle->name->full_name, &unix_times);
1328         } else if (f->handle->sticky_write_time) {
1329                 unix_times.actime = 0;
1330                 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1331                 utime(f->handle->name->full_name, &unix_times);
1332         }
1333
1334         talloc_free(f);
1335
1336         return NT_STATUS_OK;
1337 }
1338
1339
1340 /*
1341   logoff - close all file descriptors open by a vuid
1342 */
1343 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1344                      struct ntvfs_request *req)
1345 {
1346         struct pvfs_state *pvfs = ntvfs->private_data;
1347         struct pvfs_file *f, *next;
1348
1349         for (f=pvfs->files.list;f;f=next) {
1350                 next = f->next;
1351                 if (f->ntvfs->session_info == req->session_info) {
1352                         talloc_free(f);
1353                 }
1354         }
1355
1356         return NT_STATUS_OK;
1357 }
1358
1359
1360 /*
1361   exit - close files for the current pid
1362 */
1363 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1364                    struct ntvfs_request *req)
1365 {
1366         struct pvfs_state *pvfs = ntvfs->private_data;
1367         struct pvfs_file *f, *next;
1368
1369         for (f=pvfs->files.list;f;f=next) {
1370                 next = f->next;
1371                 if (f->ntvfs->session_info == req->session_info &&
1372                     f->ntvfs->smbpid == req->smbpid) {
1373                         talloc_free(f);
1374                 }
1375         }
1376
1377         return NT_STATUS_OK;
1378 }
1379
1380
1381 /*
1382   change the delete on close flag on an already open file
1383 */
1384 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1385                                   struct ntvfs_request *req, 
1386                                   struct pvfs_file *f, bool del_on_close)
1387 {
1388         struct odb_lock *lck;
1389         NTSTATUS status;
1390
1391         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1392                 return NT_STATUS_CANNOT_DELETE;
1393         }
1394         
1395         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1396             !pvfs_directory_empty(pvfs, f->handle->name)) {
1397                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1398         }
1399
1400         if (del_on_close) {
1401                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1402         } else {
1403                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1404         }
1405         
1406         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1407         if (lck == NULL) {
1408                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1409         }
1410
1411         status = odb_set_delete_on_close(lck, del_on_close);
1412
1413         talloc_free(lck);
1414
1415         return status;
1416 }
1417
1418
1419 /*
1420   determine if a file can be deleted, or if it is prevented by an
1421   already open file
1422 */
1423 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1424                          struct ntvfs_request *req,
1425                          struct pvfs_filename *name,
1426                          struct odb_lock **lckp)
1427 {
1428         NTSTATUS status;
1429         DATA_BLOB key;
1430         struct odb_lock *lck;
1431         uint32_t share_access;
1432         uint32_t access_mask;
1433         bool delete_on_close;
1434
1435         status = pvfs_locking_key(name, name, &key);
1436         if (!NT_STATUS_IS_OK(status)) {
1437                 return NT_STATUS_NO_MEMORY;
1438         }
1439
1440         lck = odb_lock(req, pvfs->odb_context, &key);
1441         if (lck == NULL) {
1442                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1443                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1444         }
1445
1446         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1447                           NTCREATEX_SHARE_ACCESS_WRITE |
1448                           NTCREATEX_SHARE_ACCESS_DELETE;
1449         access_mask     = SEC_STD_DELETE;
1450         delete_on_close = true;
1451
1452         status = odb_can_open(lck, name->stream_id,
1453                               share_access, access_mask, delete_on_close,
1454                               0, false);
1455
1456         if (NT_STATUS_IS_OK(status)) {
1457                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1458         }
1459
1460         /*
1461          * if it's a sharing violation or we got no oplock
1462          * only keep the lock if the caller requested access
1463          * to the lock
1464          */
1465         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1466             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1467                 if (lckp) {
1468                         *lckp = lck;
1469                 } else {
1470                         talloc_free(lck);
1471                 }
1472         } else if (!NT_STATUS_IS_OK(status)) {
1473                 talloc_free(lck);
1474                 if (lckp) {
1475                         *lckp = NULL;
1476                 }
1477         } else if (lckp) {
1478                 *lckp = lck;
1479         }
1480
1481         return status;
1482 }
1483
1484 /*
1485   determine if a file can be renamed, or if it is prevented by an
1486   already open file
1487 */
1488 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1489                          struct ntvfs_request *req,
1490                          struct pvfs_filename *name,
1491                          struct odb_lock **lckp)
1492 {
1493         NTSTATUS status;
1494         DATA_BLOB key;
1495         struct odb_lock *lck;
1496         uint32_t share_access;
1497         uint32_t access_mask;
1498         bool delete_on_close;
1499
1500         status = pvfs_locking_key(name, name, &key);
1501         if (!NT_STATUS_IS_OK(status)) {
1502                 return NT_STATUS_NO_MEMORY;
1503         }
1504
1505         lck = odb_lock(req, pvfs->odb_context, &key);
1506         if (lck == NULL) {
1507                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1508                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1509         }
1510
1511         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1512                           NTCREATEX_SHARE_ACCESS_WRITE;
1513         access_mask     = SEC_STD_DELETE;
1514         delete_on_close = false;
1515
1516         status = odb_can_open(lck, name->stream_id,
1517                               share_access, access_mask, delete_on_close,
1518                               0, false);
1519
1520         /*
1521          * if it's a sharing violation or we got no oplock
1522          * only keep the lock if the caller requested access
1523          * to the lock
1524          */
1525         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1526             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1527                 if (lckp) {
1528                         *lckp = lck;
1529                 } else {
1530                         talloc_free(lck);
1531                 }
1532         } else if (!NT_STATUS_IS_OK(status)) {
1533                 talloc_free(lck);
1534                 if (lckp) {
1535                         *lckp = NULL;
1536                 }
1537         } else if (lckp) {
1538                 *lckp = lck;
1539         }
1540
1541         return status;
1542 }
1543
1544 /*
1545   determine if file meta data can be accessed, or if it is prevented by an
1546   already open file
1547 */
1548 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1549                        struct ntvfs_request *req,
1550                        struct pvfs_filename *name)
1551 {
1552         NTSTATUS status;
1553         DATA_BLOB key;
1554         struct odb_lock *lck;
1555         uint32_t share_access;
1556         uint32_t access_mask;
1557         bool delete_on_close;
1558
1559         status = pvfs_locking_key(name, name, &key);
1560         if (!NT_STATUS_IS_OK(status)) {
1561                 return NT_STATUS_NO_MEMORY;
1562         }
1563
1564         lck = odb_lock(req, pvfs->odb_context, &key);
1565         if (lck == NULL) {
1566                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1567                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1568         }
1569
1570         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1571                           NTCREATEX_SHARE_ACCESS_WRITE;
1572         access_mask     = 0;
1573         delete_on_close = false;
1574
1575         status = odb_can_open(lck, name->stream_id,
1576                               share_access, access_mask, delete_on_close,
1577                               0, false);
1578
1579         if (!NT_STATUS_IS_OK(status)) {
1580                 talloc_free(lck);
1581         }
1582
1583         return status;
1584 }
1585
1586
1587 /*
1588   determine if delete on close is set on 
1589 */
1590 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h, 
1591                               int *open_count, char **path)
1592 {
1593         NTSTATUS status;
1594         bool del_on_close;
1595
1596         status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
1597                                          &del_on_close, open_count, path);
1598         if (!NT_STATUS_IS_OK(status)) {
1599                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1600                 return false;
1601         }
1602
1603         return del_on_close;
1604 }