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