b0d0348240dea550c577125ad6a38d5502ca5d7a
[kai/samba-autobuild/.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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "vfs_posix.h"
25 #include "system/dir.h"
26 #include "system/time.h"
27 #include "dlinklist.h"
28 #include "messaging/messaging.h"
29 #include "librpc/gen_ndr/xattr.h"
30
31 /*
32   find open file handle given fnum
33 */
34 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
35                                struct ntvfs_request *req, struct ntvfs_handle *h)
36 {
37         void *p;
38         struct pvfs_file *f;
39
40         p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
41         if (!p) return NULL;
42
43         f = talloc_get_type(p, struct pvfs_file);
44         if (!f) return NULL;
45
46         if (req->session_info != f->session_info) {
47                 DEBUG(2,("pvfs_find_fd: attempt to use wrong session for handle %p\n",h));
48                 return NULL;
49         }
50
51         return f;
52 }
53
54 /*
55   cleanup a open directory handle
56 */
57 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
58 {
59         int open_count;
60         char *path = NULL;
61
62         if (h->name->stream_name == NULL && 
63             pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
64             open_count == 1) {
65                 NTSTATUS status;
66                 status = pvfs_xattr_unlink_hook(h->pvfs, path);
67                 if (!NT_STATUS_IS_OK(status)) {
68                         DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
69                                  path, nt_errstr(status)));
70                 }
71                 if (rmdir(path) != 0) {
72                         DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", 
73                                  path, strerror(errno)));
74                 }
75         }
76
77         talloc_free(path);
78
79         if (h->have_opendb_entry) {
80                 struct odb_lock *lck;
81                 NTSTATUS status;
82
83                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
84                 if (lck == NULL) {
85                         DEBUG(0,("Unable to lock opendb for close\n"));
86                         return 0;
87                 }
88
89                 status = odb_close_file(lck, h);
90                 if (!NT_STATUS_IS_OK(status)) {
91                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
92                                  h->name->full_name, nt_errstr(status)));
93                 }
94
95                 talloc_free(lck);
96         }
97
98         return 0;
99 }
100
101 /*
102   cleanup a open directory fnum
103 */
104 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
105 {
106         DLIST_REMOVE(f->pvfs->files.list, f);
107         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
108
109         return 0;
110 }
111
112 /*
113   setup any EAs and the ACL on newly created files/directories
114 */
115 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
116                                         struct ntvfs_request *req,
117                                         struct pvfs_filename *name,
118                                         int fd, struct pvfs_file *f,
119                                         union smb_open *io)
120 {
121         NTSTATUS status;
122
123         /* setup any EAs that were asked for */
124         if (io->ntcreatex.in.ea_list) {
125                 status = pvfs_setfileinfo_ea_set(pvfs, name, fd, 
126                                                  io->ntcreatex.in.ea_list->num_eas,
127                                                  io->ntcreatex.in.ea_list->eas);
128                 if (!NT_STATUS_IS_OK(status)) {
129                         return status;
130                 }
131         }
132
133         /* setup an initial sec_desc if requested */
134         if (io->ntcreatex.in.sec_desc) {
135                 union smb_setfileinfo set;
136 /* 
137  * TODO: set the full ACL! 
138  *       - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
139  *         when a SACL is present on the sd,
140  *         but the user doesn't have SeSecurityPrivilege
141  *       - w2k3 allows it
142  */
143                 set.set_secdesc.in.file.ntvfs = f->ntvfs;
144                 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
145                 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
146
147                 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
148         } else {
149                 /* otherwise setup an inherited acl from the parent */
150                 status = pvfs_acl_inherit(pvfs, req, name, fd);
151         }
152
153         return status;
154 }
155
156 /*
157   form the lock context used for opendb locking. Note that we must
158   zero here to take account of possible padding on some architectures
159 */
160 static NTSTATUS pvfs_locking_key(struct pvfs_filename *name, 
161                                  TALLOC_CTX *mem_ctx, DATA_BLOB *key)
162 {
163         struct {
164                 dev_t device;
165                 ino_t inode;
166         } lock_context;
167         ZERO_STRUCT(lock_context);
168
169         lock_context.device = name->st.st_dev;
170         lock_context.inode = name->st.st_ino;
171
172         *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
173         if (key->data == NULL) {
174                 return NT_STATUS_NO_MEMORY;
175         }
176         
177         return NT_STATUS_OK;
178 }
179
180
181 /*
182   open a directory
183 */
184 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, 
185                                     struct ntvfs_request *req, 
186                                     struct pvfs_filename *name, 
187                                     union smb_open *io)
188 {
189         struct pvfs_file *f;
190         struct ntvfs_handle *h;
191         NTSTATUS status;
192         uint32_t create_action;
193         uint32_t access_mask = io->generic.in.access_mask;
194         struct odb_lock *lck;
195         BOOL del_on_close;
196         uint32_t create_options;
197         uint32_t share_access;
198
199         create_options = io->generic.in.create_options;
200         share_access   = io->generic.in.share_access;
201
202         if (name->stream_name) {
203                 return NT_STATUS_NOT_A_DIRECTORY;
204         }
205
206         /* if the client says it must be a directory, and it isn't,
207            then fail */
208         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
209                 return NT_STATUS_NOT_A_DIRECTORY;
210         }
211
212         switch (io->generic.in.open_disposition) {
213         case NTCREATEX_DISP_OPEN_IF:
214                 break;
215
216         case NTCREATEX_DISP_OPEN:
217                 if (!name->exists) {
218                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
219                 }
220                 break;
221
222         case NTCREATEX_DISP_CREATE:
223                 if (name->exists) {
224                         return NT_STATUS_OBJECT_NAME_COLLISION;
225                 }
226                 break;
227
228         case NTCREATEX_DISP_OVERWRITE_IF:
229         case NTCREATEX_DISP_OVERWRITE:
230         case NTCREATEX_DISP_SUPERSEDE:
231         default:
232                 return NT_STATUS_INVALID_PARAMETER;
233         }
234
235         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
236         NT_STATUS_NOT_OK_RETURN(status);
237
238         f = talloc(h, struct pvfs_file);
239         if (f == NULL) {
240                 return NT_STATUS_NO_MEMORY;
241         }
242
243         f->handle = talloc(f, struct pvfs_file_handle);
244         if (f->handle == NULL) {
245                 return NT_STATUS_NO_MEMORY;
246         }
247
248         if (name->exists) {
249                 /* check the security descriptor */
250                 status = pvfs_access_check(pvfs, req, name, &access_mask);
251         } else {
252                 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
253         }
254         if (!NT_STATUS_IS_OK(status)) {
255                 return status;
256         }
257
258         f->ntvfs         = h;
259         f->session_info  = req->session_info;
260         f->smbpid        = req->smbpid;
261         f->pvfs          = pvfs;
262         f->pending_list  = NULL;
263         f->lock_count    = 0;
264         f->share_access  = io->generic.in.share_access;
265         f->impersonation = io->generic.in.impersonation;
266         f->access_mask   = access_mask;
267         f->brl_handle    = NULL;
268         f->notify_buffer = NULL;
269         f->search        = NULL;
270
271         f->handle->pvfs              = pvfs;
272         f->handle->name              = talloc_steal(f->handle, name);
273         f->handle->fd                = -1;
274         f->handle->odb_locking_key   = data_blob(NULL, 0);
275         f->handle->create_options    = io->generic.in.create_options;
276         f->handle->seek_offset       = 0;
277         f->handle->position          = 0;
278         f->handle->mode              = 0;
279         f->handle->sticky_write_time = False;
280
281         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
282             pvfs_directory_empty(pvfs, f->handle->name)) {
283                 del_on_close = True;
284         } else {
285                 del_on_close = False;
286         }
287
288         if (name->exists) {
289                 /* form the lock context used for opendb locking */
290                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
291                 if (!NT_STATUS_IS_OK(status)) {
292                         return status;
293                 }
294
295                 /* get a lock on this file before the actual open */
296                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
297                 if (lck == NULL) {
298                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
299                                  name->full_name));
300                         /* we were supposed to do a blocking lock, so something
301                            is badly wrong! */
302                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
303                 }
304                 
305                 /* see if we are allowed to open at the same time as existing opens */
306                 status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
307                                        share_access, access_mask, del_on_close, 
308                                        name->full_name, OPLOCK_NONE, NULL);
309
310                 if (!NT_STATUS_IS_OK(status)) {
311                         talloc_free(lck);
312                         return status;
313                 }
314
315                 f->handle->have_opendb_entry = True;
316         }
317
318         DLIST_ADD(pvfs->files.list, f);
319
320         /* setup destructors to avoid leaks on abnormal termination */
321         talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
322         talloc_set_destructor(f, pvfs_dir_fnum_destructor);
323
324         if (!name->exists) {
325                 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
326                 mode_t mode = pvfs_fileperms(pvfs, attrib);
327
328                 if (mkdir(name->full_name, mode) == -1) {
329                         return pvfs_map_errno(pvfs,errno);
330                 }
331
332                 pvfs_xattr_unlink_hook(pvfs, name->full_name);
333
334                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
335                 if (!NT_STATUS_IS_OK(status)) {
336                         goto cleanup_delete;
337                 }
338
339                 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
340                 if (!NT_STATUS_IS_OK(status)) {
341                         goto cleanup_delete;
342                 }
343
344                 /* form the lock context used for opendb locking */
345                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
346                 if (!NT_STATUS_IS_OK(status)) {
347                         return status;
348                 }
349
350                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
351                 if (lck == NULL) {
352                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
353                                  name->full_name));
354                         /* we were supposed to do a blocking lock, so something
355                            is badly wrong! */
356                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
357                 }
358
359                 status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
360                                        share_access, access_mask, del_on_close, 
361                                        name->full_name, OPLOCK_NONE, NULL);
362
363                 if (!NT_STATUS_IS_OK(status)) {
364                         goto cleanup_delete;
365                 }
366
367                 f->handle->have_opendb_entry = True;
368
369                 create_action = NTCREATEX_ACTION_CREATED;
370
371                 notify_trigger(pvfs->notify_context, 
372                                NOTIFY_ACTION_ADDED, 
373                                FILE_NOTIFY_CHANGE_DIR_NAME,
374                                name->full_name);
375         } else {
376                 create_action = NTCREATEX_ACTION_EXISTED;
377         }
378
379         if (!name->exists) {
380                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
381         }
382
383         /* the open succeeded, keep this handle permanently */
384         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
385         if (!NT_STATUS_IS_OK(status)) {
386                 goto cleanup_delete;
387         }
388
389         io->generic.out.oplock_level  = OPLOCK_NONE;
390         io->generic.out.file.ntvfs    = h;
391         io->generic.out.create_action = create_action;
392         io->generic.out.create_time   = name->dos.create_time;
393         io->generic.out.access_time   = name->dos.access_time;
394         io->generic.out.write_time    = name->dos.write_time;
395         io->generic.out.change_time   = name->dos.change_time;
396         io->generic.out.attrib        = name->dos.attrib;
397         io->generic.out.alloc_size    = name->dos.alloc_size;
398         io->generic.out.size          = name->st.st_size;
399         io->generic.out.file_type     = FILE_TYPE_DISK;
400         io->generic.out.ipc_state     = 0;
401         io->generic.out.is_directory  = 1;
402
403         return NT_STATUS_OK;
404
405 cleanup_delete:
406         rmdir(name->full_name);
407         return status;
408 }
409
410 /*
411   destroy a struct pvfs_file_handle
412 */
413 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
414 {
415         int open_count;
416         char *path = NULL;
417
418         /* the write time is no longer sticky */
419         if (h->sticky_write_time) {
420                 NTSTATUS status;
421                 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
422                 if (NT_STATUS_IS_OK(status)) {
423                         h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
424                         pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
425                 }
426         }
427         
428         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
429             h->name->stream_name) {
430                 NTSTATUS status;
431                 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
432                 if (!NT_STATUS_IS_OK(status)) {
433                         DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
434                                  h->name->stream_name, h->name->full_name));
435                 }
436         }
437
438         if (h->fd != -1) {
439                 if (close(h->fd) != 0) {
440                         DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
441                                  h->fd, h->name->full_name, strerror(errno)));
442                 }
443                 h->fd = -1;
444         }
445
446         if (h->name->stream_name == NULL && 
447             pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
448             open_count == 1) {
449                 NTSTATUS status;
450                 status = pvfs_xattr_unlink_hook(h->pvfs, path);
451                 if (!NT_STATUS_IS_OK(status)) {
452                         DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
453                                  path, nt_errstr(status)));
454                 }
455                 if (unlink(path) != 0) {
456                         DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", 
457                                  path, strerror(errno)));
458                 } else {
459                         notify_trigger(h->pvfs->notify_context, 
460                                        NOTIFY_ACTION_REMOVED, 
461                                        FILE_NOTIFY_CHANGE_FILE_NAME,
462                                        path);
463                 }
464         }
465
466         talloc_free(path);
467
468         if (h->have_opendb_entry) {
469                 struct odb_lock *lck;
470                 NTSTATUS status;
471
472                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
473                 if (lck == NULL) {
474                         DEBUG(0,("Unable to lock opendb for close\n"));
475                         return 0;
476                 }
477
478                 status = odb_close_file(lck, h);
479                 if (!NT_STATUS_IS_OK(status)) {
480                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
481                                  h->name->full_name, nt_errstr(status)));
482                 }
483
484                 talloc_free(lck);
485         }
486
487         return 0;
488 }
489
490
491 /*
492   destroy a struct pvfs_file
493 */
494 static int pvfs_fnum_destructor(struct pvfs_file *f)
495 {
496         DLIST_REMOVE(f->pvfs->files.list, f);
497         pvfs_lock_close(f->pvfs, f);
498         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
499
500         return 0;
501 }
502
503
504 /*
505   form the lock context used for byte range locking. This is separate
506   from the locking key used for opendb locking as it needs to take
507   account of file streams (each stream is a separate byte range
508   locking space)
509 */
510 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
511                                         struct pvfs_filename *name,
512                                         struct ntvfs_handle *ntvfs,
513                                         struct brl_handle **_h)
514 {
515         DATA_BLOB odb_key, key;
516         NTSTATUS status;
517         struct brl_handle *h;
518
519         status = pvfs_locking_key(name, mem_ctx, &odb_key);
520         NT_STATUS_NOT_OK_RETURN(status);
521
522         if (name->stream_name == NULL) {
523                 key = odb_key;
524         } else {
525                 key = data_blob_talloc(mem_ctx, NULL, 
526                                        odb_key.length + strlen(name->stream_name) + 1);
527                 NT_STATUS_HAVE_NO_MEMORY(key.data);
528                 memcpy(key.data, odb_key.data, odb_key.length);
529                 memcpy(key.data + odb_key.length, 
530                        name->stream_name, strlen(name->stream_name) + 1);
531                 data_blob_free(&odb_key);
532         }
533
534         h = brl_create_handle(mem_ctx, ntvfs, &key);
535         NT_STATUS_HAVE_NO_MEMORY(h);
536
537         *_h = h;
538         return NT_STATUS_OK;
539 }
540
541 /*
542   create a new file
543 */
544 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 
545                                  struct ntvfs_request *req, 
546                                  struct pvfs_filename *name, 
547                                  union smb_open *io)
548 {
549         struct pvfs_file *f;
550         NTSTATUS status;
551         struct ntvfs_handle *h;
552         int flags, fd;
553         struct odb_lock *lck;
554         uint32_t create_options = io->generic.in.create_options;
555         uint32_t share_access = io->generic.in.share_access;
556         uint32_t access_mask = io->generic.in.access_mask;
557         mode_t mode;
558         uint32_t attrib;
559         BOOL del_on_close;
560         struct pvfs_filename *parent;
561         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
562
563         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
564             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
565                 return NT_STATUS_CANNOT_DELETE;
566         }
567         
568         status = pvfs_access_check_create(pvfs, req, name, &access_mask);
569         NT_STATUS_NOT_OK_RETURN(status);
570
571         /* check that the parent isn't opened with delete on close set */
572         status = pvfs_resolve_parent(pvfs, req, name, &parent);
573         if (NT_STATUS_IS_OK(status)) {
574                 DATA_BLOB locking_key;
575                 status = pvfs_locking_key(parent, req, &locking_key);
576                 NT_STATUS_NOT_OK_RETURN(status);
577                 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, 
578                                                  &del_on_close, NULL, NULL);
579                 NT_STATUS_NOT_OK_RETURN(status);
580                 if (del_on_close) {
581                         return NT_STATUS_DELETE_PENDING;
582                 }
583         }
584
585         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
586                 flags = O_RDWR;
587         } else {
588                 flags = O_RDONLY;
589         }
590
591         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
592         NT_STATUS_NOT_OK_RETURN(status);
593
594         f = talloc(h, struct pvfs_file);
595         NT_STATUS_HAVE_NO_MEMORY(f);
596
597         f->handle = talloc(f, struct pvfs_file_handle);
598         NT_STATUS_HAVE_NO_MEMORY(f->handle);
599
600         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
601         mode = pvfs_fileperms(pvfs, attrib);
602
603         /* create the file */
604         fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
605         if (fd == -1) {
606                 return pvfs_map_errno(pvfs, errno);
607         }
608
609         pvfs_xattr_unlink_hook(pvfs, name->full_name);
610
611         /* if this was a stream create then create the stream as well */
612         if (name->stream_name) {
613                 status = pvfs_stream_create(pvfs, name, fd);
614                 if (!NT_STATUS_IS_OK(status)) {
615                         close(fd);
616                         return status;
617                 }
618         }
619
620         /* re-resolve the open fd */
621         status = pvfs_resolve_name_fd(pvfs, fd, name);
622         if (!NT_STATUS_IS_OK(status)) {
623                 close(fd);
624                 return status;
625         }
626
627         name->dos.attrib = attrib;
628         status = pvfs_dosattrib_save(pvfs, name, fd);
629         if (!NT_STATUS_IS_OK(status)) {
630                 goto cleanup_delete;
631         }
632
633
634         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
635         if (!NT_STATUS_IS_OK(status)) {
636                 goto cleanup_delete;
637         }
638
639         /* form the lock context used for byte range locking and
640            opendb locking */
641         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
642         if (!NT_STATUS_IS_OK(status)) {
643                 goto cleanup_delete;
644         }
645
646         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
647         if (!NT_STATUS_IS_OK(status)) {
648                 goto cleanup_delete;
649         }
650
651         /* grab a lock on the open file record */
652         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
653         if (lck == NULL) {
654                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
655                          name->full_name));
656                 /* we were supposed to do a blocking lock, so something
657                    is badly wrong! */
658                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
659                 goto cleanup_delete;
660         }
661
662         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
663                 del_on_close = True;
664         } else {
665                 del_on_close = False;
666         }
667
668         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
669                 oplock_level = OPLOCK_NONE;
670         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
671                 oplock_level = OPLOCK_BATCH;
672         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
673                 oplock_level = OPLOCK_EXCLUSIVE;
674         }
675
676         status = odb_open_file(lck, f->handle, name->stream_id,
677                                share_access, access_mask, del_on_close, 
678                                name->full_name, oplock_level, &oplock_granted);
679         talloc_free(lck);
680         if (!NT_STATUS_IS_OK(status)) {
681                 /* bad news, we must have hit a race - we don't delete the file
682                    here as the most likely scenario is that someone else created 
683                    the file at the same time */
684                 close(fd);
685                 return status;
686         }
687
688         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
689                 oplock_granted = OPLOCK_BATCH;
690         }
691
692         f->ntvfs             = h;
693         f->session_info      = req->session_info;
694         f->smbpid            = req->smbpid;
695         f->pvfs              = pvfs;
696         f->pending_list      = NULL;
697         f->lock_count        = 0;
698         f->share_access      = io->generic.in.share_access;
699         f->access_mask       = access_mask;
700         f->impersonation     = io->generic.in.impersonation;
701         f->notify_buffer     = NULL;
702         f->search            = NULL;
703
704         f->handle->pvfs              = pvfs;
705         f->handle->name              = talloc_steal(f->handle, name);
706         f->handle->fd                = fd;
707         f->handle->create_options    = io->generic.in.create_options;
708         f->handle->seek_offset       = 0;
709         f->handle->position          = 0;
710         f->handle->mode              = 0;
711         f->handle->have_opendb_entry = True;
712         f->handle->sticky_write_time = False;
713
714         DLIST_ADD(pvfs->files.list, f);
715
716         /* setup a destructor to avoid file descriptor leaks on
717            abnormal termination */
718         talloc_set_destructor(f, pvfs_fnum_destructor);
719         talloc_set_destructor(f->handle, pvfs_handle_destructor);
720
721         io->generic.out.oplock_level  = oplock_granted;
722         io->generic.out.file.ntvfs    = f->ntvfs;
723         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
724         io->generic.out.create_time   = name->dos.create_time;
725         io->generic.out.access_time   = name->dos.access_time;
726         io->generic.out.write_time    = name->dos.write_time;
727         io->generic.out.change_time   = name->dos.change_time;
728         io->generic.out.attrib        = name->dos.attrib;
729         io->generic.out.alloc_size    = name->dos.alloc_size;
730         io->generic.out.size          = name->st.st_size;
731         io->generic.out.file_type     = FILE_TYPE_DISK;
732         io->generic.out.ipc_state     = 0;
733         io->generic.out.is_directory  = 0;
734
735         /* success - keep the file handle */
736         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
737         if (!NT_STATUS_IS_OK(status)) {
738                 goto cleanup_delete;
739         }
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         void *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->session_info == req->session_info &&
865                     f2->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->session_info  = req->session_info;
1124         f->smbpid        = req->smbpid;
1125         f->pvfs          = pvfs;
1126         f->pending_list  = NULL;
1127         f->lock_count    = 0;
1128         f->share_access  = io->generic.in.share_access;
1129         f->access_mask   = access_mask;
1130         f->impersonation = io->generic.in.impersonation;
1131         f->notify_buffer = NULL;
1132         f->search        = NULL;
1133
1134         f->handle->pvfs              = pvfs;
1135         f->handle->fd                = -1;
1136         f->handle->name              = talloc_steal(f->handle, name);
1137         f->handle->create_options    = io->generic.in.create_options;
1138         f->handle->seek_offset       = 0;
1139         f->handle->position          = 0;
1140         f->handle->mode              = 0;
1141         f->handle->have_opendb_entry = False;
1142         f->handle->sticky_write_time = False;
1143
1144         /* form the lock context used for byte range locking and
1145            opendb locking */
1146         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1147         if (!NT_STATUS_IS_OK(status)) {
1148                 return status;
1149         }
1150
1151         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1152         if (!NT_STATUS_IS_OK(status)) {
1153                 return status;
1154         }
1155
1156         /* get a lock on this file before the actual open */
1157         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1158         if (lck == NULL) {
1159                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1160                          name->full_name));
1161                 /* we were supposed to do a blocking lock, so something
1162                    is badly wrong! */
1163                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1164         }
1165
1166         DLIST_ADD(pvfs->files.list, f);
1167
1168         /* setup a destructor to avoid file descriptor leaks on
1169            abnormal termination */
1170         talloc_set_destructor(f, pvfs_fnum_destructor);
1171         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1172
1173         /* 
1174          * Only SMB2 takes care of the delete_on_close,
1175          * on existing files
1176          */
1177         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1178             req->ctx->protocol == PROTOCOL_SMB2) {
1179                 del_on_close = True;
1180         } else {
1181                 del_on_close = False;
1182         }
1183
1184         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1185                 oplock_level = OPLOCK_NONE;
1186         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1187                 oplock_level = OPLOCK_BATCH;
1188         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1189                 oplock_level = OPLOCK_EXCLUSIVE;
1190         }
1191
1192         /* see if we are allowed to open at the same time as existing opens */
1193         status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
1194                                share_access, access_mask, del_on_close,
1195                                name->full_name, 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         io->generic.out.oplock_level  = oplock_granted;
1279         io->generic.out.file.ntvfs    = h;
1280         io->generic.out.create_action = stream_existed?
1281                 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1282         io->generic.out.create_time   = name->dos.create_time;
1283         io->generic.out.access_time   = name->dos.access_time;
1284         io->generic.out.write_time    = name->dos.write_time;
1285         io->generic.out.change_time   = name->dos.change_time;
1286         io->generic.out.attrib        = name->dos.attrib;
1287         io->generic.out.alloc_size    = name->dos.alloc_size;
1288         io->generic.out.size          = name->st.st_size;
1289         io->generic.out.file_type     = FILE_TYPE_DISK;
1290         io->generic.out.ipc_state     = 0;
1291         io->generic.out.is_directory  = 0;
1292
1293         return NT_STATUS_OK;
1294 }
1295
1296
1297 /*
1298   close a file
1299 */
1300 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1301                     struct ntvfs_request *req, union smb_close *io)
1302 {
1303         struct pvfs_state *pvfs = ntvfs->private_data;
1304         struct pvfs_file *f;
1305         struct utimbuf unix_times;
1306
1307         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1308                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1309         }
1310
1311         if (io->generic.level != RAW_CLOSE_CLOSE) {
1312                 return ntvfs_map_close(ntvfs, req, io);
1313         }
1314
1315         f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1316         if (!f) {
1317                 return NT_STATUS_INVALID_HANDLE;
1318         }
1319
1320         if (!null_time(io->close.in.write_time)) {
1321                 unix_times.actime = 0;
1322                 unix_times.modtime = io->close.in.write_time;
1323                 utime(f->handle->name->full_name, &unix_times);
1324         } else if (f->handle->sticky_write_time) {
1325                 unix_times.actime = 0;
1326                 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1327                 utime(f->handle->name->full_name, &unix_times);
1328         }
1329
1330         talloc_free(f);
1331
1332         return NT_STATUS_OK;
1333 }
1334
1335
1336 /*
1337   logoff - close all file descriptors open by a vuid
1338 */
1339 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1340                      struct ntvfs_request *req)
1341 {
1342         struct pvfs_state *pvfs = ntvfs->private_data;
1343         struct pvfs_file *f, *next;
1344
1345         for (f=pvfs->files.list;f;f=next) {
1346                 next = f->next;
1347                 if (f->session_info == req->session_info) {
1348                         talloc_free(f);
1349                 }
1350         }
1351
1352         return NT_STATUS_OK;
1353 }
1354
1355
1356 /*
1357   exit - close files for the current pid
1358 */
1359 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1360                    struct ntvfs_request *req)
1361 {
1362         struct pvfs_state *pvfs = ntvfs->private_data;
1363         struct pvfs_file *f, *next;
1364
1365         for (f=pvfs->files.list;f;f=next) {
1366                 next = f->next;
1367                 if (f->session_info == req->session_info &&
1368                     f->smbpid == req->smbpid) {
1369                         talloc_free(f);
1370                 }
1371         }
1372
1373         return NT_STATUS_OK;
1374 }
1375
1376
1377 /*
1378   change the delete on close flag on an already open file
1379 */
1380 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1381                                   struct ntvfs_request *req, 
1382                                   struct pvfs_file *f, BOOL del_on_close)
1383 {
1384         struct odb_lock *lck;
1385         NTSTATUS status;
1386
1387         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1388                 return NT_STATUS_CANNOT_DELETE;
1389         }
1390         
1391         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1392             !pvfs_directory_empty(pvfs, f->handle->name)) {
1393                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1394         }
1395
1396         if (del_on_close) {
1397                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1398         } else {
1399                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1400         }
1401         
1402         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1403         if (lck == NULL) {
1404                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1405         }
1406
1407         status = odb_set_delete_on_close(lck, del_on_close);
1408
1409         talloc_free(lck);
1410
1411         return status;
1412 }
1413
1414
1415 /*
1416   determine if a file can be deleted, or if it is prevented by an
1417   already open file
1418 */
1419 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1420                          struct ntvfs_request *req,
1421                          struct pvfs_filename *name,
1422                          struct odb_lock **lckp)
1423 {
1424         NTSTATUS status;
1425         DATA_BLOB key;
1426         struct odb_lock *lck;
1427
1428         status = pvfs_locking_key(name, name, &key);
1429         if (!NT_STATUS_IS_OK(status)) {
1430                 return NT_STATUS_NO_MEMORY;
1431         }
1432
1433         lck = odb_lock(req, pvfs->odb_context, &key);
1434         if (lck == NULL) {
1435                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1436                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1437         }
1438
1439         status = odb_can_open(lck,
1440                               NTCREATEX_SHARE_ACCESS_READ |
1441                               NTCREATEX_SHARE_ACCESS_WRITE | 
1442                               NTCREATEX_SHARE_ACCESS_DELETE, 
1443                               NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 
1444                               SEC_STD_DELETE);
1445
1446         if (NT_STATUS_IS_OK(status)) {
1447                 status = pvfs_access_check_simple(pvfs, req, name, SEC_STD_DELETE);
1448         }
1449
1450         if (!NT_STATUS_IS_OK(status)) {
1451                 talloc_free(lck);
1452                 *lckp = lck;
1453         } else if (lckp != NULL) {
1454                 *lckp = lck;
1455         }
1456
1457         return status;
1458 }
1459
1460 /*
1461   determine if a file can be renamed, or if it is prevented by an
1462   already open file
1463 */
1464 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1465                          struct ntvfs_request *req,
1466                          struct pvfs_filename *name,
1467                          struct odb_lock **lckp)
1468 {
1469         NTSTATUS status;
1470         DATA_BLOB key;
1471         struct odb_lock *lck;
1472
1473         status = pvfs_locking_key(name, name, &key);
1474         if (!NT_STATUS_IS_OK(status)) {
1475                 return NT_STATUS_NO_MEMORY;
1476         }
1477
1478         lck = odb_lock(req, pvfs->odb_context, &key);
1479         if (lck == NULL) {
1480                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1481                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1482         }
1483
1484         status = odb_can_open(lck,
1485                               NTCREATEX_SHARE_ACCESS_READ |
1486                               NTCREATEX_SHARE_ACCESS_WRITE,
1487                               0,
1488                               SEC_STD_DELETE);
1489
1490         if (!NT_STATUS_IS_OK(status)) {
1491                 talloc_free(lck);
1492                 *lckp = lck;
1493         } else if (lckp != NULL) {
1494                 *lckp = lck;
1495         }
1496
1497         return status;
1498 }
1499
1500 /*
1501   determine if file meta data can be accessed, or if it is prevented by an
1502   already open file
1503 */
1504 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1505                        struct ntvfs_request *req,
1506                        struct pvfs_filename *name)
1507 {
1508         NTSTATUS status;
1509         DATA_BLOB key;
1510         struct odb_lock *lck;
1511
1512         status = pvfs_locking_key(name, name, &key);
1513         if (!NT_STATUS_IS_OK(status)) {
1514                 return NT_STATUS_NO_MEMORY;
1515         }
1516
1517         lck = odb_lock(req, pvfs->odb_context, &key);
1518         if (lck == NULL) {
1519                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1520                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1521         }
1522
1523         status = odb_can_open(lck,
1524                               NTCREATEX_SHARE_ACCESS_READ |
1525                               NTCREATEX_SHARE_ACCESS_WRITE,
1526                               0, 0);
1527
1528         return status;
1529 }
1530
1531
1532 /*
1533   determine if delete on close is set on 
1534 */
1535 BOOL pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h, 
1536                               int *open_count, char **path)
1537 {
1538         NTSTATUS status;
1539         BOOL del_on_close;
1540
1541         status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
1542                                          &del_on_close, open_count, path);
1543         if (!NT_STATUS_IS_OK(status)) {
1544                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1545                 return False;
1546         }
1547
1548         return del_on_close;
1549 }