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