Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
[ira/wip.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, 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, 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         bool allow_level_II_oplock = false;
548
549         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
550             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
551                 return NT_STATUS_CANNOT_DELETE;
552         }
553         
554         status = pvfs_access_check_create(pvfs, req, name, &access_mask);
555         NT_STATUS_NOT_OK_RETURN(status);
556
557         /* check that the parent isn't opened with delete on close set */
558         status = pvfs_resolve_parent(pvfs, req, name, &parent);
559         if (NT_STATUS_IS_OK(status)) {
560                 DATA_BLOB locking_key;
561                 status = pvfs_locking_key(parent, req, &locking_key);
562                 NT_STATUS_NOT_OK_RETURN(status);
563                 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, 
564                                                  &del_on_close);
565                 NT_STATUS_NOT_OK_RETURN(status);
566                 if (del_on_close) {
567                         return NT_STATUS_DELETE_PENDING;
568                 }
569         }
570
571         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
572                 flags = O_RDWR;
573         } else {
574                 flags = O_RDONLY;
575         }
576
577         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
578         NT_STATUS_NOT_OK_RETURN(status);
579
580         f = talloc(h, struct pvfs_file);
581         NT_STATUS_HAVE_NO_MEMORY(f);
582
583         f->handle = talloc(f, struct pvfs_file_handle);
584         NT_STATUS_HAVE_NO_MEMORY(f->handle);
585
586         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
587         mode = pvfs_fileperms(pvfs, attrib);
588
589         /* create the file */
590         fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
591         if (fd == -1) {
592                 return pvfs_map_errno(pvfs, errno);
593         }
594
595         pvfs_xattr_unlink_hook(pvfs, name->full_name);
596
597         /* if this was a stream create then create the stream as well */
598         if (name->stream_name) {
599                 status = pvfs_stream_create(pvfs, name, fd);
600                 if (!NT_STATUS_IS_OK(status)) {
601                         close(fd);
602                         return status;
603                 }
604         }
605
606         /* re-resolve the open fd */
607         status = pvfs_resolve_name_fd(pvfs, fd, name);
608         if (!NT_STATUS_IS_OK(status)) {
609                 close(fd);
610                 return status;
611         }
612
613         name->dos.attrib = attrib;
614         status = pvfs_dosattrib_save(pvfs, name, fd);
615         if (!NT_STATUS_IS_OK(status)) {
616                 goto cleanup_delete;
617         }
618
619
620         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
621         if (!NT_STATUS_IS_OK(status)) {
622                 goto cleanup_delete;
623         }
624
625         /* form the lock context used for byte range locking and
626            opendb locking */
627         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
628         if (!NT_STATUS_IS_OK(status)) {
629                 goto cleanup_delete;
630         }
631
632         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
633         if (!NT_STATUS_IS_OK(status)) {
634                 goto cleanup_delete;
635         }
636
637         /* grab a lock on the open file record */
638         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
639         if (lck == NULL) {
640                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
641                          name->full_name));
642                 /* we were supposed to do a blocking lock, so something
643                    is badly wrong! */
644                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
645                 goto cleanup_delete;
646         }
647
648         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
649                 del_on_close = true;
650         } else {
651                 del_on_close = false;
652         }
653
654         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
655                 oplock_level = OPLOCK_NONE;
656         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
657                 oplock_level = OPLOCK_BATCH;
658         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
659                 oplock_level = OPLOCK_EXCLUSIVE;
660         }
661
662         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
663                 allow_level_II_oplock = true;
664         }
665
666         status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
667                                share_access, access_mask, del_on_close, 
668                                io->generic.in.open_disposition,
669                                false, allow_level_II_oplock,
670                                oplock_level, &oplock_granted);
671         talloc_free(lck);
672         if (!NT_STATUS_IS_OK(status)) {
673                 /* bad news, we must have hit a race - we don't delete the file
674                    here as the most likely scenario is that someone else created 
675                    the file at the same time */
676                 close(fd);
677                 return status;
678         }
679
680
681         f->ntvfs             = h;
682         f->pvfs              = pvfs;
683         f->pending_list      = NULL;
684         f->lock_count        = 0;
685         f->share_access      = io->generic.in.share_access;
686         f->access_mask       = access_mask;
687         f->impersonation     = io->generic.in.impersonation;
688         f->notify_buffer     = NULL;
689         f->search            = NULL;
690
691         f->handle->pvfs              = pvfs;
692         f->handle->name              = talloc_steal(f->handle, name);
693         f->handle->fd                = fd;
694         f->handle->create_options    = io->generic.in.create_options;
695         f->handle->seek_offset       = 0;
696         f->handle->position          = 0;
697         f->handle->mode              = 0;
698         f->handle->oplock            = NULL;
699         f->handle->have_opendb_entry = true;
700         f->handle->sticky_write_time = false;
701         f->handle->open_completed    = false;
702
703         DLIST_ADD(pvfs->files.list, f);
704
705         /* setup a destructor to avoid file descriptor leaks on
706            abnormal termination */
707         talloc_set_destructor(f, pvfs_fnum_destructor);
708         talloc_set_destructor(f->handle, pvfs_handle_destructor);
709
710         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
711                 oplock_granted = OPLOCK_BATCH;
712         } else if (oplock_granted != OPLOCK_NONE) {
713                 status = pvfs_setup_oplock(f, oplock_granted);
714                 if (!NT_STATUS_IS_OK(status)) {
715                         return status;
716                 }
717         }
718
719         io->generic.out.oplock_level  = oplock_granted;
720         io->generic.out.file.ntvfs    = f->ntvfs;
721         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
722         io->generic.out.create_time   = name->dos.create_time;
723         io->generic.out.access_time   = name->dos.access_time;
724         io->generic.out.write_time    = name->dos.write_time;
725         io->generic.out.change_time   = name->dos.change_time;
726         io->generic.out.attrib        = name->dos.attrib;
727         io->generic.out.alloc_size    = name->dos.alloc_size;
728         io->generic.out.size          = name->st.st_size;
729         io->generic.out.file_type     = FILE_TYPE_DISK;
730         io->generic.out.ipc_state     = 0;
731         io->generic.out.is_directory  = 0;
732
733         /* success - keep the file handle */
734         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
735         if (!NT_STATUS_IS_OK(status)) {
736                 goto cleanup_delete;
737         }
738
739         f->handle->open_completed = true;
740
741         notify_trigger(pvfs->notify_context, 
742                        NOTIFY_ACTION_ADDED, 
743                        FILE_NOTIFY_CHANGE_FILE_NAME,
744                        name->full_name);
745
746         return NT_STATUS_OK;
747
748 cleanup_delete:
749         close(fd);
750         unlink(name->full_name);
751         return status;
752 }
753
754 /*
755   state of a pending retry
756 */
757 struct pvfs_odb_retry {
758         struct ntvfs_module_context *ntvfs;
759         struct ntvfs_request *req;
760         DATA_BLOB odb_locking_key;
761         void *io;
762         void *private_data;
763         void (*callback)(struct pvfs_odb_retry *r,
764                          struct ntvfs_module_context *ntvfs,
765                          struct ntvfs_request *req,
766                          void *io,
767                          void *private_data,
768                          enum pvfs_wait_notice reason);
769 };
770
771 /* destroy a pending request */
772 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
773 {
774         struct pvfs_state *pvfs = r->ntvfs->private_data;
775         if (r->odb_locking_key.data) {
776                 struct odb_lock *lck;
777                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
778                 if (lck != NULL) {
779                         odb_remove_pending(lck, r);
780                 }
781                 talloc_free(lck);
782         }
783         return 0;
784 }
785
786 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
787 {
788         struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
789
790         if (reason == PVFS_WAIT_EVENT) {
791                 /*
792                  * The pending odb entry is already removed.
793                  * We use a null locking key to indicate this
794                  * to the destructor.
795                  */
796                 data_blob_free(&r->odb_locking_key);
797         }
798
799         r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
800 }
801
802 /*
803   setup for a retry of a request that was rejected
804   by odb_open_file() or odb_can_open()
805 */
806 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
807                               struct ntvfs_request *req,
808                               struct odb_lock *lck,
809                               struct timeval end_time,
810                               void *io,
811                               void *private_data,
812                               void (*callback)(struct pvfs_odb_retry *r,
813                                                struct ntvfs_module_context *ntvfs,
814                                                struct ntvfs_request *req,
815                                                void *io,
816                                                void *private_data,
817                                                enum pvfs_wait_notice reason))
818 {
819         struct pvfs_state *pvfs = ntvfs->private_data;
820         struct pvfs_odb_retry *r;
821         struct pvfs_wait *wait_handle;
822         NTSTATUS status;
823
824         r = talloc(req, struct pvfs_odb_retry);
825         NT_STATUS_HAVE_NO_MEMORY(r);
826
827         r->ntvfs = ntvfs;
828         r->req = req;
829         r->io = io;
830         r->private_data = private_data;
831         r->callback = callback;
832         r->odb_locking_key = odb_get_key(r, lck);
833         if (r->odb_locking_key.data == NULL) {
834                 return NT_STATUS_NO_MEMORY;
835         }
836
837         /* setup a pending lock */
838         status = odb_open_file_pending(lck, r);
839         if (!NT_STATUS_IS_OK(status)) {
840                 return status;
841         }
842
843         talloc_free(lck);
844
845         talloc_set_destructor(r, pvfs_odb_retry_destructor);
846
847         wait_handle = pvfs_wait_message(pvfs, req,
848                                         MSG_PVFS_RETRY_OPEN, end_time,
849                                         pvfs_odb_retry_callback, r);
850         if (wait_handle == NULL) {
851                 return NT_STATUS_NO_MEMORY;
852         }
853
854         talloc_steal(r, wait_handle);
855
856         talloc_steal(pvfs, r);
857
858         return NT_STATUS_OK;
859 }
860
861 /*
862   retry an open after a sharing violation
863 */
864 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
865                                     struct ntvfs_module_context *ntvfs,
866                                     struct ntvfs_request *req,
867                                     void *_io,
868                                     void *private_data,
869                                     enum pvfs_wait_notice reason)
870 {
871         union smb_open *io = talloc_get_type(_io, union smb_open);
872         NTSTATUS status;
873
874         /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
875            just a bug in their server, but we better do the same */
876         if (reason == PVFS_WAIT_CANCEL) {
877                 return;
878         }
879
880         if (reason == PVFS_WAIT_TIMEOUT) {
881                 /* if it timed out, then give the failure
882                    immediately */
883                 talloc_free(r);
884                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
885                 req->async_states->send_fn(req);
886                 return;
887         }
888
889         talloc_free(r);
890
891         /* try the open again, which could trigger another retry setup
892            if it wants to, so we have to unmark the async flag so we
893            will know if it does a second async reply */
894         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
895
896         status = pvfs_open(ntvfs, req, io);
897         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
898                 /* the 2nd try also replied async, so we don't send
899                    the reply yet */
900                 return;
901         }
902
903         /* re-mark it async, just in case someone up the chain does
904            paranoid checking */
905         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
906
907         /* send the reply up the chain */
908         req->async_states->status = status;
909         req->async_states->send_fn(req);
910 }
911
912
913 /*
914   special handling for openx DENY_DOS semantics
915
916   This function attempts a reference open using an existing handle. If its allowed,
917   then it returns NT_STATUS_OK, otherwise it returns any other code and normal
918   open processing continues.
919 */
920 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
921                                    struct ntvfs_request *req, union smb_open *io,
922                                    struct pvfs_file *f, struct odb_lock *lck)
923 {
924         struct pvfs_state *pvfs = ntvfs->private_data;
925         struct pvfs_file *f2;
926         struct pvfs_filename *name;
927         NTSTATUS status;
928
929         /* search for an existing open with the right parameters. Note
930            the magic ntcreatex options flag, which is set in the
931            generic mapping code. This might look ugly, but its
932            actually pretty much now w2k does it internally as well. 
933            
934            If you look at the BASE-DENYDOS test you will see that a
935            DENY_DOS is a very special case, and in the right
936            circumstances you actually get the _same_ handle back
937            twice, rather than a new handle.
938         */
939         for (f2=pvfs->files.list;f2;f2=f2->next) {
940                 if (f2 != f &&
941                     f2->ntvfs->session_info == req->session_info &&
942                     f2->ntvfs->smbpid == req->smbpid &&
943                     (f2->handle->create_options & 
944                      (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
945                       NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
946                     (f2->access_mask & SEC_FILE_WRITE_DATA) &&
947                     strcasecmp_m(f2->handle->name->original_name, 
948                                io->generic.in.fname)==0) {
949                         break;
950                 }
951         }
952
953         if (!f2) {
954                 return NT_STATUS_SHARING_VIOLATION;
955         }
956
957         /* quite an insane set of semantics ... */
958         if (is_exe_filename(io->generic.in.fname) &&
959             (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
960                 return NT_STATUS_SHARING_VIOLATION;
961         }
962
963         /*
964           setup a reference to the existing handle
965          */
966         talloc_free(f->handle);
967         f->handle = talloc_reference(f, f2->handle);
968
969         talloc_free(lck);
970
971         name = f->handle->name;
972
973         io->generic.out.oplock_level  = OPLOCK_NONE;
974         io->generic.out.file.ntvfs    = f->ntvfs;
975         io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
976         io->generic.out.create_time   = name->dos.create_time;
977         io->generic.out.access_time   = name->dos.access_time;
978         io->generic.out.write_time    = name->dos.write_time;
979         io->generic.out.change_time   = name->dos.change_time;
980         io->generic.out.attrib        = name->dos.attrib;
981         io->generic.out.alloc_size    = name->dos.alloc_size;
982         io->generic.out.size          = name->st.st_size;
983         io->generic.out.file_type     = FILE_TYPE_DISK;
984         io->generic.out.ipc_state     = 0;
985         io->generic.out.is_directory  = 0;
986  
987         status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
988         NT_STATUS_NOT_OK_RETURN(status);
989
990         return NT_STATUS_OK;
991 }
992
993
994
995 /*
996   setup for a open retry after a sharing violation
997 */
998 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
999                                       struct ntvfs_request *req, 
1000                                       union smb_open *io,
1001                                       struct pvfs_file *f,
1002                                       struct odb_lock *lck,
1003                                       NTSTATUS parent_status)
1004 {
1005         struct pvfs_state *pvfs = ntvfs->private_data;
1006         NTSTATUS status;
1007         struct timeval end_time;
1008
1009         if (io->generic.in.create_options & 
1010             (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1011                 /* see if we can satisfy the request using the special DENY_DOS
1012                    code */
1013                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1014                 if (NT_STATUS_IS_OK(status)) {
1015                         return status;
1016                 }
1017         }
1018
1019         /* the retry should allocate a new file handle */
1020         talloc_free(f);
1021
1022         if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1023                 end_time = timeval_add(&req->statistics.request_time,
1024                                        0, pvfs->sharing_violation_delay);
1025         } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1026                 end_time = timeval_add(&req->statistics.request_time,
1027                                        pvfs->oplock_break_timeout, 0);
1028         } else {
1029                 return NT_STATUS_INTERNAL_ERROR;
1030         }
1031
1032         return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
1033                                     pvfs_retry_open_sharing);
1034 }
1035
1036 /*
1037   open a file
1038 */
1039 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1040                    struct ntvfs_request *req, union smb_open *io)
1041 {
1042         struct pvfs_state *pvfs = ntvfs->private_data;
1043         int flags;
1044         struct pvfs_filename *name;
1045         struct pvfs_file *f;
1046         struct ntvfs_handle *h;
1047         NTSTATUS status;
1048         int fd;
1049         struct odb_lock *lck;
1050         uint32_t create_options;
1051         uint32_t share_access;
1052         uint32_t access_mask;
1053         bool del_on_close;
1054         bool stream_existed, stream_truncate=false;
1055         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1056         bool allow_level_II_oplock = false;
1057
1058         /* use the generic mapping code to avoid implementing all the
1059            different open calls. */
1060         if (io->generic.level != RAW_OPEN_GENERIC &&
1061             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1062                 return ntvfs_map_open(ntvfs, req, io);
1063         }
1064
1065         /* resolve the cifs name to a posix name */
1066         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
1067                                    PVFS_RESOLVE_STREAMS, &name);
1068         if (!NT_STATUS_IS_OK(status)) {
1069                 return status;
1070         }
1071
1072         /* directory opens are handled separately */
1073         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1074             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1075                 return pvfs_open_directory(pvfs, req, name, io);
1076         }
1077
1078         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1079            open doesn't match */
1080         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1081
1082         create_options = io->generic.in.create_options;
1083         share_access   = io->generic.in.share_access;
1084         access_mask    = io->generic.in.access_mask;
1085
1086         /* certain create options are not allowed */
1087         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1088             !(access_mask & SEC_STD_DELETE)) {
1089                 return NT_STATUS_INVALID_PARAMETER;
1090         }
1091
1092         flags = 0;
1093
1094         switch (io->generic.in.open_disposition) {
1095         case NTCREATEX_DISP_SUPERSEDE:
1096         case NTCREATEX_DISP_OVERWRITE_IF:
1097                 if (name->stream_name == NULL) {
1098                         flags = O_TRUNC;
1099                 } else {
1100                         stream_truncate = true;
1101                 }
1102                 break;
1103
1104         case NTCREATEX_DISP_OPEN:
1105                 if (!name->stream_exists) {
1106                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1107                 }
1108                 flags = 0;
1109                 break;
1110
1111         case NTCREATEX_DISP_OVERWRITE:
1112                 if (!name->stream_exists) {
1113                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1114                 }
1115                 if (name->stream_name == NULL) {
1116                         flags = O_TRUNC;
1117                 } else {
1118                         stream_truncate = true;
1119                 }
1120                 break;
1121
1122         case NTCREATEX_DISP_CREATE:
1123                 if (name->stream_exists) {
1124                         return NT_STATUS_OBJECT_NAME_COLLISION;
1125                 }
1126                 flags = 0;
1127                 break;
1128
1129         case NTCREATEX_DISP_OPEN_IF:
1130                 flags = 0;
1131                 break;
1132
1133         default:
1134                 return NT_STATUS_INVALID_PARAMETER;
1135         }
1136
1137         /* handle creating a new file separately */
1138         if (!name->exists) {
1139                 status = pvfs_create_file(pvfs, req, name, io);
1140                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1141                         return status;
1142                 }
1143
1144                 /* we've hit a race - the file was created during this call */
1145                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1146                         return status;
1147                 }
1148
1149                 /* try re-resolving the name */
1150                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1151                 if (!NT_STATUS_IS_OK(status)) {
1152                         return status;
1153                 }
1154                 /* fall through to a normal open */
1155         }
1156
1157         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1158             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1159                 return NT_STATUS_CANNOT_DELETE;
1160         }
1161
1162         /* check the security descriptor */
1163         status = pvfs_access_check(pvfs, req, name, &access_mask);
1164         if (!NT_STATUS_IS_OK(status)) {
1165                 return status;
1166         }
1167
1168         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1169         NT_STATUS_NOT_OK_RETURN(status);
1170
1171         f = talloc(h, struct pvfs_file);
1172         if (f == NULL) {
1173                 return NT_STATUS_NO_MEMORY;
1174         }
1175
1176         f->handle = talloc(f, struct pvfs_file_handle);
1177         if (f->handle == NULL) {
1178                 return NT_STATUS_NO_MEMORY;
1179         }
1180
1181         f->ntvfs         = h;
1182         f->pvfs          = pvfs;
1183         f->pending_list  = NULL;
1184         f->lock_count    = 0;
1185         f->share_access  = io->generic.in.share_access;
1186         f->access_mask   = access_mask;
1187         f->impersonation = io->generic.in.impersonation;
1188         f->notify_buffer = NULL;
1189         f->search        = NULL;
1190
1191         f->handle->pvfs              = pvfs;
1192         f->handle->fd                = -1;
1193         f->handle->name              = talloc_steal(f->handle, name);
1194         f->handle->create_options    = io->generic.in.create_options;
1195         f->handle->seek_offset       = 0;
1196         f->handle->position          = 0;
1197         f->handle->mode              = 0;
1198         f->handle->oplock            = NULL;
1199         f->handle->have_opendb_entry = false;
1200         f->handle->sticky_write_time = false;
1201         f->handle->open_completed    = false;
1202
1203         /* form the lock context used for byte range locking and
1204            opendb locking */
1205         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1206         if (!NT_STATUS_IS_OK(status)) {
1207                 return status;
1208         }
1209
1210         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1211         if (!NT_STATUS_IS_OK(status)) {
1212                 return status;
1213         }
1214
1215         /* get a lock on this file before the actual open */
1216         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1217         if (lck == NULL) {
1218                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1219                          name->full_name));
1220                 /* we were supposed to do a blocking lock, so something
1221                    is badly wrong! */
1222                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1223         }
1224
1225         DLIST_ADD(pvfs->files.list, f);
1226
1227         /* setup a destructor to avoid file descriptor leaks on
1228            abnormal termination */
1229         talloc_set_destructor(f, pvfs_fnum_destructor);
1230         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1231
1232         /* 
1233          * Only SMB2 takes care of the delete_on_close,
1234          * on existing files
1235          */
1236         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1237             req->ctx->protocol == PROTOCOL_SMB2) {
1238                 del_on_close = true;
1239         } else {
1240                 del_on_close = false;
1241         }
1242
1243         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1244                 oplock_level = OPLOCK_NONE;
1245         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1246                 oplock_level = OPLOCK_BATCH;
1247         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1248                 oplock_level = OPLOCK_EXCLUSIVE;
1249         }
1250
1251         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1252                 allow_level_II_oplock = true;
1253         }
1254
1255         /* see if we are allowed to open at the same time as existing opens */
1256         status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1257                                share_access, access_mask, del_on_close,
1258                                io->generic.in.open_disposition,
1259                                false, allow_level_II_oplock,
1260                                oplock_level, &oplock_granted);
1261
1262         /*
1263          * on a sharing violation we need to retry when the file is closed by
1264          * the other user, or after 1 second
1265          * on a non granted oplock we need to retry when the file is closed by
1266          * the other user, or after 30 seconds
1267         */
1268         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1269              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1270             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1271                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1272         }
1273
1274         if (!NT_STATUS_IS_OK(status)) {
1275                 talloc_free(lck);
1276                 return status;
1277         }
1278
1279         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1280                 oplock_granted = OPLOCK_BATCH;
1281         } else if (oplock_granted != OPLOCK_NONE) {
1282                 status = pvfs_setup_oplock(f, oplock_granted);
1283                 if (!NT_STATUS_IS_OK(status)) {
1284                         talloc_free(lck);
1285                         return status;
1286                 }
1287         }
1288
1289         f->handle->have_opendb_entry = true;
1290
1291         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1292                 flags |= O_RDWR;
1293         } else {
1294                 flags |= O_RDONLY;
1295         }
1296
1297         /* do the actual open */
1298         fd = open(f->handle->name->full_name, flags);
1299         if (fd == -1) {
1300                 talloc_free(lck);
1301                 return pvfs_map_errno(f->pvfs, errno);
1302         }
1303
1304         f->handle->fd = fd;
1305
1306         stream_existed = name->stream_exists;
1307
1308         /* if this was a stream create then create the stream as well */
1309         if (!name->stream_exists) {
1310                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1311                 if (!NT_STATUS_IS_OK(status)) {
1312                         talloc_free(lck);
1313                         return status;
1314                 }
1315                 if (stream_truncate) {
1316                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1317                         if (!NT_STATUS_IS_OK(status)) {
1318                                 talloc_free(lck);
1319                                 return status;
1320                         }
1321                 }
1322         }
1323
1324         /* re-resolve the open fd */
1325         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1326         if (!NT_STATUS_IS_OK(status)) {
1327                 talloc_free(lck);
1328                 return status;
1329         }
1330
1331         if (f->handle->name->stream_id == 0 &&
1332             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1333              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1334                 /* for overwrite we need to replace file permissions */
1335                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1336                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1337                 if (fchmod(fd, mode) == -1) {
1338                         talloc_free(lck);
1339                         return pvfs_map_errno(pvfs, errno);
1340                 }
1341                 name->dos.attrib = attrib;
1342                 status = pvfs_dosattrib_save(pvfs, name, fd);
1343                 if (!NT_STATUS_IS_OK(status)) {
1344                         talloc_free(lck);
1345                         return status;
1346                 }
1347         }
1348             
1349         talloc_free(lck);
1350
1351         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1352         NT_STATUS_NOT_OK_RETURN(status);
1353
1354         /* mark the open as having completed fully, so delete on close
1355            can now be used */
1356         f->handle->open_completed     = true;
1357
1358         io->generic.out.oplock_level  = oplock_granted;
1359         io->generic.out.file.ntvfs    = h;
1360         io->generic.out.create_action = stream_existed?
1361                 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1362         io->generic.out.create_time   = name->dos.create_time;
1363         io->generic.out.access_time   = name->dos.access_time;
1364         io->generic.out.write_time    = name->dos.write_time;
1365         io->generic.out.change_time   = name->dos.change_time;
1366         io->generic.out.attrib        = name->dos.attrib;
1367         io->generic.out.alloc_size    = name->dos.alloc_size;
1368         io->generic.out.size          = name->st.st_size;
1369         io->generic.out.file_type     = FILE_TYPE_DISK;
1370         io->generic.out.ipc_state     = 0;
1371         io->generic.out.is_directory  = 0;
1372
1373         return NT_STATUS_OK;
1374 }
1375
1376
1377 /*
1378   close a file
1379 */
1380 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1381                     struct ntvfs_request *req, union smb_close *io)
1382 {
1383         struct pvfs_state *pvfs = ntvfs->private_data;
1384         struct pvfs_file *f;
1385         struct utimbuf unix_times;
1386
1387         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1388                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1389         }
1390
1391         if (io->generic.level != RAW_CLOSE_CLOSE) {
1392                 return ntvfs_map_close(ntvfs, req, io);
1393         }
1394
1395         f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1396         if (!f) {
1397                 return NT_STATUS_INVALID_HANDLE;
1398         }
1399
1400         if (!null_time(io->close.in.write_time)) {
1401                 unix_times.actime = 0;
1402                 unix_times.modtime = io->close.in.write_time;
1403                 utime(f->handle->name->full_name, &unix_times);
1404         } else if (f->handle->sticky_write_time) {
1405                 unix_times.actime = 0;
1406                 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1407                 utime(f->handle->name->full_name, &unix_times);
1408         }
1409
1410         talloc_free(f);
1411
1412         return NT_STATUS_OK;
1413 }
1414
1415
1416 /*
1417   logoff - close all file descriptors open by a vuid
1418 */
1419 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1420                      struct ntvfs_request *req)
1421 {
1422         struct pvfs_state *pvfs = ntvfs->private_data;
1423         struct pvfs_file *f, *next;
1424
1425         for (f=pvfs->files.list;f;f=next) {
1426                 next = f->next;
1427                 if (f->ntvfs->session_info == req->session_info) {
1428                         talloc_free(f);
1429                 }
1430         }
1431
1432         return NT_STATUS_OK;
1433 }
1434
1435
1436 /*
1437   exit - close files for the current pid
1438 */
1439 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1440                    struct ntvfs_request *req)
1441 {
1442         struct pvfs_state *pvfs = ntvfs->private_data;
1443         struct pvfs_file *f, *next;
1444
1445         for (f=pvfs->files.list;f;f=next) {
1446                 next = f->next;
1447                 if (f->ntvfs->session_info == req->session_info &&
1448                     f->ntvfs->smbpid == req->smbpid) {
1449                         talloc_free(f);
1450                 }
1451         }
1452
1453         return NT_STATUS_OK;
1454 }
1455
1456
1457 /*
1458   change the delete on close flag on an already open file
1459 */
1460 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1461                                   struct ntvfs_request *req, 
1462                                   struct pvfs_file *f, bool del_on_close)
1463 {
1464         struct odb_lock *lck;
1465         NTSTATUS status;
1466
1467         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1468                 return NT_STATUS_CANNOT_DELETE;
1469         }
1470         
1471         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1472             !pvfs_directory_empty(pvfs, f->handle->name)) {
1473                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1474         }
1475
1476         if (del_on_close) {
1477                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1478         } else {
1479                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1480         }
1481         
1482         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1483         if (lck == NULL) {
1484                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1485         }
1486
1487         status = odb_set_delete_on_close(lck, del_on_close);
1488
1489         talloc_free(lck);
1490
1491         return status;
1492 }
1493
1494
1495 /*
1496   determine if a file can be deleted, or if it is prevented by an
1497   already open file
1498 */
1499 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1500                          struct ntvfs_request *req,
1501                          struct pvfs_filename *name,
1502                          struct odb_lock **lckp)
1503 {
1504         NTSTATUS status;
1505         DATA_BLOB key;
1506         struct odb_lock *lck;
1507         uint32_t share_access;
1508         uint32_t access_mask;
1509         bool delete_on_close;
1510
1511         status = pvfs_locking_key(name, name, &key);
1512         if (!NT_STATUS_IS_OK(status)) {
1513                 return NT_STATUS_NO_MEMORY;
1514         }
1515
1516         lck = odb_lock(req, pvfs->odb_context, &key);
1517         if (lck == NULL) {
1518                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1519                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1520         }
1521
1522         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1523                           NTCREATEX_SHARE_ACCESS_WRITE |
1524                           NTCREATEX_SHARE_ACCESS_DELETE;
1525         access_mask     = SEC_STD_DELETE;
1526         delete_on_close = true;
1527
1528         status = odb_can_open(lck, name->stream_id,
1529                               share_access, access_mask, delete_on_close,
1530                               NTCREATEX_DISP_OPEN, false);
1531
1532         if (NT_STATUS_IS_OK(status)) {
1533                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1534         }
1535
1536         /*
1537          * if it's a sharing violation or we got no oplock
1538          * only keep the lock if the caller requested access
1539          * to the lock
1540          */
1541         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1542             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1543                 if (lckp) {
1544                         *lckp = lck;
1545                 } else {
1546                         talloc_free(lck);
1547                 }
1548         } else if (!NT_STATUS_IS_OK(status)) {
1549                 talloc_free(lck);
1550                 if (lckp) {
1551                         *lckp = NULL;
1552                 }
1553         } else if (lckp) {
1554                 *lckp = lck;
1555         }
1556
1557         return status;
1558 }
1559
1560 /*
1561   determine if a file can be renamed, or if it is prevented by an
1562   already open file
1563 */
1564 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1565                          struct ntvfs_request *req,
1566                          struct pvfs_filename *name,
1567                          struct odb_lock **lckp)
1568 {
1569         NTSTATUS status;
1570         DATA_BLOB key;
1571         struct odb_lock *lck;
1572         uint32_t share_access;
1573         uint32_t access_mask;
1574         bool delete_on_close;
1575
1576         status = pvfs_locking_key(name, name, &key);
1577         if (!NT_STATUS_IS_OK(status)) {
1578                 return NT_STATUS_NO_MEMORY;
1579         }
1580
1581         lck = odb_lock(req, pvfs->odb_context, &key);
1582         if (lck == NULL) {
1583                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1584                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1585         }
1586
1587         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1588                           NTCREATEX_SHARE_ACCESS_WRITE;
1589         access_mask     = SEC_STD_DELETE;
1590         delete_on_close = false;
1591
1592         status = odb_can_open(lck, name->stream_id,
1593                               share_access, access_mask, delete_on_close,
1594                               NTCREATEX_DISP_OPEN, false);
1595
1596         /*
1597          * if it's a sharing violation or we got no oplock
1598          * only keep the lock if the caller requested access
1599          * to the lock
1600          */
1601         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1602             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1603                 if (lckp) {
1604                         *lckp = lck;
1605                 } else {
1606                         talloc_free(lck);
1607                 }
1608         } else if (!NT_STATUS_IS_OK(status)) {
1609                 talloc_free(lck);
1610                 if (lckp) {
1611                         *lckp = NULL;
1612                 }
1613         } else if (lckp) {
1614                 *lckp = lck;
1615         }
1616
1617         return status;
1618 }
1619
1620 /*
1621   determine if the file size of a file can be changed,
1622   or if it is prevented by an already open file
1623 */
1624 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1625                                    struct ntvfs_request *req,
1626                                    struct pvfs_filename *name,
1627                                    struct odb_lock **lckp)
1628 {
1629         NTSTATUS status;
1630         DATA_BLOB key;
1631         struct odb_lock *lck;
1632         uint32_t share_access;
1633         uint32_t access_mask;
1634         bool break_to_none;
1635         bool delete_on_close;
1636
1637         status = pvfs_locking_key(name, name, &key);
1638         if (!NT_STATUS_IS_OK(status)) {
1639                 return NT_STATUS_NO_MEMORY;
1640         }
1641
1642         lck = odb_lock(req, pvfs->odb_context, &key);
1643         if (lck == NULL) {
1644                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1645                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1646         }
1647
1648         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1649                           NTCREATEX_SHARE_ACCESS_WRITE |
1650                           NTCREATEX_SHARE_ACCESS_DELETE;
1651         /*
1652          * I would have thought that we would need to pass
1653          * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1654          *
1655          * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1656          * to set the filesize.
1657          *
1658          * --metze
1659          */
1660         access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
1661         delete_on_close = false;
1662         break_to_none   = true;
1663
1664         status = odb_can_open(lck, name->stream_id,
1665                               share_access, access_mask, delete_on_close,
1666                               NTCREATEX_DISP_OPEN, break_to_none);
1667
1668         /*
1669          * if it's a sharing violation or we got no oplock
1670          * only keep the lock if the caller requested access
1671          * to the lock
1672          */
1673         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1674             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1675                 if (lckp) {
1676                         *lckp = lck;
1677                 } else {
1678                         talloc_free(lck);
1679                 }
1680         } else if (!NT_STATUS_IS_OK(status)) {
1681                 talloc_free(lck);
1682                 if (lckp) {
1683                         *lckp = NULL;
1684                 }
1685         } else if (lckp) {
1686                 *lckp = lck;
1687         }
1688
1689         return status;
1690 }
1691
1692 /*
1693   determine if file meta data can be accessed, or if it is prevented by an
1694   already open file
1695 */
1696 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1697                        struct ntvfs_request *req,
1698                        struct pvfs_filename *name)
1699 {
1700         NTSTATUS status;
1701         DATA_BLOB key;
1702         struct odb_lock *lck;
1703         uint32_t share_access;
1704         uint32_t access_mask;
1705         bool delete_on_close;
1706
1707         status = pvfs_locking_key(name, name, &key);
1708         if (!NT_STATUS_IS_OK(status)) {
1709                 return NT_STATUS_NO_MEMORY;
1710         }
1711
1712         lck = odb_lock(req, pvfs->odb_context, &key);
1713         if (lck == NULL) {
1714                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1715                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1716         }
1717
1718         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1719                           NTCREATEX_SHARE_ACCESS_WRITE;
1720         access_mask     = SEC_FILE_READ_ATTRIBUTE;
1721         delete_on_close = false;
1722
1723         status = odb_can_open(lck, name->stream_id,
1724                               share_access, access_mask, delete_on_close,
1725                               NTCREATEX_DISP_OPEN, false);
1726
1727         if (!NT_STATUS_IS_OK(status)) {
1728                 talloc_free(lck);
1729         }
1730
1731         return status;
1732 }
1733
1734
1735 /*
1736   determine if delete on close is set on 
1737 */
1738 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1739 {
1740         NTSTATUS status;
1741         bool del_on_close;
1742
1743         status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
1744                                          &del_on_close);
1745         if (!NT_STATUS_IS_OK(status)) {
1746                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1747                 return false;
1748         }
1749
1750         return del_on_close;
1751 }