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