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