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