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