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