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