8a32f0122335c6549872462d6ee200c93ea2ade6
[kai/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                 DEBUG(2,(__location__ " create_options 0x%x not supported\n", 
1220                          create_options));
1221                 return NT_STATUS_NOT_SUPPORTED;
1222         }
1223
1224         if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1225                 return NT_STATUS_INVALID_PARAMETER;
1226         }
1227
1228         /* TODO: When we implement HSM, add a hook here not to pull
1229          * the actual file off tape, when this option is passed from
1230          * the client */
1231         if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1232                 /* no-op */
1233         }
1234
1235         /* TODO: If (unlikely) Linux does a good compressed
1236          * filesystem, we might need an ioctl call for this */
1237         if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1238                 /* no-op */
1239         }
1240
1241         if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1242                 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1243         }
1244
1245         /* Open the file with sync, if they asked for it, but
1246            'strict sync = no' turns this client request into a no-op */
1247         if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1248                 flags |= O_SYNC;
1249         }
1250
1251
1252         /* other create options are not allowed */
1253         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1254             !(access_mask & SEC_STD_DELETE)) {
1255                 return NT_STATUS_INVALID_PARAMETER;
1256         }
1257
1258         if (access_mask & SEC_MASK_INVALID) {
1259                 return NT_STATUS_ACCESS_DENIED;
1260         }
1261
1262         /* what does this bit really mean?? */
1263         if (req->ctx->protocol == PROTOCOL_SMB2 &&
1264             access_mask == SEC_STD_SYNCHRONIZE) {
1265                 return NT_STATUS_ACCESS_DENIED;
1266         }
1267
1268         if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1269                                           FILE_ATTRIBUTE_VOLUME| 
1270                                           (~FILE_ATTRIBUTE_ALL_MASK))) {
1271                 return NT_STATUS_INVALID_PARAMETER;
1272         }
1273
1274         /* we ignore some file_attr bits */
1275         io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED | 
1276                                         FILE_ATTRIBUTE_COMPRESSED |
1277                                         FILE_ATTRIBUTE_REPARSE_POINT |
1278                                         FILE_ATTRIBUTE_SPARSE |
1279                                         FILE_ATTRIBUTE_NORMAL);
1280
1281         /* resolve the cifs name to a posix name */
1282         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
1283                                    PVFS_RESOLVE_STREAMS, &name);
1284         if (!NT_STATUS_IS_OK(status)) {
1285                 return status;
1286         }
1287
1288         /* if the client specified that it must not be a directory then
1289            check that it isn't */
1290         if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1291             (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1292                 return NT_STATUS_FILE_IS_A_DIRECTORY;
1293         }
1294
1295         /* if the client specified that it must be a directory then
1296            check that it is */
1297         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1298             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1299                 return NT_STATUS_NOT_A_DIRECTORY;
1300         }
1301
1302         /* directory opens are handled separately */
1303         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1304             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1305                 return pvfs_open_directory(pvfs, req, name, io);
1306         }
1307
1308         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1309            open doesn't match */
1310         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1311
1312         switch (io->generic.in.open_disposition) {
1313         case NTCREATEX_DISP_SUPERSEDE:
1314         case NTCREATEX_DISP_OVERWRITE_IF:
1315                 if (name->stream_name == NULL) {
1316                         flags = O_TRUNC;
1317                 } else {
1318                         stream_truncate = true;
1319                 }
1320                 create_action = NTCREATEX_ACTION_TRUNCATED;
1321                 break;
1322
1323         case NTCREATEX_DISP_OPEN:
1324                 if (!name->stream_exists) {
1325                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1326                 }
1327                 flags = 0;
1328                 break;
1329
1330         case NTCREATEX_DISP_OVERWRITE:
1331                 if (!name->stream_exists) {
1332                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1333                 }
1334                 if (name->stream_name == NULL) {
1335                         flags = O_TRUNC;
1336                 } else {
1337                         stream_truncate = true;
1338                 }
1339                 create_action = NTCREATEX_ACTION_TRUNCATED;
1340                 break;
1341
1342         case NTCREATEX_DISP_CREATE:
1343                 if (name->stream_exists) {
1344                         return NT_STATUS_OBJECT_NAME_COLLISION;
1345                 }
1346                 flags = 0;
1347                 break;
1348
1349         case NTCREATEX_DISP_OPEN_IF:
1350                 flags = 0;
1351                 break;
1352
1353         default:
1354                 return NT_STATUS_INVALID_PARAMETER;
1355         }
1356
1357         /* handle creating a new file separately */
1358         if (!name->exists) {
1359                 status = pvfs_create_file(pvfs, req, name, io);
1360                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1361                         return status;
1362                 }
1363
1364                 /* we've hit a race - the file was created during this call */
1365                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1366                         return status;
1367                 }
1368
1369                 /* try re-resolving the name */
1370                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1371                 if (!NT_STATUS_IS_OK(status)) {
1372                         return status;
1373                 }
1374                 /* fall through to a normal open */
1375         }
1376
1377         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1378             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1379                 return NT_STATUS_CANNOT_DELETE;
1380         }
1381
1382         /* check the security descriptor */
1383         status = pvfs_access_check(pvfs, req, name, &access_mask);
1384         NT_STATUS_NOT_OK_RETURN(status);
1385
1386         if (io->generic.in.query_maximal_access) {
1387                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
1388                                                      &io->generic.out.maximal_access);
1389                 NT_STATUS_NOT_OK_RETURN(status);
1390         }
1391
1392         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1393         NT_STATUS_NOT_OK_RETURN(status);
1394
1395         f = talloc(h, struct pvfs_file);
1396         if (f == NULL) {
1397                 return NT_STATUS_NO_MEMORY;
1398         }
1399
1400         f->handle = talloc(f, struct pvfs_file_handle);
1401         if (f->handle == NULL) {
1402                 return NT_STATUS_NO_MEMORY;
1403         }
1404
1405         f->ntvfs         = h;
1406         f->pvfs          = pvfs;
1407         f->pending_list  = NULL;
1408         f->lock_count    = 0;
1409         f->share_access  = io->generic.in.share_access;
1410         f->access_mask   = access_mask;
1411         f->impersonation = io->generic.in.impersonation;
1412         f->notify_buffer = NULL;
1413         f->search        = NULL;
1414
1415         f->handle->pvfs              = pvfs;
1416         f->handle->fd                = -1;
1417         f->handle->name              = talloc_steal(f->handle, name);
1418         f->handle->create_options    = io->generic.in.create_options;
1419         f->handle->seek_offset       = 0;
1420         f->handle->position          = 0;
1421         f->handle->mode              = 0;
1422         f->handle->oplock            = NULL;
1423         f->handle->have_opendb_entry = false;
1424         ZERO_STRUCT(f->handle->write_time);
1425         f->handle->open_completed    = false;
1426
1427         /* form the lock context used for byte range locking and
1428            opendb locking */
1429         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1430         if (!NT_STATUS_IS_OK(status)) {
1431                 return status;
1432         }
1433
1434         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1435         if (!NT_STATUS_IS_OK(status)) {
1436                 return status;
1437         }
1438
1439         /* get a lock on this file before the actual open */
1440         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1441         if (lck == NULL) {
1442                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1443                          name->full_name));
1444                 /* we were supposed to do a blocking lock, so something
1445                    is badly wrong! */
1446                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1447         }
1448
1449         DLIST_ADD(pvfs->files.list, f);
1450
1451         /* setup a destructor to avoid file descriptor leaks on
1452            abnormal termination */
1453         talloc_set_destructor(f, pvfs_fnum_destructor);
1454         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1455
1456         /* 
1457          * Only SMB2 takes care of the delete_on_close,
1458          * on existing files
1459          */
1460         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1461             req->ctx->protocol == PROTOCOL_SMB2) {
1462                 del_on_close = true;
1463         } else {
1464                 del_on_close = false;
1465         }
1466
1467         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1468                 oplock_level = OPLOCK_NONE;
1469         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1470                 oplock_level = OPLOCK_BATCH;
1471         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1472                 oplock_level = OPLOCK_EXCLUSIVE;
1473         }
1474
1475         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1476                 allow_level_II_oplock = true;
1477         }
1478
1479         /* see if we are allowed to open at the same time as existing opens */
1480         status = odb_can_open(lck, name->stream_id,
1481                               share_access, access_mask, del_on_close,
1482                               io->generic.in.open_disposition, false);
1483
1484         /*
1485          * on a sharing violation we need to retry when the file is closed by
1486          * the other user, or after 1 second
1487          * on a non granted oplock we need to retry when the file is closed by
1488          * the other user, or after 30 seconds
1489         */
1490         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1491              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1492             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1493                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1494         }
1495
1496         if (!NT_STATUS_IS_OK(status)) {
1497                 talloc_free(lck);
1498                 return status;
1499         }
1500
1501         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1502                 flags |= O_RDWR;
1503         } else {
1504                 flags |= O_RDONLY;
1505         }
1506
1507         /* do the actual open */
1508         fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1509         if (fd == -1) {
1510                 status = pvfs_map_errno(f->pvfs, errno);
1511
1512                 /*
1513                  * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1514                  */
1515                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1516                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1517                         return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1518                 }
1519
1520                 talloc_free(lck);
1521                 return status;
1522         }
1523
1524         f->handle->fd = fd;
1525
1526         /* now really mark the file as open */
1527         status = odb_open_file(lck, f->handle, name->full_name,
1528                                &f->handle->fd, name->dos.write_time,
1529                                allow_level_II_oplock,
1530                                oplock_level, &oplock_granted);
1531
1532         if (!NT_STATUS_IS_OK(status)) {
1533                 talloc_free(lck);
1534                 return status;
1535         }
1536
1537         f->handle->have_opendb_entry = true;
1538
1539         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1540                 oplock_granted = OPLOCK_BATCH;
1541         } else if (oplock_granted != OPLOCK_NONE) {
1542                 status = pvfs_setup_oplock(f, oplock_granted);
1543                 if (!NT_STATUS_IS_OK(status)) {
1544                         talloc_free(lck);
1545                         return status;
1546                 }
1547         }
1548
1549         stream_existed = name->stream_exists;
1550
1551         /* if this was a stream create then create the stream as well */
1552         if (!name->stream_exists) {
1553                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1554                 if (!NT_STATUS_IS_OK(status)) {
1555                         talloc_free(lck);
1556                         return status;
1557                 }
1558                 if (stream_truncate) {
1559                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1560                         if (!NT_STATUS_IS_OK(status)) {
1561                                 talloc_free(lck);
1562                                 return status;
1563                         }
1564                 }
1565         }
1566
1567         /* re-resolve the open fd */
1568         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1569         if (!NT_STATUS_IS_OK(status)) {
1570                 talloc_free(lck);
1571                 return status;
1572         }
1573
1574         if (f->handle->name->stream_id == 0 &&
1575             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1576              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1577                 /* for overwrite we need to replace file permissions */
1578                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1579                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1580                 if (fchmod(fd, mode) == -1) {
1581                         talloc_free(lck);
1582                         return pvfs_map_errno(pvfs, errno);
1583                 }
1584                 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1585                 name->dos.attrib = attrib;
1586                 status = pvfs_dosattrib_save(pvfs, name, fd);
1587                 if (!NT_STATUS_IS_OK(status)) {
1588                         talloc_free(lck);
1589                         return status;
1590                 }
1591         }
1592             
1593         talloc_free(lck);
1594
1595         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1596         NT_STATUS_NOT_OK_RETURN(status);
1597
1598         /* mark the open as having completed fully, so delete on close
1599            can now be used */
1600         f->handle->open_completed     = true;
1601
1602         io->generic.out.oplock_level  = oplock_granted;
1603         io->generic.out.file.ntvfs    = h;
1604         io->generic.out.create_action = stream_existed?
1605                 create_action:NTCREATEX_ACTION_CREATED;
1606         
1607         io->generic.out.create_time   = name->dos.create_time;
1608         io->generic.out.access_time   = name->dos.access_time;
1609         io->generic.out.write_time    = name->dos.write_time;
1610         io->generic.out.change_time   = name->dos.change_time;
1611         io->generic.out.attrib        = name->dos.attrib;
1612         io->generic.out.alloc_size    = name->dos.alloc_size;
1613         io->generic.out.size          = name->st.st_size;
1614         io->generic.out.file_type     = FILE_TYPE_DISK;
1615         io->generic.out.ipc_state     = 0;
1616         io->generic.out.is_directory  = 0;
1617
1618         return NT_STATUS_OK;
1619 }
1620
1621
1622 /*
1623   close a file
1624 */
1625 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1626                     struct ntvfs_request *req, union smb_close *io)
1627 {
1628         struct pvfs_state *pvfs = ntvfs->private_data;
1629         struct pvfs_file *f;
1630
1631         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1632                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1633         }
1634
1635         if (io->generic.level != RAW_CLOSE_GENERIC) {
1636                 return ntvfs_map_close(ntvfs, req, io);
1637         }
1638
1639         f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1640         if (!f) {
1641                 return NT_STATUS_INVALID_HANDLE;
1642         }
1643
1644         if (!null_time(io->generic.in.write_time)) {
1645                 f->handle->write_time.update_forced = false;
1646                 f->handle->write_time.update_on_close = true;
1647                 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1648         }
1649
1650         if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1651                 struct pvfs_filename *name;
1652                 NTSTATUS status;
1653                 struct pvfs_file_handle *h = f->handle;
1654
1655                 status = pvfs_resolve_name_handle(pvfs, h);
1656                 if (!NT_STATUS_IS_OK(status)) {
1657                         return status;
1658                 }
1659                 name = h->name;
1660
1661                 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1662                 io->generic.out.create_time = name->dos.create_time;
1663                 io->generic.out.access_time = name->dos.access_time;
1664                 io->generic.out.write_time  = name->dos.write_time;
1665                 io->generic.out.change_time = name->dos.change_time;
1666                 io->generic.out.alloc_size  = name->dos.alloc_size;
1667                 io->generic.out.size        = name->st.st_size;
1668                 io->generic.out.file_attr   = name->dos.attrib;         
1669         } else {
1670                 ZERO_STRUCT(io->generic.out);
1671         }
1672
1673         talloc_free(f);
1674
1675         return NT_STATUS_OK;
1676 }
1677
1678
1679 /*
1680   logoff - close all file descriptors open by a vuid
1681 */
1682 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1683                      struct ntvfs_request *req)
1684 {
1685         struct pvfs_state *pvfs = ntvfs->private_data;
1686         struct pvfs_file *f, *next;
1687
1688         for (f=pvfs->files.list;f;f=next) {
1689                 next = f->next;
1690                 if (f->ntvfs->session_info == req->session_info) {
1691                         talloc_free(f);
1692                 }
1693         }
1694
1695         return NT_STATUS_OK;
1696 }
1697
1698
1699 /*
1700   exit - close files for the current pid
1701 */
1702 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1703                    struct ntvfs_request *req)
1704 {
1705         struct pvfs_state *pvfs = ntvfs->private_data;
1706         struct pvfs_file *f, *next;
1707
1708         for (f=pvfs->files.list;f;f=next) {
1709                 next = f->next;
1710                 if (f->ntvfs->session_info == req->session_info &&
1711                     f->ntvfs->smbpid == req->smbpid) {
1712                         talloc_free(f);
1713                 }
1714         }
1715
1716         return NT_STATUS_OK;
1717 }
1718
1719
1720 /*
1721   change the delete on close flag on an already open file
1722 */
1723 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1724                                   struct ntvfs_request *req, 
1725                                   struct pvfs_file *f, bool del_on_close)
1726 {
1727         struct odb_lock *lck;
1728         NTSTATUS status;
1729
1730         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1731                 return NT_STATUS_CANNOT_DELETE;
1732         }
1733         
1734         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1735             !pvfs_directory_empty(pvfs, f->handle->name)) {
1736                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1737         }
1738
1739         if (del_on_close) {
1740                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1741         } else {
1742                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1743         }
1744         
1745         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1746         if (lck == NULL) {
1747                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1748         }
1749
1750         status = odb_set_delete_on_close(lck, del_on_close);
1751
1752         talloc_free(lck);
1753
1754         return status;
1755 }
1756
1757
1758 /*
1759   determine if a file can be deleted, or if it is prevented by an
1760   already open file
1761 */
1762 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1763                          struct ntvfs_request *req,
1764                          struct pvfs_filename *name,
1765                          struct odb_lock **lckp)
1766 {
1767         NTSTATUS status;
1768         DATA_BLOB key;
1769         struct odb_lock *lck;
1770         uint32_t share_access;
1771         uint32_t access_mask;
1772         bool delete_on_close;
1773
1774         status = pvfs_locking_key(name, name, &key);
1775         if (!NT_STATUS_IS_OK(status)) {
1776                 return NT_STATUS_NO_MEMORY;
1777         }
1778
1779         lck = odb_lock(req, pvfs->odb_context, &key);
1780         if (lck == NULL) {
1781                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1782                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1783         }
1784
1785         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1786                           NTCREATEX_SHARE_ACCESS_WRITE |
1787                           NTCREATEX_SHARE_ACCESS_DELETE;
1788         access_mask     = SEC_STD_DELETE;
1789         delete_on_close = true;
1790
1791         status = odb_can_open(lck, name->stream_id,
1792                               share_access, access_mask, delete_on_close,
1793                               NTCREATEX_DISP_OPEN, false);
1794
1795         if (NT_STATUS_IS_OK(status)) {
1796                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1797         }
1798
1799         /*
1800          * if it's a sharing violation or we got no oplock
1801          * only keep the lock if the caller requested access
1802          * to the lock
1803          */
1804         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1805             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1806                 if (lckp) {
1807                         *lckp = lck;
1808                 } else {
1809                         talloc_free(lck);
1810                 }
1811         } else if (!NT_STATUS_IS_OK(status)) {
1812                 talloc_free(lck);
1813                 if (lckp) {
1814                         *lckp = NULL;
1815                 }
1816         } else if (lckp) {
1817                 *lckp = lck;
1818         }
1819
1820         return status;
1821 }
1822
1823 /*
1824   determine if a file can be renamed, or if it is prevented by an
1825   already open file
1826 */
1827 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
1828                          struct ntvfs_request *req,
1829                          struct pvfs_filename *name,
1830                          struct odb_lock **lckp)
1831 {
1832         NTSTATUS status;
1833         DATA_BLOB key;
1834         struct odb_lock *lck;
1835         uint32_t share_access;
1836         uint32_t access_mask;
1837         bool delete_on_close;
1838
1839         status = pvfs_locking_key(name, name, &key);
1840         if (!NT_STATUS_IS_OK(status)) {
1841                 return NT_STATUS_NO_MEMORY;
1842         }
1843
1844         lck = odb_lock(req, pvfs->odb_context, &key);
1845         if (lck == NULL) {
1846                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1847                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1848         }
1849
1850         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1851                           NTCREATEX_SHARE_ACCESS_WRITE;
1852         access_mask     = SEC_STD_DELETE;
1853         delete_on_close = false;
1854
1855         status = odb_can_open(lck, name->stream_id,
1856                               share_access, access_mask, delete_on_close,
1857                               NTCREATEX_DISP_OPEN, false);
1858
1859         /*
1860          * if it's a sharing violation or we got no oplock
1861          * only keep the lock if the caller requested access
1862          * to the lock
1863          */
1864         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1865             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1866                 if (lckp) {
1867                         *lckp = lck;
1868                 } else {
1869                         talloc_free(lck);
1870                 }
1871         } else if (!NT_STATUS_IS_OK(status)) {
1872                 talloc_free(lck);
1873                 if (lckp) {
1874                         *lckp = NULL;
1875                 }
1876         } else if (lckp) {
1877                 *lckp = lck;
1878         }
1879
1880         return status;
1881 }
1882
1883 /*
1884   determine if the file size of a file can be changed,
1885   or if it is prevented by an already open file
1886 */
1887 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1888                                    struct ntvfs_request *req,
1889                                    struct pvfs_filename *name,
1890                                    struct odb_lock **lckp)
1891 {
1892         NTSTATUS status;
1893         DATA_BLOB key;
1894         struct odb_lock *lck;
1895         uint32_t share_access;
1896         uint32_t access_mask;
1897         bool break_to_none;
1898         bool delete_on_close;
1899
1900         status = pvfs_locking_key(name, name, &key);
1901         if (!NT_STATUS_IS_OK(status)) {
1902                 return NT_STATUS_NO_MEMORY;
1903         }
1904
1905         lck = odb_lock(req, pvfs->odb_context, &key);
1906         if (lck == NULL) {
1907                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1908                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1909         }
1910
1911         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1912                           NTCREATEX_SHARE_ACCESS_WRITE |
1913                           NTCREATEX_SHARE_ACCESS_DELETE;
1914         /*
1915          * I would have thought that we would need to pass
1916          * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1917          *
1918          * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1919          * to set the filesize.
1920          *
1921          * --metze
1922          */
1923         access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
1924         delete_on_close = false;
1925         break_to_none   = true;
1926
1927         status = odb_can_open(lck, name->stream_id,
1928                               share_access, access_mask, delete_on_close,
1929                               NTCREATEX_DISP_OPEN, break_to_none);
1930
1931         /*
1932          * if it's a sharing violation or we got no oplock
1933          * only keep the lock if the caller requested access
1934          * to the lock
1935          */
1936         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1937             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1938                 if (lckp) {
1939                         *lckp = lck;
1940                 } else {
1941                         talloc_free(lck);
1942                 }
1943         } else if (!NT_STATUS_IS_OK(status)) {
1944                 talloc_free(lck);
1945                 if (lckp) {
1946                         *lckp = NULL;
1947                 }
1948         } else if (lckp) {
1949                 *lckp = lck;
1950         }
1951
1952         return status;
1953 }
1954
1955 /*
1956   determine if file meta data can be accessed, or if it is prevented by an
1957   already open file
1958 */
1959 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
1960                        struct ntvfs_request *req,
1961                        struct pvfs_filename *name)
1962 {
1963         NTSTATUS status;
1964         DATA_BLOB key;
1965         struct odb_lock *lck;
1966         uint32_t share_access;
1967         uint32_t access_mask;
1968         bool delete_on_close;
1969
1970         status = pvfs_locking_key(name, name, &key);
1971         if (!NT_STATUS_IS_OK(status)) {
1972                 return NT_STATUS_NO_MEMORY;
1973         }
1974
1975         lck = odb_lock(req, pvfs->odb_context, &key);
1976         if (lck == NULL) {
1977                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1978                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1979         }
1980
1981         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1982                           NTCREATEX_SHARE_ACCESS_WRITE;
1983         access_mask     = SEC_FILE_READ_ATTRIBUTE;
1984         delete_on_close = false;
1985
1986         status = odb_can_open(lck, name->stream_id,
1987                               share_access, access_mask, delete_on_close,
1988                               NTCREATEX_DISP_OPEN, false);
1989
1990         if (!NT_STATUS_IS_OK(status)) {
1991                 talloc_free(lck);
1992         }
1993
1994         return status;
1995 }
1996
1997
1998 /*
1999   determine if delete on close is set on 
2000 */
2001 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2002 {
2003         NTSTATUS status;
2004         bool del_on_close;
2005
2006         status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
2007                                     &del_on_close, NULL);
2008         if (!NT_STATUS_IS_OK(status)) {
2009                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2010                 return false;
2011         }
2012
2013         return del_on_close;
2014 }