pvfs_open: call pvfs_setup_oplock() if an oplock was granted
[tprouty/samba.git] / source4 / ntvfs / posix / pvfs_open.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - open and close
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 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 {
1013         struct pvfs_state *pvfs = ntvfs->private_data;
1014         NTSTATUS status;
1015         struct timeval end_time;
1016
1017         if (io->generic.in.create_options & 
1018             (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1019                 /* see if we can satisfy the request using the special DENY_DOS
1020                    code */
1021                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1022                 if (NT_STATUS_IS_OK(status)) {
1023                         return status;
1024                 }
1025         }
1026
1027         /* the retry should allocate a new file handle */
1028         talloc_free(f);
1029
1030         end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
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
1057         /* use the generic mapping code to avoid implementing all the
1058            different open calls. */
1059         if (io->generic.level != RAW_OPEN_GENERIC &&
1060             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1061                 return ntvfs_map_open(ntvfs, req, io);
1062         }
1063
1064         /* resolve the cifs name to a posix name */
1065         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
1066                                    PVFS_RESOLVE_STREAMS, &name);
1067         if (!NT_STATUS_IS_OK(status)) {
1068                 return status;
1069         }
1070
1071         /* directory opens are handled separately */
1072         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1073             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1074                 return pvfs_open_directory(pvfs, req, name, io);
1075         }
1076
1077         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1078            open doesn't match */
1079         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1080
1081         create_options = io->generic.in.create_options;
1082         share_access   = io->generic.in.share_access;
1083         access_mask    = io->generic.in.access_mask;
1084
1085         /* certain create options are not allowed */
1086         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1087             !(access_mask & SEC_STD_DELETE)) {
1088                 return NT_STATUS_INVALID_PARAMETER;
1089         }
1090
1091         flags = 0;
1092
1093         switch (io->generic.in.open_disposition) {
1094         case NTCREATEX_DISP_SUPERSEDE:
1095         case NTCREATEX_DISP_OVERWRITE_IF:
1096                 if (name->stream_name == NULL) {
1097                         flags = O_TRUNC;
1098                 } else {
1099                         stream_truncate = true;
1100                 }
1101                 break;
1102
1103         case NTCREATEX_DISP_OPEN:
1104                 if (!name->stream_exists) {
1105                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1106                 }
1107                 flags = 0;
1108                 break;
1109
1110         case NTCREATEX_DISP_OVERWRITE:
1111                 if (!name->stream_exists) {
1112                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1113                 }
1114                 if (name->stream_name == NULL) {
1115                         flags = O_TRUNC;
1116                 } else {
1117                         stream_truncate = true;
1118                 }
1119                 break;
1120
1121         case NTCREATEX_DISP_CREATE:
1122                 if (name->stream_exists) {
1123                         return NT_STATUS_OBJECT_NAME_COLLISION;
1124                 }
1125                 flags = 0;
1126                 break;
1127
1128         case NTCREATEX_DISP_OPEN_IF:
1129                 flags = 0;
1130                 break;
1131
1132         default:
1133                 return NT_STATUS_INVALID_PARAMETER;
1134         }
1135
1136         /* handle creating a new file separately */
1137         if (!name->exists) {
1138                 status = pvfs_create_file(pvfs, req, name, io);
1139                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1140                         return status;
1141                 }
1142
1143                 /* we've hit a race - the file was created during this call */
1144                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1145                         return status;
1146                 }
1147
1148                 /* try re-resolving the name */
1149                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1150                 if (!NT_STATUS_IS_OK(status)) {
1151                         return status;
1152                 }
1153                 /* fall through to a normal open */
1154         }
1155
1156         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1157             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1158                 return NT_STATUS_CANNOT_DELETE;
1159         }
1160
1161         /* check the security descriptor */
1162         status = pvfs_access_check(pvfs, req, name, &access_mask);
1163         if (!NT_STATUS_IS_OK(status)) {
1164                 return status;
1165         }
1166
1167         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1168         NT_STATUS_NOT_OK_RETURN(status);
1169
1170         f = talloc(h, struct pvfs_file);
1171         if (f == NULL) {
1172                 return NT_STATUS_NO_MEMORY;
1173         }
1174
1175         f->handle = talloc(f, struct pvfs_file_handle);
1176         if (f->handle == NULL) {
1177                 return NT_STATUS_NO_MEMORY;
1178         }
1179
1180         f->ntvfs         = h;
1181         f->pvfs          = pvfs;
1182         f->pending_list  = NULL;
1183         f->lock_count    = 0;
1184         f->share_access  = io->generic.in.share_access;
1185         f->access_mask   = access_mask;
1186         f->impersonation = io->generic.in.impersonation;
1187         f->notify_buffer = NULL;
1188         f->search        = NULL;
1189
1190         f->handle->pvfs              = pvfs;
1191         f->handle->fd                = -1;
1192         f->handle->name              = talloc_steal(f->handle, name);
1193         f->handle->create_options    = io->generic.in.create_options;
1194         f->handle->seek_offset       = 0;
1195         f->handle->position          = 0;
1196         f->handle->mode              = 0;
1197         f->handle->oplock            = NULL;
1198         f->handle->have_opendb_entry = false;
1199         f->handle->sticky_write_time = false;
1200         f->handle->open_completed    = false;
1201
1202         /* form the lock context used for byte range locking and
1203            opendb locking */
1204         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1205         if (!NT_STATUS_IS_OK(status)) {
1206                 return status;
1207         }
1208
1209         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1210         if (!NT_STATUS_IS_OK(status)) {
1211                 return status;
1212         }
1213
1214         /* get a lock on this file before the actual open */
1215         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1216         if (lck == NULL) {
1217                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1218                          name->full_name));
1219                 /* we were supposed to do a blocking lock, so something
1220                    is badly wrong! */
1221                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1222         }
1223
1224         DLIST_ADD(pvfs->files.list, f);
1225
1226         /* setup a destructor to avoid file descriptor leaks on
1227            abnormal termination */
1228         talloc_set_destructor(f, pvfs_fnum_destructor);
1229         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1230
1231         /* 
1232          * Only SMB2 takes care of the delete_on_close,
1233          * on existing files
1234          */
1235         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1236             req->ctx->protocol == PROTOCOL_SMB2) {
1237                 del_on_close = true;
1238         } else {
1239                 del_on_close = false;
1240         }
1241
1242         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1243                 oplock_level = OPLOCK_NONE;
1244         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1245                 oplock_level = OPLOCK_BATCH;
1246         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1247                 oplock_level = OPLOCK_EXCLUSIVE;
1248         }
1249
1250         /* see if we are allowed to open at the same time as existing opens */
1251         status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1252                                share_access, access_mask, del_on_close,
1253                                io->generic.in.open_disposition,
1254                                false, oplock_level, &oplock_granted);
1255
1256         /* on a sharing violation we need to retry when the file is closed by 
1257            the other user, or after 1 second */
1258         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1259             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1260                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1261         }
1262
1263         if (!NT_STATUS_IS_OK(status)) {
1264                 talloc_free(lck);
1265                 return status;
1266         }
1267
1268         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1269                 oplock_granted = OPLOCK_BATCH;
1270         } else if (oplock_granted != OPLOCK_NONE) {
1271                 status = pvfs_setup_oplock(f, oplock_granted);
1272                 if (!NT_STATUS_IS_OK(status)) {
1273                         talloc_free(lck);
1274                         return status;
1275                 }
1276         }
1277
1278         f->handle->have_opendb_entry = true;
1279
1280         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1281                 flags |= O_RDWR;
1282         } else {
1283                 flags |= O_RDONLY;
1284         }
1285
1286         /* do the actual open */
1287         fd = open(f->handle->name->full_name, flags);
1288         if (fd == -1) {
1289                 talloc_free(lck);
1290                 return pvfs_map_errno(f->pvfs, errno);
1291         }
1292
1293         f->handle->fd = fd;
1294
1295         stream_existed = name->stream_exists;
1296
1297         /* if this was a stream create then create the stream as well */
1298         if (!name->stream_exists) {
1299                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1300                 if (!NT_STATUS_IS_OK(status)) {
1301                         talloc_free(lck);
1302                         return status;
1303                 }
1304                 if (stream_truncate) {
1305                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1306                         if (!NT_STATUS_IS_OK(status)) {
1307                                 talloc_free(lck);
1308                                 return status;
1309                         }
1310                 }
1311         }
1312
1313         /* re-resolve the open fd */
1314         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1315         if (!NT_STATUS_IS_OK(status)) {
1316                 talloc_free(lck);
1317                 return status;
1318         }
1319
1320         if (f->handle->name->stream_id == 0 &&
1321             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1322              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1323                 /* for overwrite we need to replace file permissions */
1324                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1325                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1326                 if (fchmod(fd, mode) == -1) {
1327                         talloc_free(lck);
1328                         return pvfs_map_errno(pvfs, errno);
1329                 }
1330                 name->dos.attrib = attrib;
1331                 status = pvfs_dosattrib_save(pvfs, name, fd);
1332                 if (!NT_STATUS_IS_OK(status)) {
1333                         talloc_free(lck);
1334                         return status;
1335                 }
1336         }
1337             
1338         talloc_free(lck);
1339
1340         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1341         NT_STATUS_NOT_OK_RETURN(status);
1342
1343         /* mark the open as having completed fully, so delete on close
1344            can now be used */
1345         f->handle->open_completed     = true;
1346
1347         io->generic.out.oplock_level  = oplock_granted;
1348         io->generic.out.file.ntvfs    = h;
1349         io->generic.out.create_action = stream_existed?
1350                 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1351         io->generic.out.create_time   = name->dos.create_time;
1352         io->generic.out.access_time   = name->dos.access_time;
1353         io->generic.out.write_time    = name->dos.write_time;
1354         io->generic.out.change_time   = name->dos.change_time;
1355         io->generic.out.attrib        = name->dos.attrib;
1356         io->generic.out.alloc_size    = name->dos.alloc_size;
1357         io->generic.out.size          = name->st.st_size;
1358         io->generic.out.file_type     = FILE_TYPE_DISK;
1359         io->generic.out.ipc_state     = 0;
1360         io->generic.out.is_directory  = 0;
1361
1362         return NT_STATUS_OK;
1363 }
1364
1365
1366 /*
1367   close a file
1368 */
1369 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1370                     struct ntvfs_request *req, union smb_close *io)
1371 {
1372         struct pvfs_state *pvfs = ntvfs->private_data;
1373         struct pvfs_file *f;
1374         struct utimbuf unix_times;
1375
1376         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1377                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1378         }
1379
1380         if (io->generic.level != RAW_CLOSE_CLOSE) {
1381                 return ntvfs_map_close(ntvfs, req, io);
1382         }
1383
1384         f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1385         if (!f) {
1386                 return NT_STATUS_INVALID_HANDLE;
1387         }
1388
1389         if (!null_time(io->close.in.write_time)) {
1390                 unix_times.actime = 0;
1391                 unix_times.modtime = io->close.in.write_time;
1392                 utime(f->handle->name->full_name, &unix_times);
1393         } else if (f->handle->sticky_write_time) {
1394                 unix_times.actime = 0;
1395                 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1396                 utime(f->handle->name->full_name, &unix_times);
1397         }
1398
1399         talloc_free(f);
1400
1401         return NT_STATUS_OK;
1402 }
1403
1404
1405 /*
1406   logoff - close all file descriptors open by a vuid
1407 */
1408 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1409                      struct ntvfs_request *req)
1410 {
1411         struct pvfs_state *pvfs = ntvfs->private_data;
1412         struct pvfs_file *f, *next;
1413
1414         for (f=pvfs->files.list;f;f=next) {
1415                 next = f->next;
1416                 if (f->ntvfs->session_info == req->session_info) {
1417                         talloc_free(f);
1418                 }
1419         }
1420
1421         return NT_STATUS_OK;
1422 }
1423
1424
1425 /*
1426   exit - close files for the current pid
1427 */
1428 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1429                    struct ntvfs_request *req)
1430 {
1431         struct pvfs_state *pvfs = ntvfs->private_data;
1432         struct pvfs_file *f, *next;
1433
1434         for (f=pvfs->files.list;f;f=next) {
1435                 next = f->next;
1436                 if (f->ntvfs->session_info == req->session_info &&
1437                     f->ntvfs->smbpid == req->smbpid) {
1438                         talloc_free(f);
1439                 }
1440         }
1441
1442         return NT_STATUS_OK;
1443 }
1444
1445
1446 /*
1447   change the delete on close flag on an already open file
1448 */
1449 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1450                                   struct ntvfs_request *req, 
1451                                   struct pvfs_file *f, bool del_on_close)
1452 {
1453         struct odb_lock *lck;
1454         NTSTATUS status;
1455
1456         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1457                 return NT_STATUS_CANNOT_DELETE;
1458         }
1459         
1460         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1461             !pvfs_directory_empty(pvfs, f->handle->name)) {
1462                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1463         }
1464
1465         if (del_on_close) {
1466                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1467         } else {
1468                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1469         }
1470         
1471         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1472         if (lck == NULL) {
1473                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1474         }
1475
1476         status = odb_set_delete_on_close(lck, del_on_close);
1477
1478         talloc_free(lck);
1479
1480         return status;
1481 }
1482
1483
1484 /*
1485   determine if a file can be deleted, or if it is prevented by an
1486   already open file
1487 */
1488 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1489                          struct ntvfs_request *req,
1490                          struct pvfs_filename *name,
1491                          struct odb_lock **lckp)
1492 {
1493         NTSTATUS status;
1494         DATA_BLOB key;
1495         struct odb_lock *lck;
1496         uint32_t share_access;
1497         uint32_t access_mask;
1498         bool delete_on_close;
1499
1500         status = pvfs_locking_key(name, name, &key);
1501         if (!NT_STATUS_IS_OK(status)) {
1502                 return NT_STATUS_NO_MEMORY;
1503         }
1504
1505         lck = odb_lock(req, pvfs->odb_context, &key);
1506         if (lck == NULL) {
1507                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1508                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1509         }
1510
1511         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1512                           NTCREATEX_SHARE_ACCESS_WRITE |
1513                           NTCREATEX_SHARE_ACCESS_DELETE;
1514         access_mask     = SEC_STD_DELETE;
1515         delete_on_close = true;
1516
1517         status = odb_can_open(lck, name->stream_id,
1518                               share_access, access_mask, delete_on_close,
1519                               0, false);
1520
1521         if (NT_STATUS_IS_OK(status)) {
1522                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1523         }
1524
1525         /*
1526          * if it's a sharing violation or we got no oplock
1527          * only keep the lock if the caller requested access
1528          * to the lock
1529          */
1530         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1531             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1532                 if (lckp) {
1533                         *lckp = lck;
1534                 } else {
1535                         talloc_free(lck);
1536                 }
1537         } else if (!NT_STATUS_IS_OK(status)) {
1538                 talloc_free(lck);
1539                 if (lckp) {
1540                         *lckp = NULL;
1541                 }
1542         } else if (lckp) {
1543                 *lckp = lck;
1544         }
1545
1546         return status;
1547 }
1548
1549 /*
1550   determine if a file can be renamed, or if it is prevented by an
1551   already open file
1552 */
1553 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1554                          struct ntvfs_request *req,
1555                          struct pvfs_filename *name,
1556                          struct odb_lock **lckp)
1557 {
1558         NTSTATUS status;
1559         DATA_BLOB key;
1560         struct odb_lock *lck;
1561         uint32_t share_access;
1562         uint32_t access_mask;
1563         bool delete_on_close;
1564
1565         status = pvfs_locking_key(name, name, &key);
1566         if (!NT_STATUS_IS_OK(status)) {
1567                 return NT_STATUS_NO_MEMORY;
1568         }
1569
1570         lck = odb_lock(req, pvfs->odb_context, &key);
1571         if (lck == NULL) {
1572                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1573                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1574         }
1575
1576         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1577                           NTCREATEX_SHARE_ACCESS_WRITE;
1578         access_mask     = SEC_STD_DELETE;
1579         delete_on_close = false;
1580
1581         status = odb_can_open(lck, name->stream_id,
1582                               share_access, access_mask, delete_on_close,
1583                               0, false);
1584
1585         /*
1586          * if it's a sharing violation or we got no oplock
1587          * only keep the lock if the caller requested access
1588          * to the lock
1589          */
1590         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1591             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1592                 if (lckp) {
1593                         *lckp = lck;
1594                 } else {
1595                         talloc_free(lck);
1596                 }
1597         } else if (!NT_STATUS_IS_OK(status)) {
1598                 talloc_free(lck);
1599                 if (lckp) {
1600                         *lckp = NULL;
1601                 }
1602         } else if (lckp) {
1603                 *lckp = lck;
1604         }
1605
1606         return status;
1607 }
1608
1609 /*
1610   determine if file meta data can be accessed, or if it is prevented by an
1611   already open file
1612 */
1613 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1614                        struct ntvfs_request *req,
1615                        struct pvfs_filename *name)
1616 {
1617         NTSTATUS status;
1618         DATA_BLOB key;
1619         struct odb_lock *lck;
1620         uint32_t share_access;
1621         uint32_t access_mask;
1622         bool delete_on_close;
1623
1624         status = pvfs_locking_key(name, name, &key);
1625         if (!NT_STATUS_IS_OK(status)) {
1626                 return NT_STATUS_NO_MEMORY;
1627         }
1628
1629         lck = odb_lock(req, pvfs->odb_context, &key);
1630         if (lck == NULL) {
1631                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1632                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1633         }
1634
1635         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1636                           NTCREATEX_SHARE_ACCESS_WRITE;
1637         access_mask     = 0;
1638         delete_on_close = false;
1639
1640         status = odb_can_open(lck, name->stream_id,
1641                               share_access, access_mask, delete_on_close,
1642                               0, false);
1643
1644         if (!NT_STATUS_IS_OK(status)) {
1645                 talloc_free(lck);
1646         }
1647
1648         return status;
1649 }
1650
1651
1652 /*
1653   determine if delete on close is set on 
1654 */
1655 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h, 
1656                               int *open_count, char **path)
1657 {
1658         NTSTATUS status;
1659         bool del_on_close;
1660
1661         status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
1662                                          &del_on_close, open_count, path);
1663         if (!NT_STATUS_IS_OK(status)) {
1664                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1665                 return false;
1666         }
1667
1668         return del_on_close;
1669 }