pvfs: fix handling of create_option flags
[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         bool forced;
186
187         create_options = io->generic.in.create_options;
188         share_access   = io->generic.in.share_access;
189
190         forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
191
192         if (name->stream_name) {
193                 if (forced) {
194                         return NT_STATUS_NOT_A_DIRECTORY;
195                 } else {
196                         return NT_STATUS_FILE_IS_A_DIRECTORY;
197                 }
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         /* found with gentest */
207         if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
208             (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
209             (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
210                 return NT_STATUS_INVALID_PARAMETER;
211         }
212         
213         switch (io->generic.in.open_disposition) {
214         case NTCREATEX_DISP_OPEN_IF:
215                 break;
216
217         case NTCREATEX_DISP_OPEN:
218                 if (!name->exists) {
219                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
220                 }
221                 break;
222
223         case NTCREATEX_DISP_CREATE:
224                 if (name->exists) {
225                         return NT_STATUS_OBJECT_NAME_COLLISION;
226                 }
227                 break;
228
229         case NTCREATEX_DISP_OVERWRITE_IF:
230         case NTCREATEX_DISP_OVERWRITE:
231         case NTCREATEX_DISP_SUPERSEDE:
232         default:
233                 return NT_STATUS_INVALID_PARAMETER;
234         }
235
236         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
237         NT_STATUS_NOT_OK_RETURN(status);
238
239         f = talloc(h, struct pvfs_file);
240         if (f == NULL) {
241                 return NT_STATUS_NO_MEMORY;
242         }
243
244         f->handle = talloc(f, struct pvfs_file_handle);
245         if (f->handle == NULL) {
246                 return NT_STATUS_NO_MEMORY;
247         }
248
249         if (name->exists) {
250                 /* check the security descriptor */
251                 status = pvfs_access_check(pvfs, req, name, &access_mask);
252         } else {
253                 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
254         }
255         NT_STATUS_NOT_OK_RETURN(status);
256
257         if (io->generic.in.query_maximal_access) {
258                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
259                                                      &io->generic.out.maximal_access);
260                 NT_STATUS_NOT_OK_RETURN(status);
261         }
262
263         f->ntvfs         = h;
264         f->pvfs          = pvfs;
265         f->pending_list  = NULL;
266         f->lock_count    = 0;
267         f->share_access  = io->generic.in.share_access;
268         f->impersonation = io->generic.in.impersonation;
269         f->access_mask   = access_mask;
270         f->brl_handle    = NULL;
271         f->notify_buffer = NULL;
272         f->search        = NULL;
273
274         f->handle->pvfs              = pvfs;
275         f->handle->name              = talloc_steal(f->handle, name);
276         f->handle->fd                = -1;
277         f->handle->odb_locking_key   = data_blob(NULL, 0);
278         f->handle->create_options    = io->generic.in.create_options;
279         f->handle->seek_offset       = 0;
280         f->handle->position          = 0;
281         f->handle->mode              = 0;
282         f->handle->oplock            = NULL;
283         ZERO_STRUCT(f->handle->write_time);
284         f->handle->open_completed    = false;
285
286         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
287             pvfs_directory_empty(pvfs, f->handle->name)) {
288                 del_on_close = true;
289         } else {
290                 del_on_close = false;
291         }
292
293         if (name->exists) {
294                 /* form the lock context used for opendb locking */
295                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
296                 if (!NT_STATUS_IS_OK(status)) {
297                         return status;
298                 }
299
300                 /* get a lock on this file before the actual open */
301                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
302                 if (lck == NULL) {
303                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
304                                  name->full_name));
305                         /* we were supposed to do a blocking lock, so something
306                            is badly wrong! */
307                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
308                 }
309                 
310                 /* see if we are allowed to open at the same time as existing opens */
311                 status = odb_can_open(lck, name->stream_id,
312                                       share_access, access_mask, del_on_close,
313                                       io->generic.in.open_disposition, false);
314                 if (!NT_STATUS_IS_OK(status)) {
315                         talloc_free(lck);
316                         return status;
317                 }
318
319                 /* now really mark the file as open */
320                 status = odb_open_file(lck, f->handle, name->full_name,
321                                        NULL, name->dos.write_time,
322                                        false, OPLOCK_NONE, NULL);
323
324                 if (!NT_STATUS_IS_OK(status)) {
325                         talloc_free(lck);
326                         return status;
327                 }
328
329                 f->handle->have_opendb_entry = true;
330         }
331
332         DLIST_ADD(pvfs->files.list, f);
333
334         /* setup destructors to avoid leaks on abnormal termination */
335         talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
336         talloc_set_destructor(f, pvfs_dir_fnum_destructor);
337
338         if (!name->exists) {
339                 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
340                 mode_t mode = pvfs_fileperms(pvfs, attrib);
341
342                 if (mkdir(name->full_name, mode) == -1) {
343                         return pvfs_map_errno(pvfs,errno);
344                 }
345
346                 pvfs_xattr_unlink_hook(pvfs, name->full_name);
347
348                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
349                 if (!NT_STATUS_IS_OK(status)) {
350                         goto cleanup_delete;
351                 }
352
353                 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
354                 if (!NT_STATUS_IS_OK(status)) {
355                         goto cleanup_delete;
356                 }
357
358                 /* form the lock context used for opendb locking */
359                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
360                 if (!NT_STATUS_IS_OK(status)) {
361                         return status;
362                 }
363
364                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
365                 if (lck == NULL) {
366                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
367                                  name->full_name));
368                         /* we were supposed to do a blocking lock, so something
369                            is badly wrong! */
370                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
371                 }
372
373                 status = odb_can_open(lck, name->stream_id,
374                                       share_access, access_mask, del_on_close,
375                                       io->generic.in.open_disposition, false);
376
377                 if (!NT_STATUS_IS_OK(status)) {
378                         goto cleanup_delete;
379                 }
380
381                 status = odb_open_file(lck, f->handle, name->full_name,
382                                        NULL, name->dos.write_time,
383                                        false, OPLOCK_NONE, NULL);
384
385                 if (!NT_STATUS_IS_OK(status)) {
386                         goto cleanup_delete;
387                 }
388
389                 f->handle->have_opendb_entry = true;
390
391                 create_action = NTCREATEX_ACTION_CREATED;
392
393                 notify_trigger(pvfs->notify_context, 
394                                NOTIFY_ACTION_ADDED, 
395                                FILE_NOTIFY_CHANGE_DIR_NAME,
396                                name->full_name);
397         } else {
398                 create_action = NTCREATEX_ACTION_EXISTED;
399         }
400
401         if (!name->exists) {
402                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
403         }
404
405         /* the open succeeded, keep this handle permanently */
406         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
407         if (!NT_STATUS_IS_OK(status)) {
408                 goto cleanup_delete;
409         }
410
411         f->handle->open_completed = true;
412
413         io->generic.out.oplock_level  = OPLOCK_NONE;
414         io->generic.out.file.ntvfs    = h;
415         io->generic.out.create_action = create_action;
416         io->generic.out.create_time   = name->dos.create_time;
417         io->generic.out.access_time   = name->dos.access_time;
418         io->generic.out.write_time    = name->dos.write_time;
419         io->generic.out.change_time   = name->dos.change_time;
420         io->generic.out.attrib        = name->dos.attrib;
421         io->generic.out.alloc_size    = name->dos.alloc_size;
422         io->generic.out.size          = name->st.st_size;
423         io->generic.out.file_type     = FILE_TYPE_DISK;
424         io->generic.out.ipc_state     = 0;
425         io->generic.out.is_directory  = 1;
426
427         return NT_STATUS_OK;
428
429 cleanup_delete:
430         rmdir(name->full_name);
431         return status;
432 }
433
434 /*
435   destroy a struct pvfs_file_handle
436 */
437 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
438 {
439         talloc_free(h->write_time.update_event);
440         h->write_time.update_event = NULL;
441
442         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
443             h->name->stream_name) {
444                 NTSTATUS status;
445                 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
446                 if (!NT_STATUS_IS_OK(status)) {
447                         DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
448                                  h->name->stream_name, h->name->full_name));
449                 }
450         }
451
452         if (h->fd != -1) {
453                 if (close(h->fd) != 0) {
454                         DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
455                                  h->fd, h->name->full_name, strerror(errno)));
456                 }
457                 h->fd = -1;
458         }
459
460         if (!h->write_time.update_forced &&
461             h->write_time.update_on_close &&
462             h->write_time.close_time == 0) {
463                 struct timeval tv;
464                 tv = timeval_current();
465                 h->write_time.close_time = timeval_to_nttime(&tv);
466         }
467
468         if (h->have_opendb_entry) {
469                 struct odb_lock *lck;
470                 NTSTATUS status;
471                 const char *delete_path = NULL;
472
473                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
474                 if (lck == NULL) {
475                         DEBUG(0,("Unable to lock opendb for close\n"));
476                         return 0;
477                 }
478
479                 if (h->write_time.update_forced) {
480                         status = odb_get_file_infos(h->pvfs->odb_context,
481                                                     &h->odb_locking_key,
482                                                     NULL,
483                                                     &h->write_time.close_time);
484                         if (!NT_STATUS_IS_OK(status)) {
485                                 DEBUG(0,("Unable get write time for '%s' - %s\n",
486                                          h->name->full_name, nt_errstr(status)));
487                         }
488
489                         h->write_time.update_forced = false;
490                         h->write_time.update_on_close = true;
491                 } else if (h->write_time.update_on_close) {
492                         status = odb_set_write_time(lck, h->write_time.close_time, true);
493                         if (!NT_STATUS_IS_OK(status)) {
494                                 DEBUG(0,("Unable set write time for '%s' - %s\n",
495                                          h->name->full_name, nt_errstr(status)));
496                         }
497                 }
498
499                 status = odb_close_file(lck, h, &delete_path);
500                 if (!NT_STATUS_IS_OK(status)) {
501                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
502                                  h->name->full_name, nt_errstr(status)));
503                 }
504
505                 if (h->name->stream_name == NULL &&
506                     h->open_completed && delete_path) {
507                         status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
508                         if (!NT_STATUS_IS_OK(status)) {
509                                 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
510                                          delete_path, nt_errstr(status)));
511                         }
512                         if (unlink(delete_path) != 0) {
513                                 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
514                                          delete_path, strerror(errno)));
515                         } else {
516                                 notify_trigger(h->pvfs->notify_context,
517                                                NOTIFY_ACTION_REMOVED,
518                                                FILE_NOTIFY_CHANGE_FILE_NAME,
519                                                delete_path);
520                         }
521                         h->write_time.update_on_close = false;
522                 }
523
524                 talloc_free(lck);
525         }
526
527         if (h->write_time.update_on_close) {
528                 struct timeval tv[2];
529
530                 nttime_to_timeval(&tv[0], h->name->dos.access_time);
531                 nttime_to_timeval(&tv[1], h->write_time.close_time);
532
533                 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
534                         if (utimes(h->name->full_name, tv) == -1) {
535                                 DEBUG(0,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
536                                          h->name->full_name, strerror(errno)));
537                         }
538                 }
539         }
540
541         return 0;
542 }
543
544
545 /*
546   destroy a struct pvfs_file
547 */
548 static int pvfs_fnum_destructor(struct pvfs_file *f)
549 {
550         DLIST_REMOVE(f->pvfs->files.list, f);
551         pvfs_lock_close(f->pvfs, f);
552         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
553
554         return 0;
555 }
556
557
558 /*
559   form the lock context used for byte range locking. This is separate
560   from the locking key used for opendb locking as it needs to take
561   account of file streams (each stream is a separate byte range
562   locking space)
563 */
564 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
565                                         struct pvfs_filename *name,
566                                         struct ntvfs_handle *ntvfs,
567                                         struct brl_handle **_h)
568 {
569         DATA_BLOB odb_key, key;
570         NTSTATUS status;
571         struct brl_handle *h;
572
573         status = pvfs_locking_key(name, mem_ctx, &odb_key);
574         NT_STATUS_NOT_OK_RETURN(status);
575
576         if (name->stream_name == NULL) {
577                 key = odb_key;
578         } else {
579                 key = data_blob_talloc(mem_ctx, NULL, 
580                                        odb_key.length + strlen(name->stream_name) + 1);
581                 NT_STATUS_HAVE_NO_MEMORY(key.data);
582                 memcpy(key.data, odb_key.data, odb_key.length);
583                 memcpy(key.data + odb_key.length, 
584                        name->stream_name, strlen(name->stream_name) + 1);
585                 data_blob_free(&odb_key);
586         }
587
588         h = brl_create_handle(mem_ctx, ntvfs, &key);
589         NT_STATUS_HAVE_NO_MEMORY(h);
590
591         *_h = h;
592         return NT_STATUS_OK;
593 }
594
595 /*
596   create a new file
597 */
598 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 
599                                  struct ntvfs_request *req, 
600                                  struct pvfs_filename *name, 
601                                  union smb_open *io)
602 {
603         struct pvfs_file *f;
604         NTSTATUS status;
605         struct ntvfs_handle *h;
606         int flags, fd;
607         struct odb_lock *lck;
608         uint32_t create_options = io->generic.in.create_options;
609         uint32_t share_access = io->generic.in.share_access;
610         uint32_t access_mask = io->generic.in.access_mask;
611         mode_t mode;
612         uint32_t attrib;
613         bool del_on_close;
614         struct pvfs_filename *parent;
615         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
616         bool allow_level_II_oplock = false;
617
618         if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
619                 return NT_STATUS_INVALID_PARAMETER;
620         }
621
622         if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
623                 return NT_STATUS_ACCESS_DENIED;
624         }
625             
626         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
627             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
628                 return NT_STATUS_CANNOT_DELETE;
629         }
630
631         status = pvfs_access_check_create(pvfs, req, name, &access_mask);
632         NT_STATUS_NOT_OK_RETURN(status);
633
634         /* check that the parent isn't opened with delete on close set */
635         status = pvfs_resolve_parent(pvfs, req, name, &parent);
636         if (NT_STATUS_IS_OK(status)) {
637                 DATA_BLOB locking_key;
638                 status = pvfs_locking_key(parent, req, &locking_key);
639                 NT_STATUS_NOT_OK_RETURN(status);
640                 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
641                                             &del_on_close, NULL);
642                 NT_STATUS_NOT_OK_RETURN(status);
643                 if (del_on_close) {
644                         return NT_STATUS_DELETE_PENDING;
645                 }
646         }
647
648         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
649                 flags = O_RDWR;
650         } else {
651                 flags = O_RDONLY;
652         }
653
654         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
655         NT_STATUS_NOT_OK_RETURN(status);
656
657         f = talloc(h, struct pvfs_file);
658         NT_STATUS_HAVE_NO_MEMORY(f);
659
660         f->handle = talloc(f, struct pvfs_file_handle);
661         NT_STATUS_HAVE_NO_MEMORY(f->handle);
662
663         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
664         mode = pvfs_fileperms(pvfs, attrib);
665
666         /* create the file */
667         fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
668         if (fd == -1) {
669                 return pvfs_map_errno(pvfs, errno);
670         }
671
672         pvfs_xattr_unlink_hook(pvfs, name->full_name);
673
674         /* if this was a stream create then create the stream as well */
675         if (name->stream_name) {
676                 status = pvfs_stream_create(pvfs, name, fd);
677                 if (!NT_STATUS_IS_OK(status)) {
678                         close(fd);
679                         return status;
680                 }
681         }
682
683         /* re-resolve the open fd */
684         status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
685         if (!NT_STATUS_IS_OK(status)) {
686                 close(fd);
687                 return status;
688         }
689
690         /* support initial alloc sizes */
691         name->dos.alloc_size = io->ntcreatex.in.alloc_size;
692         name->dos.attrib = attrib;
693         status = pvfs_dosattrib_save(pvfs, name, fd);
694         if (!NT_STATUS_IS_OK(status)) {
695                 goto cleanup_delete;
696         }
697
698
699         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
700         if (!NT_STATUS_IS_OK(status)) {
701                 goto cleanup_delete;
702         }
703
704         if (io->generic.in.query_maximal_access) {
705                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
706                                                      &io->generic.out.maximal_access);
707                 NT_STATUS_NOT_OK_RETURN(status);
708         }
709
710         /* form the lock context used for byte range locking and
711            opendb locking */
712         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
713         if (!NT_STATUS_IS_OK(status)) {
714                 goto cleanup_delete;
715         }
716
717         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
718         if (!NT_STATUS_IS_OK(status)) {
719                 goto cleanup_delete;
720         }
721
722         /* grab a lock on the open file record */
723         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
724         if (lck == NULL) {
725                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
726                          name->full_name));
727                 /* we were supposed to do a blocking lock, so something
728                    is badly wrong! */
729                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
730                 goto cleanup_delete;
731         }
732
733         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
734                 del_on_close = true;
735         } else {
736                 del_on_close = false;
737         }
738
739         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
740                 oplock_level = OPLOCK_NONE;
741         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
742                 oplock_level = OPLOCK_BATCH;
743         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
744                 oplock_level = OPLOCK_EXCLUSIVE;
745         }
746
747         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
748                 allow_level_II_oplock = true;
749         }
750
751         status = odb_can_open(lck, name->stream_id,
752                               share_access, access_mask, del_on_close,
753                               io->generic.in.open_disposition, false);
754         if (!NT_STATUS_IS_OK(status)) {
755                 talloc_free(lck);
756                 /* bad news, we must have hit a race - we don't delete the file
757                    here as the most likely scenario is that someone else created
758                    the file at the same time */
759                 close(fd);
760                 return status;
761         }
762
763         f->ntvfs             = h;
764         f->pvfs              = pvfs;
765         f->pending_list      = NULL;
766         f->lock_count        = 0;
767         f->share_access      = io->generic.in.share_access;
768         f->access_mask       = access_mask;
769         f->impersonation     = io->generic.in.impersonation;
770         f->notify_buffer     = NULL;
771         f->search            = NULL;
772
773         f->handle->pvfs              = pvfs;
774         f->handle->name              = talloc_steal(f->handle, name);
775         f->handle->fd                = fd;
776         f->handle->create_options    = io->generic.in.create_options;
777         f->handle->seek_offset       = 0;
778         f->handle->position          = 0;
779         f->handle->mode              = 0;
780         f->handle->oplock            = NULL;
781         f->handle->have_opendb_entry = true;
782         ZERO_STRUCT(f->handle->write_time);
783         f->handle->open_completed    = false;
784
785         status = odb_open_file(lck, f->handle, name->full_name,
786                                &f->handle->fd, name->dos.write_time,
787                                allow_level_II_oplock,
788                                oplock_level, &oplock_granted);
789         talloc_free(lck);
790         if (!NT_STATUS_IS_OK(status)) {
791                 /* bad news, we must have hit a race - we don't delete the file
792                    here as the most likely scenario is that someone else created
793                    the file at the same time */
794                 close(fd);
795                 return status;
796         }
797
798         DLIST_ADD(pvfs->files.list, f);
799
800         /* setup a destructor to avoid file descriptor leaks on
801            abnormal termination */
802         talloc_set_destructor(f, pvfs_fnum_destructor);
803         talloc_set_destructor(f->handle, pvfs_handle_destructor);
804
805         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
806                 oplock_granted = OPLOCK_BATCH;
807         } else if (oplock_granted != OPLOCK_NONE) {
808                 status = pvfs_setup_oplock(f, oplock_granted);
809                 if (!NT_STATUS_IS_OK(status)) {
810                         return status;
811                 }
812         }
813
814         io->generic.out.oplock_level  = oplock_granted;
815         io->generic.out.file.ntvfs    = f->ntvfs;
816         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
817         io->generic.out.create_time   = name->dos.create_time;
818         io->generic.out.access_time   = name->dos.access_time;
819         io->generic.out.write_time    = name->dos.write_time;
820         io->generic.out.change_time   = name->dos.change_time;
821         io->generic.out.attrib        = name->dos.attrib;
822         io->generic.out.alloc_size    = name->dos.alloc_size;
823         io->generic.out.size          = name->st.st_size;
824         io->generic.out.file_type     = FILE_TYPE_DISK;
825         io->generic.out.ipc_state     = 0;
826         io->generic.out.is_directory  = 0;
827
828         /* success - keep the file handle */
829         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
830         if (!NT_STATUS_IS_OK(status)) {
831                 goto cleanup_delete;
832         }
833
834         f->handle->open_completed = true;
835
836         notify_trigger(pvfs->notify_context, 
837                        NOTIFY_ACTION_ADDED, 
838                        FILE_NOTIFY_CHANGE_FILE_NAME,
839                        name->full_name);
840
841         return NT_STATUS_OK;
842
843 cleanup_delete:
844         close(fd);
845         unlink(name->full_name);
846         return status;
847 }
848
849 /*
850   state of a pending retry
851 */
852 struct pvfs_odb_retry {
853         struct ntvfs_module_context *ntvfs;
854         struct ntvfs_request *req;
855         DATA_BLOB odb_locking_key;
856         void *io;
857         void *private_data;
858         void (*callback)(struct pvfs_odb_retry *r,
859                          struct ntvfs_module_context *ntvfs,
860                          struct ntvfs_request *req,
861                          void *io,
862                          void *private_data,
863                          enum pvfs_wait_notice reason);
864 };
865
866 /* destroy a pending request */
867 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
868 {
869         struct pvfs_state *pvfs = r->ntvfs->private_data;
870         if (r->odb_locking_key.data) {
871                 struct odb_lock *lck;
872                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
873                 if (lck != NULL) {
874                         odb_remove_pending(lck, r);
875                 }
876                 talloc_free(lck);
877         }
878         return 0;
879 }
880
881 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
882 {
883         struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
884
885         if (reason == PVFS_WAIT_EVENT) {
886                 /*
887                  * The pending odb entry is already removed.
888                  * We use a null locking key to indicate this
889                  * to the destructor.
890                  */
891                 data_blob_free(&r->odb_locking_key);
892         }
893
894         r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
895 }
896
897 /*
898   setup for a retry of a request that was rejected
899   by odb_can_open()
900 */
901 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
902                               struct ntvfs_request *req,
903                               struct odb_lock *lck,
904                               struct timeval end_time,
905                               void *io,
906                               void *private_data,
907                               void (*callback)(struct pvfs_odb_retry *r,
908                                                struct ntvfs_module_context *ntvfs,
909                                                struct ntvfs_request *req,
910                                                void *io,
911                                                void *private_data,
912                                                enum pvfs_wait_notice reason))
913 {
914         struct pvfs_state *pvfs = ntvfs->private_data;
915         struct pvfs_odb_retry *r;
916         struct pvfs_wait *wait_handle;
917         NTSTATUS status;
918
919         r = talloc(req, struct pvfs_odb_retry);
920         NT_STATUS_HAVE_NO_MEMORY(r);
921
922         r->ntvfs = ntvfs;
923         r->req = req;
924         r->io = io;
925         r->private_data = private_data;
926         r->callback = callback;
927         r->odb_locking_key = odb_get_key(r, lck);
928         if (r->odb_locking_key.data == NULL) {
929                 return NT_STATUS_NO_MEMORY;
930         }
931
932         /* setup a pending lock */
933         status = odb_open_file_pending(lck, r);
934         if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
935                 /*
936                  * maybe only a unix application
937                  * has the file open
938                  */
939                 data_blob_free(&r->odb_locking_key);
940         } else if (!NT_STATUS_IS_OK(status)) {
941                 return status;
942         }
943
944         talloc_free(lck);
945
946         talloc_set_destructor(r, pvfs_odb_retry_destructor);
947
948         wait_handle = pvfs_wait_message(pvfs, req,
949                                         MSG_PVFS_RETRY_OPEN, end_time,
950                                         pvfs_odb_retry_callback, r);
951         if (wait_handle == NULL) {
952                 return NT_STATUS_NO_MEMORY;
953         }
954
955         talloc_steal(r, wait_handle);
956
957         return NT_STATUS_OK;
958 }
959
960 /*
961   retry an open after a sharing violation
962 */
963 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
964                                     struct ntvfs_module_context *ntvfs,
965                                     struct ntvfs_request *req,
966                                     void *_io,
967                                     void *private_data,
968                                     enum pvfs_wait_notice reason)
969 {
970         union smb_open *io = talloc_get_type(_io, union smb_open);
971         struct timeval *final_timeout = NULL;
972         NTSTATUS status;
973
974         if (private_data) {
975                 final_timeout = talloc_get_type(private_data,
976                                                 struct timeval);
977         }
978
979         /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
980            just a bug in their server, but we better do the same */
981         if (reason == PVFS_WAIT_CANCEL) {
982                 return;
983         }
984
985         if (reason == PVFS_WAIT_TIMEOUT) {
986                 if (final_timeout &&
987                     !timeval_expired(final_timeout)) {
988                         /*
989                          * we need to retry periodictly
990                          * after an EAGAIN as there's
991                          * no way the kernel tell us
992                          * an oplock is released.
993                          */
994                         goto retry;
995                 }
996                 /* if it timed out, then give the failure
997                    immediately */
998                 talloc_free(r);
999                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1000                 req->async_states->send_fn(req);
1001                 return;
1002         }
1003
1004 retry:
1005         talloc_free(r);
1006
1007         /* try the open again, which could trigger another retry setup
1008            if it wants to, so we have to unmark the async flag so we
1009            will know if it does a second async reply */
1010         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1011
1012         status = pvfs_open(ntvfs, req, io);
1013         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1014                 /* the 2nd try also replied async, so we don't send
1015                    the reply yet */
1016                 return;
1017         }
1018
1019         /* re-mark it async, just in case someone up the chain does
1020            paranoid checking */
1021         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1022
1023         /* send the reply up the chain */
1024         req->async_states->status = status;
1025         req->async_states->send_fn(req);
1026 }
1027
1028
1029 /*
1030   special handling for openx DENY_DOS semantics
1031
1032   This function attempts a reference open using an existing handle. If its allowed,
1033   then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1034   open processing continues.
1035 */
1036 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1037                                    struct ntvfs_request *req, union smb_open *io,
1038                                    struct pvfs_file *f, struct odb_lock *lck)
1039 {
1040         struct pvfs_state *pvfs = ntvfs->private_data;
1041         struct pvfs_file *f2;
1042         struct pvfs_filename *name;
1043         NTSTATUS status;
1044
1045         /* search for an existing open with the right parameters. Note
1046            the magic ntcreatex options flag, which is set in the
1047            generic mapping code. This might look ugly, but its
1048            actually pretty much now w2k does it internally as well. 
1049            
1050            If you look at the BASE-DENYDOS test you will see that a
1051            DENY_DOS is a very special case, and in the right
1052            circumstances you actually get the _same_ handle back
1053            twice, rather than a new handle.
1054         */
1055         for (f2=pvfs->files.list;f2;f2=f2->next) {
1056                 if (f2 != f &&
1057                     f2->ntvfs->session_info == req->session_info &&
1058                     f2->ntvfs->smbpid == req->smbpid &&
1059                     (f2->handle->create_options & 
1060                      (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1061                       NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1062                     (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1063                     strcasecmp_m(f2->handle->name->original_name, 
1064                                io->generic.in.fname)==0) {
1065                         break;
1066                 }
1067         }
1068
1069         if (!f2) {
1070                 return NT_STATUS_SHARING_VIOLATION;
1071         }
1072
1073         /* quite an insane set of semantics ... */
1074         if (is_exe_filename(io->generic.in.fname) &&
1075             (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1076                 return NT_STATUS_SHARING_VIOLATION;
1077         }
1078
1079         /*
1080           setup a reference to the existing handle
1081          */
1082         talloc_free(f->handle);
1083         f->handle = talloc_reference(f, f2->handle);
1084
1085         talloc_free(lck);
1086
1087         name = f->handle->name;
1088
1089         io->generic.out.oplock_level  = OPLOCK_NONE;
1090         io->generic.out.file.ntvfs    = f->ntvfs;
1091         io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1092         io->generic.out.create_time   = name->dos.create_time;
1093         io->generic.out.access_time   = name->dos.access_time;
1094         io->generic.out.write_time    = name->dos.write_time;
1095         io->generic.out.change_time   = name->dos.change_time;
1096         io->generic.out.attrib        = name->dos.attrib;
1097         io->generic.out.alloc_size    = name->dos.alloc_size;
1098         io->generic.out.size          = name->st.st_size;
1099         io->generic.out.file_type     = FILE_TYPE_DISK;
1100         io->generic.out.ipc_state     = 0;
1101         io->generic.out.is_directory  = 0;
1102  
1103         status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1104         NT_STATUS_NOT_OK_RETURN(status);
1105
1106         return NT_STATUS_OK;
1107 }
1108
1109
1110
1111 /*
1112   setup for a open retry after a sharing violation
1113 */
1114 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1115                                       struct ntvfs_request *req, 
1116                                       union smb_open *io,
1117                                       struct pvfs_file *f,
1118                                       struct odb_lock *lck,
1119                                       NTSTATUS parent_status)
1120 {
1121         struct pvfs_state *pvfs = ntvfs->private_data;
1122         NTSTATUS status;
1123         struct timeval end_time;
1124         struct timeval *final_timeout = NULL;
1125
1126         if (io->generic.in.create_options & 
1127             (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1128                 /* see if we can satisfy the request using the special DENY_DOS
1129                    code */
1130                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1131                 if (NT_STATUS_IS_OK(status)) {
1132                         return status;
1133                 }
1134         }
1135
1136         /* the retry should allocate a new file handle */
1137         talloc_free(f);
1138
1139         if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1140                 end_time = timeval_add(&req->statistics.request_time,
1141                                        0, pvfs->sharing_violation_delay);
1142         } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1143                 end_time = timeval_add(&req->statistics.request_time,
1144                                        pvfs->oplock_break_timeout, 0);
1145         } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1146                 /*
1147                  * we got EAGAIN which means a unix application
1148                  * has an oplock or share mode
1149                  *
1150                  * we retry every 4/5 of the sharing violation delay
1151                  * to see if the unix application
1152                  * has released the oplock or share mode.
1153                  */
1154                 final_timeout = talloc(req, struct timeval);
1155                 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1156                 *final_timeout = timeval_add(&req->statistics.request_time,
1157                                              pvfs->oplock_break_timeout,
1158                                              0);
1159                 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1160                 end_time = timeval_min(final_timeout, &end_time);
1161         } else {
1162                 return NT_STATUS_INTERNAL_ERROR;
1163         }
1164
1165         return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1166                                     final_timeout, pvfs_retry_open_sharing);
1167 }
1168
1169 /*
1170   open a file
1171 */
1172 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1173                    struct ntvfs_request *req, union smb_open *io)
1174 {
1175         struct pvfs_state *pvfs = ntvfs->private_data;
1176         int flags = 0;
1177         struct pvfs_filename *name;
1178         struct pvfs_file *f;
1179         struct ntvfs_handle *h;
1180         NTSTATUS status;
1181         int fd;
1182         struct odb_lock *lck;
1183         uint32_t create_options;
1184         uint32_t create_options_must_ignore_mask;
1185         uint32_t share_access;
1186         uint32_t access_mask;
1187         uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1188         bool del_on_close;
1189         bool stream_existed, stream_truncate=false;
1190         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1191         bool allow_level_II_oplock = false;
1192
1193         /* use the generic mapping code to avoid implementing all the
1194            different open calls. */
1195         if (io->generic.level != RAW_OPEN_GENERIC &&
1196             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1197                 return ntvfs_map_open(ntvfs, req, io);
1198         }
1199
1200         ZERO_STRUCT(io->generic.out);
1201
1202         create_options = io->generic.in.create_options;
1203         share_access   = io->generic.in.share_access;
1204         access_mask    = io->generic.in.access_mask;
1205
1206         if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1207                 return NT_STATUS_INVALID_PARAMETER;
1208         }
1209
1210         /*
1211          * These options are ignored,
1212          * but we reuse some of them as private values for the generic mapping
1213          */
1214         create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1215         create_options_must_ignore_mask &= ~NTCREATEX_OPTIONS_PRIVATE_MASK;
1216         create_options &= ~create_options_must_ignore_mask;
1217
1218         if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1219                 return NT_STATUS_NOT_SUPPORTED;
1220         }
1221
1222         if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1223                 return NT_STATUS_INVALID_PARAMETER;
1224         }
1225
1226         /* TODO: When we implement HSM, add a hook here not to pull
1227          * the actual file off tape, when this option is passed from
1228          * the client */
1229         if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1230                 /* no-op */
1231         }
1232
1233         /* TODO: If (unlikely) Linux does a good compressed
1234          * filesystem, we might need an ioctl call for this */
1235         if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1236                 /* no-op */
1237         }
1238
1239         if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1240                 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1241         }
1242
1243         /* Open the file with sync, if they asked for it, but
1244            'strict sync = no' turns this client request into a no-op */
1245         if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1246                 flags |= O_SYNC;
1247         }
1248
1249
1250         /* other create options are not allowed */
1251         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1252             !(access_mask & SEC_STD_DELETE)) {
1253                 return NT_STATUS_INVALID_PARAMETER;
1254         }
1255
1256         if (access_mask & SEC_MASK_INVALID) {
1257                 return NT_STATUS_ACCESS_DENIED;
1258         }
1259
1260         /* what does this bit really mean?? */
1261         if (req->ctx->protocol == PROTOCOL_SMB2 &&
1262             access_mask == SEC_STD_SYNCHRONIZE) {
1263                 return NT_STATUS_ACCESS_DENIED;
1264         }
1265
1266         if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1267                                           FILE_ATTRIBUTE_VOLUME| 
1268                                           (~FILE_ATTRIBUTE_ALL_MASK))) {
1269                 return NT_STATUS_INVALID_PARAMETER;
1270         }
1271
1272         /* we ignore some file_attr bits */
1273         io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED | 
1274                                         FILE_ATTRIBUTE_COMPRESSED |
1275                                         FILE_ATTRIBUTE_REPARSE_POINT |
1276                                         FILE_ATTRIBUTE_SPARSE |
1277                                         FILE_ATTRIBUTE_NORMAL);
1278
1279         /* resolve the cifs name to a posix name */
1280         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
1281                                    PVFS_RESOLVE_STREAMS, &name);
1282         if (!NT_STATUS_IS_OK(status)) {
1283                 return status;
1284         }
1285
1286         /* if the client specified that it must not be a directory then
1287            check that it isn't */
1288         if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1289             (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1290                 return NT_STATUS_FILE_IS_A_DIRECTORY;
1291         }
1292
1293         /* if the client specified that it must be a directory then
1294            check that it is */
1295         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1296             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1297                 return NT_STATUS_NOT_A_DIRECTORY;
1298         }
1299
1300         /* directory opens are handled separately */
1301         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1302             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1303                 return pvfs_open_directory(pvfs, req, name, io);
1304         }
1305
1306         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1307            open doesn't match */
1308         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1309
1310         switch (io->generic.in.open_disposition) {
1311         case NTCREATEX_DISP_SUPERSEDE:
1312         case NTCREATEX_DISP_OVERWRITE_IF:
1313                 if (name->stream_name == NULL) {
1314                         flags = O_TRUNC;
1315                 } else {
1316                         stream_truncate = true;
1317                 }
1318                 create_action = NTCREATEX_ACTION_TRUNCATED;
1319                 break;
1320
1321         case NTCREATEX_DISP_OPEN:
1322                 if (!name->stream_exists) {
1323                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1324                 }
1325                 flags = 0;
1326                 break;
1327
1328         case NTCREATEX_DISP_OVERWRITE:
1329                 if (!name->stream_exists) {
1330                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1331                 }
1332                 if (name->stream_name == NULL) {
1333                         flags = O_TRUNC;
1334                 } else {
1335                         stream_truncate = true;
1336                 }
1337                 create_action = NTCREATEX_ACTION_TRUNCATED;
1338                 break;
1339
1340         case NTCREATEX_DISP_CREATE:
1341                 if (name->stream_exists) {
1342                         return NT_STATUS_OBJECT_NAME_COLLISION;
1343                 }
1344                 flags = 0;
1345                 break;
1346
1347         case NTCREATEX_DISP_OPEN_IF:
1348                 flags = 0;
1349                 break;
1350
1351         default:
1352                 return NT_STATUS_INVALID_PARAMETER;
1353         }
1354
1355         /* handle creating a new file separately */
1356         if (!name->exists) {
1357                 status = pvfs_create_file(pvfs, req, name, io);
1358                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1359                         return status;
1360                 }
1361
1362                 /* we've hit a race - the file was created during this call */
1363                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1364                         return status;
1365                 }
1366
1367                 /* try re-resolving the name */
1368                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1369                 if (!NT_STATUS_IS_OK(status)) {
1370                         return status;
1371                 }
1372                 /* fall through to a normal open */
1373         }
1374
1375         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1376             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1377                 return NT_STATUS_CANNOT_DELETE;
1378         }
1379
1380         /* check the security descriptor */
1381         status = pvfs_access_check(pvfs, req, name, &access_mask);
1382         NT_STATUS_NOT_OK_RETURN(status);
1383
1384         if (io->generic.in.query_maximal_access) {
1385                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
1386                                                      &io->generic.out.maximal_access);
1387                 NT_STATUS_NOT_OK_RETURN(status);
1388         }
1389
1390         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1391         NT_STATUS_NOT_OK_RETURN(status);
1392
1393         f = talloc(h, struct pvfs_file);
1394         if (f == NULL) {
1395                 return NT_STATUS_NO_MEMORY;
1396         }
1397
1398         f->handle = talloc(f, struct pvfs_file_handle);
1399         if (f->handle == NULL) {
1400                 return NT_STATUS_NO_MEMORY;
1401         }
1402
1403         f->ntvfs         = h;
1404         f->pvfs          = pvfs;
1405         f->pending_list  = NULL;
1406         f->lock_count    = 0;
1407         f->share_access  = io->generic.in.share_access;
1408         f->access_mask   = access_mask;
1409         f->impersonation = io->generic.in.impersonation;
1410         f->notify_buffer = NULL;
1411         f->search        = NULL;
1412
1413         f->handle->pvfs              = pvfs;
1414         f->handle->fd                = -1;
1415         f->handle->name              = talloc_steal(f->handle, name);
1416         f->handle->create_options    = io->generic.in.create_options;
1417         f->handle->seek_offset       = 0;
1418         f->handle->position          = 0;
1419         f->handle->mode              = 0;
1420         f->handle->oplock            = NULL;
1421         f->handle->have_opendb_entry = false;
1422         ZERO_STRUCT(f->handle->write_time);
1423         f->handle->open_completed    = false;
1424
1425         /* form the lock context used for byte range locking and
1426            opendb locking */
1427         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1428         if (!NT_STATUS_IS_OK(status)) {
1429                 return status;
1430         }
1431
1432         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1433         if (!NT_STATUS_IS_OK(status)) {
1434                 return status;
1435         }
1436
1437         /* get a lock on this file before the actual open */
1438         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1439         if (lck == NULL) {
1440                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1441                          name->full_name));
1442                 /* we were supposed to do a blocking lock, so something
1443                    is badly wrong! */
1444                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1445         }
1446
1447         DLIST_ADD(pvfs->files.list, f);
1448
1449         /* setup a destructor to avoid file descriptor leaks on
1450            abnormal termination */
1451         talloc_set_destructor(f, pvfs_fnum_destructor);
1452         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1453
1454         /* 
1455          * Only SMB2 takes care of the delete_on_close,
1456          * on existing files
1457          */
1458         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1459             req->ctx->protocol == PROTOCOL_SMB2) {
1460                 del_on_close = true;
1461         } else {
1462                 del_on_close = false;
1463         }
1464
1465         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1466                 oplock_level = OPLOCK_NONE;
1467         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1468                 oplock_level = OPLOCK_BATCH;
1469         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1470                 oplock_level = OPLOCK_EXCLUSIVE;
1471         }
1472
1473         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1474                 allow_level_II_oplock = true;
1475         }
1476
1477         /* see if we are allowed to open at the same time as existing opens */
1478         status = odb_can_open(lck, name->stream_id,
1479                               share_access, access_mask, del_on_close,
1480                               io->generic.in.open_disposition, false);
1481
1482         /*
1483          * on a sharing violation we need to retry when the file is closed by
1484          * the other user, or after 1 second
1485          * on a non granted oplock we need to retry when the file is closed by
1486          * the other user, or after 30 seconds
1487         */
1488         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1489              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1490             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1491                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1492         }
1493
1494         if (!NT_STATUS_IS_OK(status)) {
1495                 talloc_free(lck);
1496                 return status;
1497         }
1498
1499         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1500                 flags |= O_RDWR;
1501         } else {
1502                 flags |= O_RDONLY;
1503         }
1504
1505         /* do the actual open */
1506         fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1507         if (fd == -1) {
1508                 status = pvfs_map_errno(f->pvfs, errno);
1509
1510                 /*
1511                  * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1512                  */
1513                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1514                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1515                         return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1516                 }
1517
1518                 talloc_free(lck);
1519                 return status;
1520         }
1521
1522         f->handle->fd = fd;
1523
1524         /* now really mark the file as open */
1525         status = odb_open_file(lck, f->handle, name->full_name,
1526                                &f->handle->fd, name->dos.write_time,
1527                                allow_level_II_oplock,
1528                                oplock_level, &oplock_granted);
1529
1530         if (!NT_STATUS_IS_OK(status)) {
1531                 talloc_free(lck);
1532                 return status;
1533         }
1534
1535         f->handle->have_opendb_entry = true;
1536
1537         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1538                 oplock_granted = OPLOCK_BATCH;
1539         } else if (oplock_granted != OPLOCK_NONE) {
1540                 status = pvfs_setup_oplock(f, oplock_granted);
1541                 if (!NT_STATUS_IS_OK(status)) {
1542                         talloc_free(lck);
1543                         return status;
1544                 }
1545         }
1546
1547         stream_existed = name->stream_exists;
1548
1549         /* if this was a stream create then create the stream as well */
1550         if (!name->stream_exists) {
1551                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1552                 if (!NT_STATUS_IS_OK(status)) {
1553                         talloc_free(lck);
1554                         return status;
1555                 }
1556                 if (stream_truncate) {
1557                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1558                         if (!NT_STATUS_IS_OK(status)) {
1559                                 talloc_free(lck);
1560                                 return status;
1561                         }
1562                 }
1563         }
1564
1565         /* re-resolve the open fd */
1566         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1567         if (!NT_STATUS_IS_OK(status)) {
1568                 talloc_free(lck);
1569                 return status;
1570         }
1571
1572         if (f->handle->name->stream_id == 0 &&
1573             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1574              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1575                 /* for overwrite we need to replace file permissions */
1576                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1577                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1578                 if (fchmod(fd, mode) == -1) {
1579                         talloc_free(lck);
1580                         return pvfs_map_errno(pvfs, errno);
1581                 }
1582                 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1583                 name->dos.attrib = attrib;
1584                 status = pvfs_dosattrib_save(pvfs, name, fd);
1585                 if (!NT_STATUS_IS_OK(status)) {
1586                         talloc_free(lck);
1587                         return status;
1588                 }
1589         }
1590             
1591         talloc_free(lck);
1592
1593         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1594         NT_STATUS_NOT_OK_RETURN(status);
1595
1596         /* mark the open as having completed fully, so delete on close
1597            can now be used */
1598         f->handle->open_completed     = true;
1599
1600         io->generic.out.oplock_level  = oplock_granted;
1601         io->generic.out.file.ntvfs    = h;
1602         io->generic.out.create_action = stream_existed?
1603                 create_action:NTCREATEX_ACTION_CREATED;
1604         
1605         io->generic.out.create_time   = name->dos.create_time;
1606         io->generic.out.access_time   = name->dos.access_time;
1607         io->generic.out.write_time    = name->dos.write_time;
1608         io->generic.out.change_time   = name->dos.change_time;
1609         io->generic.out.attrib        = name->dos.attrib;
1610         io->generic.out.alloc_size    = name->dos.alloc_size;
1611         io->generic.out.size          = name->st.st_size;
1612         io->generic.out.file_type     = FILE_TYPE_DISK;
1613         io->generic.out.ipc_state     = 0;
1614         io->generic.out.is_directory  = 0;
1615
1616         return NT_STATUS_OK;
1617 }
1618
1619
1620 /*
1621   close a file
1622 */
1623 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1624                     struct ntvfs_request *req, union smb_close *io)
1625 {
1626         struct pvfs_state *pvfs = ntvfs->private_data;
1627         struct pvfs_file *f;
1628
1629         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1630                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1631         }
1632
1633         if (io->generic.level != RAW_CLOSE_GENERIC) {
1634                 return ntvfs_map_close(ntvfs, req, io);
1635         }
1636
1637         f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1638         if (!f) {
1639                 return NT_STATUS_INVALID_HANDLE;
1640         }
1641
1642         if (!null_time(io->generic.in.write_time)) {
1643                 f->handle->write_time.update_forced = false;
1644                 f->handle->write_time.update_on_close = true;
1645                 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1646         }
1647
1648         if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1649                 struct pvfs_filename *name;
1650                 NTSTATUS status;
1651                 struct pvfs_file_handle *h = f->handle;
1652
1653                 status = pvfs_resolve_name_handle(pvfs, h);
1654                 if (!NT_STATUS_IS_OK(status)) {
1655                         return status;
1656                 }
1657                 name = h->name;
1658
1659                 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1660                 io->generic.out.create_time = name->dos.create_time;
1661                 io->generic.out.access_time = name->dos.access_time;
1662                 io->generic.out.write_time  = name->dos.write_time;
1663                 io->generic.out.change_time = name->dos.change_time;
1664                 io->generic.out.alloc_size  = name->dos.alloc_size;
1665                 io->generic.out.size        = name->st.st_size;
1666                 io->generic.out.file_attr   = name->dos.attrib;         
1667         } else {
1668                 ZERO_STRUCT(io->generic.out);
1669         }
1670
1671         talloc_free(f);
1672
1673         return NT_STATUS_OK;
1674 }
1675
1676
1677 /*
1678   logoff - close all file descriptors open by a vuid
1679 */
1680 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1681                      struct ntvfs_request *req)
1682 {
1683         struct pvfs_state *pvfs = ntvfs->private_data;
1684         struct pvfs_file *f, *next;
1685
1686         for (f=pvfs->files.list;f;f=next) {
1687                 next = f->next;
1688                 if (f->ntvfs->session_info == req->session_info) {
1689                         talloc_free(f);
1690                 }
1691         }
1692
1693         return NT_STATUS_OK;
1694 }
1695
1696
1697 /*
1698   exit - close files for the current pid
1699 */
1700 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1701                    struct ntvfs_request *req)
1702 {
1703         struct pvfs_state *pvfs = ntvfs->private_data;
1704         struct pvfs_file *f, *next;
1705
1706         for (f=pvfs->files.list;f;f=next) {
1707                 next = f->next;
1708                 if (f->ntvfs->session_info == req->session_info &&
1709                     f->ntvfs->smbpid == req->smbpid) {
1710                         talloc_free(f);
1711                 }
1712         }
1713
1714         return NT_STATUS_OK;
1715 }
1716
1717
1718 /*
1719   change the delete on close flag on an already open file
1720 */
1721 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1722                                   struct ntvfs_request *req, 
1723                                   struct pvfs_file *f, bool del_on_close)
1724 {
1725         struct odb_lock *lck;
1726         NTSTATUS status;
1727
1728         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1729                 return NT_STATUS_CANNOT_DELETE;
1730         }
1731         
1732         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1733             !pvfs_directory_empty(pvfs, f->handle->name)) {
1734                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1735         }
1736
1737         if (del_on_close) {
1738                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1739         } else {
1740                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1741         }
1742         
1743         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1744         if (lck == NULL) {
1745                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1746         }
1747
1748         status = odb_set_delete_on_close(lck, del_on_close);
1749
1750         talloc_free(lck);
1751
1752         return status;
1753 }
1754
1755
1756 /*
1757   determine if a file can be deleted, or if it is prevented by an
1758   already open file
1759 */
1760 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1761                          struct ntvfs_request *req,
1762                          struct pvfs_filename *name,
1763                          struct odb_lock **lckp)
1764 {
1765         NTSTATUS status;
1766         DATA_BLOB key;
1767         struct odb_lock *lck;
1768         uint32_t share_access;
1769         uint32_t access_mask;
1770         bool delete_on_close;
1771
1772         status = pvfs_locking_key(name, name, &key);
1773         if (!NT_STATUS_IS_OK(status)) {
1774                 return NT_STATUS_NO_MEMORY;
1775         }
1776
1777         lck = odb_lock(req, pvfs->odb_context, &key);
1778         if (lck == NULL) {
1779                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1780                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1781         }
1782
1783         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1784                           NTCREATEX_SHARE_ACCESS_WRITE |
1785                           NTCREATEX_SHARE_ACCESS_DELETE;
1786         access_mask     = SEC_STD_DELETE;
1787         delete_on_close = true;
1788
1789         status = odb_can_open(lck, name->stream_id,
1790                               share_access, access_mask, delete_on_close,
1791                               NTCREATEX_DISP_OPEN, false);
1792
1793         if (NT_STATUS_IS_OK(status)) {
1794                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1795         }
1796
1797         /*
1798          * if it's a sharing violation or we got no oplock
1799          * only keep the lock if the caller requested access
1800          * to the lock
1801          */
1802         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1803             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1804                 if (lckp) {
1805                         *lckp = lck;
1806                 } else {
1807                         talloc_free(lck);
1808                 }
1809         } else if (!NT_STATUS_IS_OK(status)) {
1810                 talloc_free(lck);
1811                 if (lckp) {
1812                         *lckp = NULL;
1813                 }
1814         } else if (lckp) {
1815                 *lckp = lck;
1816         }
1817
1818         return status;
1819 }
1820
1821 /*
1822   determine if a file can be renamed, or if it is prevented by an
1823   already open file
1824 */
1825 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1826                          struct ntvfs_request *req,
1827                          struct pvfs_filename *name,
1828                          struct odb_lock **lckp)
1829 {
1830         NTSTATUS status;
1831         DATA_BLOB key;
1832         struct odb_lock *lck;
1833         uint32_t share_access;
1834         uint32_t access_mask;
1835         bool delete_on_close;
1836
1837         status = pvfs_locking_key(name, name, &key);
1838         if (!NT_STATUS_IS_OK(status)) {
1839                 return NT_STATUS_NO_MEMORY;
1840         }
1841
1842         lck = odb_lock(req, pvfs->odb_context, &key);
1843         if (lck == NULL) {
1844                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1845                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1846         }
1847
1848         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1849                           NTCREATEX_SHARE_ACCESS_WRITE;
1850         access_mask     = SEC_STD_DELETE;
1851         delete_on_close = false;
1852
1853         status = odb_can_open(lck, name->stream_id,
1854                               share_access, access_mask, delete_on_close,
1855                               NTCREATEX_DISP_OPEN, false);
1856
1857         /*
1858          * if it's a sharing violation or we got no oplock
1859          * only keep the lock if the caller requested access
1860          * to the lock
1861          */
1862         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1863             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1864                 if (lckp) {
1865                         *lckp = lck;
1866                 } else {
1867                         talloc_free(lck);
1868                 }
1869         } else if (!NT_STATUS_IS_OK(status)) {
1870                 talloc_free(lck);
1871                 if (lckp) {
1872                         *lckp = NULL;
1873                 }
1874         } else if (lckp) {
1875                 *lckp = lck;
1876         }
1877
1878         return status;
1879 }
1880
1881 /*
1882   determine if the file size of a file can be changed,
1883   or if it is prevented by an already open file
1884 */
1885 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1886                                    struct ntvfs_request *req,
1887                                    struct pvfs_filename *name,
1888                                    struct odb_lock **lckp)
1889 {
1890         NTSTATUS status;
1891         DATA_BLOB key;
1892         struct odb_lock *lck;
1893         uint32_t share_access;
1894         uint32_t access_mask;
1895         bool break_to_none;
1896         bool delete_on_close;
1897
1898         status = pvfs_locking_key(name, name, &key);
1899         if (!NT_STATUS_IS_OK(status)) {
1900                 return NT_STATUS_NO_MEMORY;
1901         }
1902
1903         lck = odb_lock(req, pvfs->odb_context, &key);
1904         if (lck == NULL) {
1905                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1906                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1907         }
1908
1909         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1910                           NTCREATEX_SHARE_ACCESS_WRITE |
1911                           NTCREATEX_SHARE_ACCESS_DELETE;
1912         /*
1913          * I would have thought that we would need to pass
1914          * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1915          *
1916          * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1917          * to set the filesize.
1918          *
1919          * --metze
1920          */
1921         access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
1922         delete_on_close = false;
1923         break_to_none   = true;
1924
1925         status = odb_can_open(lck, name->stream_id,
1926                               share_access, access_mask, delete_on_close,
1927                               NTCREATEX_DISP_OPEN, break_to_none);
1928
1929         /*
1930          * if it's a sharing violation or we got no oplock
1931          * only keep the lock if the caller requested access
1932          * to the lock
1933          */
1934         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1935             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1936                 if (lckp) {
1937                         *lckp = lck;
1938                 } else {
1939                         talloc_free(lck);
1940                 }
1941         } else if (!NT_STATUS_IS_OK(status)) {
1942                 talloc_free(lck);
1943                 if (lckp) {
1944                         *lckp = NULL;
1945                 }
1946         } else if (lckp) {
1947                 *lckp = lck;
1948         }
1949
1950         return status;
1951 }
1952
1953 /*
1954   determine if file meta data can be accessed, or if it is prevented by an
1955   already open file
1956 */
1957 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1958                        struct ntvfs_request *req,
1959                        struct pvfs_filename *name)
1960 {
1961         NTSTATUS status;
1962         DATA_BLOB key;
1963         struct odb_lock *lck;
1964         uint32_t share_access;
1965         uint32_t access_mask;
1966         bool delete_on_close;
1967
1968         status = pvfs_locking_key(name, name, &key);
1969         if (!NT_STATUS_IS_OK(status)) {
1970                 return NT_STATUS_NO_MEMORY;
1971         }
1972
1973         lck = odb_lock(req, pvfs->odb_context, &key);
1974         if (lck == NULL) {
1975                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1976                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1977         }
1978
1979         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1980                           NTCREATEX_SHARE_ACCESS_WRITE;
1981         access_mask     = SEC_FILE_READ_ATTRIBUTE;
1982         delete_on_close = false;
1983
1984         status = odb_can_open(lck, name->stream_id,
1985                               share_access, access_mask, delete_on_close,
1986                               NTCREATEX_DISP_OPEN, false);
1987
1988         if (!NT_STATUS_IS_OK(status)) {
1989                 talloc_free(lck);
1990         }
1991
1992         return status;
1993 }
1994
1995
1996 /*
1997   determine if delete on close is set on 
1998 */
1999 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2000 {
2001         NTSTATUS status;
2002         bool del_on_close;
2003
2004         status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
2005                                     &del_on_close, NULL);
2006         if (!NT_STATUS_IS_OK(status)) {
2007                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2008                 return false;
2009         }
2010
2011         return del_on_close;
2012 }