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