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