r14616: added notify change support to the posix backend
[metze/samba/wip.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         } else {
382                 create_action = NTCREATEX_ACTION_EXISTED;
383         }
384
385         if (!name->exists) {
386                 idr_remove(pvfs->files.idtree, fnum);
387                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
388         }
389
390         /* the open succeeded, keep this handle permanently */
391         talloc_steal(pvfs, f);
392
393         io->generic.out.oplock_level  = OPLOCK_NONE;
394         io->generic.out.file.fnum     = f->fnum;
395         io->generic.out.create_action = create_action;
396         io->generic.out.create_time   = name->dos.create_time;
397         io->generic.out.access_time   = name->dos.access_time;
398         io->generic.out.write_time    = name->dos.write_time;
399         io->generic.out.change_time   = name->dos.change_time;
400         io->generic.out.attrib        = name->dos.attrib;
401         io->generic.out.alloc_size    = name->dos.alloc_size;
402         io->generic.out.size          = name->st.st_size;
403         io->generic.out.file_type     = FILE_TYPE_DISK;
404         io->generic.out.ipc_state     = 0;
405         io->generic.out.is_directory  = 1;
406
407         return NT_STATUS_OK;
408
409 cleanup_delete:
410         idr_remove(pvfs->files.idtree, fnum);
411         rmdir(name->full_name);
412         return status;
413 }
414
415 /*
416   destroy a struct pvfs_file_handle
417 */
418 static int pvfs_handle_destructor(void *p)
419 {
420         struct pvfs_file_handle *h = p;
421         int open_count;
422         char *path;
423
424         /* the write time is no longer sticky */
425         if (h->sticky_write_time) {
426                 NTSTATUS status;
427                 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
428                 if (NT_STATUS_IS_OK(status)) {
429                         h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
430                         pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
431                 }
432         }
433         
434         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
435             h->name->stream_name) {
436                 NTSTATUS status;
437                 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
438                 if (!NT_STATUS_IS_OK(status)) {
439                         DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
440                                  h->name->stream_name, h->name->full_name));
441                 }
442         }
443
444         if (h->fd != -1) {
445                 if (close(h->fd) != 0) {
446                         DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
447                                  h->fd, h->name->full_name, strerror(errno)));
448                 }
449                 h->fd = -1;
450         }
451
452         if (h->name->stream_name == NULL && 
453             pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
454             open_count == 1) {
455                 NTSTATUS status;
456                 status = pvfs_xattr_unlink_hook(h->pvfs, path);
457                 if (!NT_STATUS_IS_OK(status)) {
458                         DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
459                                  path, nt_errstr(status)));
460                 }
461                 if (unlink(path) != 0) {
462                         DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", 
463                                  path, strerror(errno)));
464                 }
465         }
466
467         if (h->have_opendb_entry) {
468                 struct odb_lock *lck;
469                 NTSTATUS status;
470
471                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
472                 if (lck == NULL) {
473                         DEBUG(0,("Unable to lock opendb for close\n"));
474                         return 0;
475                 }
476
477                 status = odb_close_file(lck, h);
478                 if (!NT_STATUS_IS_OK(status)) {
479                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
480                                  h->name->full_name, nt_errstr(status)));
481                 }
482
483                 talloc_free(lck);
484         }
485
486         return 0;
487 }
488
489
490 /*
491   destroy a struct pvfs_file
492 */
493 static int pvfs_fnum_destructor(void *p)
494 {
495         struct pvfs_file *f = p;
496
497         DLIST_REMOVE(f->pvfs->files.list, f);
498         pvfs_lock_close(f->pvfs, f);
499         idr_remove(f->pvfs->files.idtree, f->fnum);
500
501         return 0;
502 }
503
504
505 /*
506   form the lock context used for byte range locking. This is separate
507   from the locking key used for opendb locking as it needs to take
508   account of file streams (each stream is a separate byte range
509   locking space)
510 */
511 static NTSTATUS pvfs_brl_locking_key(struct pvfs_filename *name, 
512                                      TALLOC_CTX *mem_ctx, DATA_BLOB *key)
513 {
514         DATA_BLOB odb_key;
515         NTSTATUS status;
516         status = pvfs_locking_key(name, mem_ctx, &odb_key);
517         if (!NT_STATUS_IS_OK(status)) {
518                 return status;
519         }
520         if (name->stream_name == NULL) {
521                 *key = odb_key;
522                 return NT_STATUS_OK;
523         }
524         *key = data_blob_talloc(mem_ctx, NULL, 
525                                 odb_key.length + strlen(name->stream_name) + 1);
526         if (key->data == NULL) {
527                 return NT_STATUS_NO_MEMORY;
528         }
529         memcpy(key->data, odb_key.data, odb_key.length);
530         memcpy(key->data + odb_key.length, 
531                name->stream_name, strlen(name->stream_name)+1);
532         data_blob_free(&odb_key);
533         return NT_STATUS_OK;
534 }
535
536
537 /*
538   create a new file
539 */
540 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 
541                                  struct ntvfs_request *req, 
542                                  struct pvfs_filename *name, 
543                                  union smb_open *io)
544 {
545         struct pvfs_file *f;
546         NTSTATUS status;
547         int flags, fnum, fd;
548         struct odb_lock *lck;
549         uint32_t create_options = io->generic.in.create_options;
550         uint32_t share_access = io->generic.in.share_access;
551         uint32_t access_mask = io->generic.in.access_mask;
552         mode_t mode;
553         uint32_t attrib;
554         BOOL del_on_close;
555         struct pvfs_filename *parent;
556
557         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
558             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
559                 return NT_STATUS_CANNOT_DELETE;
560         }
561         
562         status = pvfs_access_check_create(pvfs, req, name, &access_mask);
563         NT_STATUS_NOT_OK_RETURN(status);
564
565         /* check that the parent isn't opened with delete on close set */
566         status = pvfs_resolve_parent(pvfs, req, name, &parent);
567         if (NT_STATUS_IS_OK(status)) {
568                 DATA_BLOB locking_key;
569                 status = pvfs_locking_key(parent, req, &locking_key);
570                 NT_STATUS_NOT_OK_RETURN(status);
571                 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, 
572                                                  &del_on_close, NULL, NULL);
573                 NT_STATUS_NOT_OK_RETURN(status);
574                 if (del_on_close) {
575                         return NT_STATUS_DELETE_PENDING;
576                 }
577         }
578
579         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
580                 flags = O_RDWR;
581         } else {
582                 flags = O_RDONLY;
583         }
584
585         f = talloc(req, struct pvfs_file);
586         if (f == NULL) {
587                 return NT_STATUS_NO_MEMORY;
588         }
589
590         f->handle = talloc(f, struct pvfs_file_handle);
591         if (f->handle == NULL) {
592                 return NT_STATUS_NO_MEMORY;
593         }
594
595         fnum = idr_get_new_above(pvfs->files.idtree, f, PVFS_MIN_NEW_FNUM, UINT16_MAX);
596         if (fnum == -1) {
597                 return NT_STATUS_TOO_MANY_OPENED_FILES;
598         }
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                 idr_remove(pvfs->files.idtree, fnum);
607                 return pvfs_map_errno(pvfs, errno);
608         }
609
610         pvfs_xattr_unlink_hook(pvfs, name->full_name);
611
612         /* if this was a stream create then create the stream as well */
613         if (name->stream_name) {
614                 status = pvfs_stream_create(pvfs, name, fd);
615                 if (!NT_STATUS_IS_OK(status)) {
616                         idr_remove(pvfs->files.idtree, fnum);
617                         close(fd);
618                         return status;
619                 }
620         }
621
622         /* re-resolve the open fd */
623         status = pvfs_resolve_name_fd(pvfs, fd, name);
624         if (!NT_STATUS_IS_OK(status)) {
625                 idr_remove(pvfs->files.idtree, fnum);
626                 close(fd);
627                 return status;
628         }
629
630         name->dos.attrib = attrib;
631         status = pvfs_dosattrib_save(pvfs, name, fd);
632         if (!NT_STATUS_IS_OK(status)) {
633                 goto cleanup_delete;
634         }
635
636
637         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, fnum, io);
638         if (!NT_STATUS_IS_OK(status)) {
639                 goto cleanup_delete;
640         }
641
642         /* form the lock context used for byte range locking and
643            opendb locking */
644         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
645         if (!NT_STATUS_IS_OK(status)) {
646                 goto cleanup_delete;
647         }
648
649         status = pvfs_brl_locking_key(name, f->handle, &f->handle->brl_locking_key);
650         if (!NT_STATUS_IS_OK(status)) {
651                 goto cleanup_delete;
652         }
653
654         /* grab a lock on the open file record */
655         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
656         if (lck == NULL) {
657                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
658                          name->full_name));
659                 /* we were supposed to do a blocking lock, so something
660                    is badly wrong! */
661                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
662                 goto cleanup_delete;
663         }
664
665         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
666                 del_on_close = True;
667         } else {
668                 del_on_close = False;
669         }
670
671         status = odb_open_file(lck, f->handle, name->stream_id,
672                                share_access, access_mask, del_on_close, name->full_name);
673         talloc_free(lck);
674         if (!NT_STATUS_IS_OK(status)) {
675                 /* bad news, we must have hit a race - we don't delete the file
676                    here as the most likely scenario is that someone else created 
677                    the file at the same time */
678                 idr_remove(pvfs->files.idtree, fnum);
679                 close(fd);
680                 return status;
681         }
682
683         f->fnum              = fnum;
684         f->session_info      = req->session_info;
685         f->smbpid            = req->smbpid;
686         f->pvfs              = pvfs;
687         f->pending_list      = NULL;
688         f->lock_count        = 0;
689         f->share_access      = io->generic.in.share_access;
690         f->access_mask       = access_mask;
691         f->impersonation     = io->generic.in.impersonation;
692         f->notify_buffer     = NULL;
693
694         f->handle->pvfs              = pvfs;
695         f->handle->name              = talloc_steal(f->handle, name);
696         f->handle->fd                = fd;
697         f->handle->create_options    = io->generic.in.create_options;
698         f->handle->seek_offset       = 0;
699         f->handle->position          = 0;
700         f->handle->mode              = 0;
701         f->handle->have_opendb_entry = True;
702         f->handle->sticky_write_time = False;
703
704         DLIST_ADD(pvfs->files.list, f);
705
706         /* setup a destructor to avoid file descriptor leaks on
707            abnormal termination */
708         talloc_set_destructor(f, pvfs_fnum_destructor);
709         talloc_set_destructor(f->handle, pvfs_handle_destructor);
710
711         
712         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
713                 io->generic.out.oplock_level  = OPLOCK_EXCLUSIVE;
714         } else {
715                 io->generic.out.oplock_level  = OPLOCK_NONE;
716         }
717         io->generic.out.file.fnum     = f->fnum;
718         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
719         io->generic.out.create_time   = name->dos.create_time;
720         io->generic.out.access_time   = name->dos.access_time;
721         io->generic.out.write_time    = name->dos.write_time;
722         io->generic.out.change_time   = name->dos.change_time;
723         io->generic.out.attrib        = name->dos.attrib;
724         io->generic.out.alloc_size    = name->dos.alloc_size;
725         io->generic.out.size          = name->st.st_size;
726         io->generic.out.file_type     = FILE_TYPE_DISK;
727         io->generic.out.ipc_state     = 0;
728         io->generic.out.is_directory  = 0;
729
730         /* success - keep the file handle */
731         talloc_steal(pvfs, f);
732
733         return NT_STATUS_OK;
734
735 cleanup_delete:
736         idr_remove(pvfs->files.idtree, fnum);
737         close(fd);
738         unlink(name->full_name);
739         return status;
740 }
741
742
743 /*
744   state of a pending open retry
745 */
746 struct pvfs_open_retry {
747         struct ntvfs_module_context *ntvfs;
748         struct ntvfs_request *req;
749         union smb_open *io;
750         void *wait_handle;
751         DATA_BLOB odb_locking_key;
752 };
753
754 /* destroy a pending open request */
755 static int pvfs_retry_destructor(void *ptr)
756 {
757         struct pvfs_open_retry *r = ptr;
758         struct pvfs_state *pvfs = r->ntvfs->private_data;
759         if (r->odb_locking_key.data) {
760                 struct odb_lock *lck;
761                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
762                 if (lck != NULL) {
763                         odb_remove_pending(lck, r);
764                 }
765                 talloc_free(lck);
766         }
767         return 0;
768 }
769
770 /*
771   retry an open
772 */
773 static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
774 {
775         struct pvfs_open_retry *r = private;
776         struct ntvfs_module_context *ntvfs = r->ntvfs;
777         struct ntvfs_request *req = r->req;
778         union smb_open *io = r->io;
779         NTSTATUS status;
780
781         /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
782            just a bug in their server, but we better do the same */
783         if (reason == PVFS_WAIT_CANCEL) {
784                 return;
785         }
786
787         talloc_free(r->wait_handle);
788
789         if (reason == PVFS_WAIT_TIMEOUT) {
790                 /* if it timed out, then give the failure
791                    immediately */
792                 talloc_free(r);
793                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
794                 req->async_states->send_fn(req);
795                 return;
796         }
797
798         /* the pending odb entry is already removed. We use a null locking
799            key to indicate this */
800         data_blob_free(&r->odb_locking_key);
801         talloc_free(r);
802
803         /* try the open again, which could trigger another retry setup
804            if it wants to, so we have to unmark the async flag so we
805            will know if it does a second async reply */
806         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
807
808         status = pvfs_open(ntvfs, req, io);
809         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
810                 /* the 2nd try also replied async, so we don't send
811                    the reply yet */
812                 return;
813         }
814
815         /* re-mark it async, just in case someone up the chain does
816            paranoid checking */
817         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
818
819         /* send the reply up the chain */
820         req->async_states->status = status;
821         req->async_states->send_fn(req);
822 }
823
824
825 /*
826   special handling for openx DENY_DOS semantics
827
828   This function attempts a reference open using an existing handle. If its allowed,
829   then it returns NT_STATUS_OK, otherwise it returns any other code and normal
830   open processing continues.
831 */
832 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
833                                    struct ntvfs_request *req, union smb_open *io,
834                                    struct pvfs_file *f, struct odb_lock *lck)
835 {
836         struct pvfs_state *pvfs = ntvfs->private_data;
837         struct pvfs_file *f2;
838         struct pvfs_filename *name;
839
840         /* search for an existing open with the right parameters. Note
841            the magic ntcreatex options flag, which is set in the
842            generic mapping code. This might look ugly, but its
843            actually pretty much now w2k does it internally as well. 
844            
845            If you look at the BASE-DENYDOS test you will see that a
846            DENY_DOS is a very special case, and in the right
847            circumstances you actually get the _same_ handle back
848            twice, rather than a new handle.
849         */
850         for (f2=pvfs->files.list;f2;f2=f2->next) {
851                 if (f2 != f &&
852                     f2->session_info == req->session_info &&
853                     f2->smbpid == req->smbpid &&
854                     (f2->handle->create_options & 
855                      (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
856                       NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
857                     (f2->access_mask & SEC_FILE_WRITE_DATA) &&
858                     strcasecmp_m(f2->handle->name->original_name, 
859                                io->generic.in.fname)==0) {
860                         break;
861                 }
862         }
863
864         if (!f2) {
865                 return NT_STATUS_SHARING_VIOLATION;
866         }
867
868         /* quite an insane set of semantics ... */
869         if (is_exe_filename(io->generic.in.fname) &&
870             (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
871                 return NT_STATUS_SHARING_VIOLATION;
872         }
873
874         /*
875           setup a reference to the existing handle
876          */
877         talloc_free(f->handle);
878         f->handle = talloc_reference(f, f2->handle);
879
880         talloc_free(lck);
881
882         name = f->handle->name;
883
884         io->generic.out.oplock_level  = OPLOCK_NONE;
885         io->generic.out.file.fnum     = f->fnum;
886         io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
887         io->generic.out.create_time   = name->dos.create_time;
888         io->generic.out.access_time   = name->dos.access_time;
889         io->generic.out.write_time    = name->dos.write_time;
890         io->generic.out.change_time   = name->dos.change_time;
891         io->generic.out.attrib        = name->dos.attrib;
892         io->generic.out.alloc_size    = name->dos.alloc_size;
893         io->generic.out.size          = name->st.st_size;
894         io->generic.out.file_type     = FILE_TYPE_DISK;
895         io->generic.out.ipc_state     = 0;
896         io->generic.out.is_directory  = 0;
897
898         talloc_steal(f->pvfs, f);
899
900         return NT_STATUS_OK;
901 }
902
903
904
905 /*
906   setup for a open retry after a sharing violation
907 */
908 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
909                                       struct ntvfs_request *req, 
910                                       union smb_open *io,
911                                       struct pvfs_file *f,
912                                       struct odb_lock *lck)
913 {
914         struct pvfs_state *pvfs = ntvfs->private_data;
915         struct pvfs_open_retry *r;
916         NTSTATUS status;
917         struct timeval end_time;
918
919         if (io->generic.in.create_options & 
920             (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
921                 /* see if we can satisfy the request using the special DENY_DOS
922                    code */
923                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
924                 if (NT_STATUS_IS_OK(status)) {
925                         return status;
926                 }
927         }
928
929         r = talloc(req, struct pvfs_open_retry);
930         if (r == NULL) {
931                 return NT_STATUS_NO_MEMORY;
932         }
933
934         r->ntvfs = ntvfs;
935         r->req = req;
936         r->io = io;
937         r->odb_locking_key = data_blob_talloc(r, 
938                                               f->handle->odb_locking_key.data, 
939                                               f->handle->odb_locking_key.length);
940
941         end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
942
943         /* setup a pending lock */
944         status = odb_open_file_pending(lck, r);
945         if (!NT_STATUS_IS_OK(status)) {
946                 return status;
947         }
948
949         talloc_free(lck);
950         talloc_free(f);
951
952         talloc_set_destructor(r, pvfs_retry_destructor);
953
954         r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, end_time, 
955                                            pvfs_open_retry, r);
956         if (r->wait_handle == NULL) {
957                 return NT_STATUS_NO_MEMORY;
958         }
959
960         talloc_steal(pvfs, r);
961
962         return NT_STATUS_OK;
963 }
964
965 /*
966   open a file
967 */
968 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
969                    struct ntvfs_request *req, union smb_open *io)
970 {
971         struct pvfs_state *pvfs = ntvfs->private_data;
972         int flags;
973         struct pvfs_filename *name;
974         struct pvfs_file *f;
975         NTSTATUS status;
976         int fnum, fd;
977         struct odb_lock *lck;
978         uint32_t create_options;
979         uint32_t share_access;
980         uint32_t access_mask;
981         BOOL stream_existed, stream_truncate=False;
982
983         /* use the generic mapping code to avoid implementing all the
984            different open calls. */
985         if (io->generic.level != RAW_OPEN_GENERIC &&
986             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
987                 return ntvfs_map_open(ntvfs, req, io);
988         }
989
990         /* resolve the cifs name to a posix name */
991         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
992                                    PVFS_RESOLVE_STREAMS, &name);
993         if (!NT_STATUS_IS_OK(status)) {
994                 return status;
995         }
996
997         /* directory opens are handled separately */
998         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
999             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1000                 return pvfs_open_directory(pvfs, req, name, io);
1001         }
1002
1003         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1004            open doesn't match */
1005         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1006
1007         create_options = io->generic.in.create_options;
1008         share_access   = io->generic.in.share_access;
1009         access_mask    = io->generic.in.access_mask;
1010
1011         /* certain create options are not allowed */
1012         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1013             !(access_mask & SEC_STD_DELETE)) {
1014                 return NT_STATUS_INVALID_PARAMETER;
1015         }
1016
1017         flags = 0;
1018
1019         switch (io->generic.in.open_disposition) {
1020         case NTCREATEX_DISP_SUPERSEDE:
1021         case NTCREATEX_DISP_OVERWRITE_IF:
1022                 if (name->stream_name == NULL) {
1023                         flags = O_TRUNC;
1024                 } else {
1025                         stream_truncate = True;
1026                 }
1027                 break;
1028
1029         case NTCREATEX_DISP_OPEN:
1030                 if (!name->stream_exists) {
1031                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1032                 }
1033                 flags = 0;
1034                 break;
1035
1036         case NTCREATEX_DISP_OVERWRITE:
1037                 if (!name->stream_exists) {
1038                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1039                 }
1040                 if (name->stream_name == NULL) {
1041                         flags = O_TRUNC;
1042                 } else {
1043                         stream_truncate = True;
1044                 }
1045                 break;
1046
1047         case NTCREATEX_DISP_CREATE:
1048                 if (name->stream_exists) {
1049                         return NT_STATUS_OBJECT_NAME_COLLISION;
1050                 }
1051                 flags = 0;
1052                 break;
1053
1054         case NTCREATEX_DISP_OPEN_IF:
1055                 flags = 0;
1056                 break;
1057
1058         default:
1059                 return NT_STATUS_INVALID_PARAMETER;
1060         }
1061
1062         /* handle creating a new file separately */
1063         if (!name->exists) {
1064                 status = pvfs_create_file(pvfs, req, name, io);
1065                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1066                         return status;
1067                 }
1068
1069                 /* we've hit a race - the file was created during this call */
1070                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1071                         return status;
1072                 }
1073
1074                 /* try re-resolving the name */
1075                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1076                 if (!NT_STATUS_IS_OK(status)) {
1077                         return status;
1078                 }
1079                 /* fall through to a normal open */
1080         }
1081
1082         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1083             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1084                 return NT_STATUS_CANNOT_DELETE;
1085         }
1086
1087         /* check the security descriptor */
1088         status = pvfs_access_check(pvfs, req, name, &access_mask);
1089         if (!NT_STATUS_IS_OK(status)) {
1090                 return status;
1091         }
1092
1093         f = talloc(req, struct pvfs_file);
1094         if (f == NULL) {
1095                 return NT_STATUS_NO_MEMORY;
1096         }
1097
1098         f->handle = talloc(f, struct pvfs_file_handle);
1099         if (f->handle == NULL) {
1100                 return NT_STATUS_NO_MEMORY;
1101         }
1102
1103         /* allocate a fnum */
1104         fnum = idr_get_new_above(pvfs->files.idtree, f, PVFS_MIN_FILE_FNUM, UINT16_MAX);
1105         if (fnum == -1) {
1106                 return NT_STATUS_TOO_MANY_OPENED_FILES;
1107         }
1108
1109         f->fnum          = fnum;
1110         f->session_info  = req->session_info;
1111         f->smbpid        = req->smbpid;
1112         f->pvfs          = pvfs;
1113         f->pending_list  = NULL;
1114         f->lock_count    = 0;
1115         f->share_access  = io->generic.in.share_access;
1116         f->access_mask   = access_mask;
1117         f->impersonation = io->generic.in.impersonation;
1118         f->notify_buffer = NULL;
1119
1120         f->handle->pvfs              = pvfs;
1121         f->handle->fd                = -1;
1122         f->handle->name              = talloc_steal(f->handle, name);
1123         f->handle->create_options    = io->generic.in.create_options;
1124         f->handle->seek_offset       = 0;
1125         f->handle->position          = 0;
1126         f->handle->mode              = 0;
1127         f->handle->have_opendb_entry = False;
1128         f->handle->sticky_write_time = False;
1129
1130         /* form the lock context used for byte range locking and
1131            opendb locking */
1132         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1133         if (!NT_STATUS_IS_OK(status)) {
1134                 idr_remove(pvfs->files.idtree, f->fnum);
1135                 return status;
1136         }
1137
1138         status = pvfs_brl_locking_key(name, f->handle, &f->handle->brl_locking_key);
1139         if (!NT_STATUS_IS_OK(status)) {
1140                 idr_remove(pvfs->files.idtree, f->fnum);
1141                 return status;
1142         }
1143
1144         /* get a lock on this file before the actual open */
1145         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1146         if (lck == NULL) {
1147                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1148                          name->full_name));
1149                 /* we were supposed to do a blocking lock, so something
1150                    is badly wrong! */
1151                 idr_remove(pvfs->files.idtree, fnum);
1152                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1153         }
1154
1155         DLIST_ADD(pvfs->files.list, f);
1156
1157         /* setup a destructor to avoid file descriptor leaks on
1158            abnormal termination */
1159         talloc_set_destructor(f, pvfs_fnum_destructor);
1160         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1161
1162         /* see if we are allowed to open at the same time as existing opens */
1163         status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
1164                                share_access, access_mask, False, name->full_name);
1165
1166         /* on a sharing violation we need to retry when the file is closed by 
1167            the other user, or after 1 second */
1168         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1169             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1170                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1171         }
1172
1173         if (!NT_STATUS_IS_OK(status)) {
1174                 talloc_free(lck);
1175                 return status;
1176         }
1177
1178         f->handle->have_opendb_entry = True;
1179
1180         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1181                 flags |= O_RDWR;
1182         } else {
1183                 flags |= O_RDONLY;
1184         }
1185
1186         /* do the actual open */
1187         fd = open(f->handle->name->full_name, flags);
1188         if (fd == -1) {
1189                 talloc_free(lck);
1190                 return pvfs_map_errno(f->pvfs, errno);
1191         }
1192
1193         f->handle->fd = fd;
1194
1195         stream_existed = name->stream_exists;
1196
1197         /* if this was a stream create then create the stream as well */
1198         if (!name->stream_exists) {
1199                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1200                 if (!NT_STATUS_IS_OK(status)) {
1201                         talloc_free(lck);
1202                         return status;
1203                 }
1204                 if (stream_truncate) {
1205                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1206                         if (!NT_STATUS_IS_OK(status)) {
1207                                 talloc_free(lck);
1208                                 return status;
1209                         }
1210                 }
1211         }
1212
1213         /* re-resolve the open fd */
1214         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1215         if (!NT_STATUS_IS_OK(status)) {
1216                 talloc_free(lck);
1217                 return status;
1218         }
1219
1220         if (f->handle->name->stream_id == 0 &&
1221             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1222              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1223                 /* for overwrite we need to replace file permissions */
1224                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1225                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1226                 if (fchmod(fd, mode) == -1) {
1227                         talloc_free(lck);
1228                         return pvfs_map_errno(pvfs, errno);
1229                 }
1230                 name->dos.attrib = attrib;
1231                 status = pvfs_dosattrib_save(pvfs, name, fd);
1232                 if (!NT_STATUS_IS_OK(status)) {
1233                         talloc_free(lck);
1234                         return status;
1235                 }
1236         }
1237             
1238         talloc_free(lck);
1239
1240         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1241                 io->generic.out.oplock_level  = OPLOCK_EXCLUSIVE;
1242         } else {
1243                 io->generic.out.oplock_level  = OPLOCK_NONE;
1244         }
1245         io->generic.out.file.fnum     = f->fnum;
1246         io->generic.out.create_action = stream_existed?
1247                 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1248         io->generic.out.create_time   = name->dos.create_time;
1249         io->generic.out.access_time   = name->dos.access_time;
1250         io->generic.out.write_time    = name->dos.write_time;
1251         io->generic.out.change_time   = name->dos.change_time;
1252         io->generic.out.attrib        = name->dos.attrib;
1253         io->generic.out.alloc_size    = name->dos.alloc_size;
1254         io->generic.out.size          = name->st.st_size;
1255         io->generic.out.file_type     = FILE_TYPE_DISK;
1256         io->generic.out.ipc_state     = 0;
1257         io->generic.out.is_directory  = 0;
1258
1259         /* success - keep the file handle */
1260         talloc_steal(f->pvfs, f);
1261
1262         return NT_STATUS_OK;
1263 }
1264
1265
1266 /*
1267   close a file
1268 */
1269 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1270                     struct ntvfs_request *req, union smb_close *io)
1271 {
1272         struct pvfs_state *pvfs = ntvfs->private_data;
1273         struct pvfs_file *f;
1274         struct utimbuf unix_times;
1275
1276         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1277                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1278         }
1279
1280         if (io->generic.level != RAW_CLOSE_CLOSE) {
1281                 return ntvfs_map_close(ntvfs, req, io);
1282         }
1283
1284         f = pvfs_find_fd(pvfs, req, io->close.in.file.fnum);
1285         if (!f) {
1286                 return NT_STATUS_INVALID_HANDLE;
1287         }
1288
1289         if (!null_time(io->close.in.write_time)) {
1290                 unix_times.actime = 0;
1291                 unix_times.modtime = io->close.in.write_time;
1292                 utime(f->handle->name->full_name, &unix_times);
1293         } else if (f->handle->sticky_write_time) {
1294                 unix_times.actime = 0;
1295                 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1296                 utime(f->handle->name->full_name, &unix_times);
1297         }
1298
1299         talloc_free(f);
1300
1301         return NT_STATUS_OK;
1302 }
1303
1304
1305 /*
1306   logoff - close all file descriptors open by a vuid
1307 */
1308 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1309                      struct ntvfs_request *req)
1310 {
1311         struct pvfs_state *pvfs = ntvfs->private_data;
1312         struct pvfs_file *f, *next;
1313
1314         for (f=pvfs->files.list;f;f=next) {
1315                 next = f->next;
1316                 if (f->session_info == req->session_info) {
1317                         talloc_free(f);
1318                 }
1319         }
1320
1321         return NT_STATUS_OK;
1322 }
1323
1324
1325 /*
1326   exit - close files for the current pid
1327 */
1328 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1329                    struct ntvfs_request *req)
1330 {
1331         struct pvfs_state *pvfs = ntvfs->private_data;
1332         struct pvfs_file *f, *next;
1333
1334         for (f=pvfs->files.list;f;f=next) {
1335                 next = f->next;
1336                 if (f->session_info == req->session_info &&
1337                     f->smbpid == req->smbpid) {
1338                         talloc_free(f);
1339                 }
1340         }
1341
1342         return NT_STATUS_OK;
1343 }
1344
1345
1346 /*
1347   change the delete on close flag on an already open file
1348 */
1349 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1350                                   struct ntvfs_request *req, 
1351                                   struct pvfs_file *f, BOOL del_on_close)
1352 {
1353         struct odb_lock *lck;
1354         NTSTATUS status;
1355
1356         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1357                 return NT_STATUS_CANNOT_DELETE;
1358         }
1359         
1360         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1361             !pvfs_directory_empty(pvfs, f->handle->name)) {
1362                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1363         }
1364
1365         if (del_on_close) {
1366                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1367         } else {
1368                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1369         }
1370         
1371         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1372         if (lck == NULL) {
1373                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1374         }
1375
1376         status = odb_set_delete_on_close(lck, del_on_close);
1377
1378         talloc_free(lck);
1379
1380         return status;
1381 }
1382
1383
1384 /*
1385   determine if a file can be deleted, or if it is prevented by an
1386   already open file
1387 */
1388 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1389                          struct ntvfs_request *req,
1390                          struct pvfs_filename *name,
1391                          struct odb_lock **lckp)
1392 {
1393         NTSTATUS status;
1394         DATA_BLOB key;
1395         struct odb_lock *lck;
1396
1397         status = pvfs_locking_key(name, name, &key);
1398         if (!NT_STATUS_IS_OK(status)) {
1399                 return NT_STATUS_NO_MEMORY;
1400         }
1401
1402         lck = odb_lock(req, pvfs->odb_context, &key);
1403         if (lck == NULL) {
1404                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1405                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1406         }
1407
1408         status = odb_can_open(lck,
1409                               NTCREATEX_SHARE_ACCESS_READ |
1410                               NTCREATEX_SHARE_ACCESS_WRITE | 
1411                               NTCREATEX_SHARE_ACCESS_DELETE, 
1412                               NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 
1413                               SEC_STD_DELETE);
1414
1415         if (NT_STATUS_IS_OK(status)) {
1416                 status = pvfs_access_check_simple(pvfs, req, name, SEC_STD_DELETE);
1417         }
1418
1419         if (!NT_STATUS_IS_OK(status)) {
1420                 talloc_free(lck);
1421                 *lckp = lck;
1422         } else if (lckp != NULL) {
1423                 *lckp = lck;
1424         }
1425
1426         return status;
1427 }
1428
1429 /*
1430   determine if a file can be renamed, or if it is prevented by an
1431   already open file
1432 */
1433 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1434                          struct ntvfs_request *req,
1435                          struct pvfs_filename *name,
1436                          struct odb_lock **lckp)
1437 {
1438         NTSTATUS status;
1439         DATA_BLOB key;
1440         struct odb_lock *lck;
1441
1442         status = pvfs_locking_key(name, name, &key);
1443         if (!NT_STATUS_IS_OK(status)) {
1444                 return NT_STATUS_NO_MEMORY;
1445         }
1446
1447         lck = odb_lock(req, pvfs->odb_context, &key);
1448         if (lck == NULL) {
1449                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1450                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1451         }
1452
1453         status = odb_can_open(lck,
1454                               NTCREATEX_SHARE_ACCESS_READ |
1455                               NTCREATEX_SHARE_ACCESS_WRITE,
1456                               0,
1457                               SEC_STD_DELETE);
1458
1459         if (!NT_STATUS_IS_OK(status)) {
1460                 talloc_free(lck);
1461                 *lckp = lck;
1462         } else if (lckp != NULL) {
1463                 *lckp = lck;
1464         }
1465
1466         return status;
1467 }
1468
1469 /*
1470   determine if file meta data can be accessed, or if it is prevented by an
1471   already open file
1472 */
1473 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1474                        struct ntvfs_request *req,
1475                        struct pvfs_filename *name)
1476 {
1477         NTSTATUS status;
1478         DATA_BLOB key;
1479         struct odb_lock *lck;
1480
1481         status = pvfs_locking_key(name, name, &key);
1482         if (!NT_STATUS_IS_OK(status)) {
1483                 return NT_STATUS_NO_MEMORY;
1484         }
1485
1486         lck = odb_lock(req, pvfs->odb_context, &key);
1487         if (lck == NULL) {
1488                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1489                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1490         }
1491
1492         status = odb_can_open(lck,
1493                               NTCREATEX_SHARE_ACCESS_READ |
1494                               NTCREATEX_SHARE_ACCESS_WRITE,
1495                               0, 0);
1496
1497         return status;
1498 }
1499
1500
1501 /*
1502   determine if delete on close is set on 
1503 */
1504 BOOL pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h, 
1505                               int *open_count, char **path)
1506 {
1507         NTSTATUS status;
1508         BOOL del_on_close;
1509
1510         status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
1511                                          &del_on_close, open_count, path);
1512         if (!NT_STATUS_IS_OK(status)) {
1513                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1514                 return False;
1515         }
1516
1517         return del_on_close;
1518 }