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