1695d8e1d9bb50dd703e13d492922cfc953c9081
[samba.git] / source4 / ntvfs / posix / pvfs_open.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - open and close
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "vfs_posix.h"
25 #include "system/time.h"
26 #include "system/filesys.h"
27 #include "dlinklist.h"
28 #include "messages.h"
29 #include "librpc/gen_ndr/ndr_xattr.h"
30
31 /*
32   create file handles with convenient numbers for sniffers
33 */
34 #define PVFS_MIN_FILE_FNUM 0x100
35 #define PVFS_MIN_NEW_FNUM  0x200
36 #define PVFS_MIN_DIR_FNUM  0x300
37
38 /*
39   find open file handle given fnum
40 */
41 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
42                                struct smbsrv_request *req, uint16_t fnum)
43 {
44         struct pvfs_file *f;
45
46         f = idr_find(pvfs->idtree_fnum, fnum);
47         if (f == NULL) {
48                 return NULL;
49         }
50
51         if (f->fnum != fnum) {
52                 smb_panic("pvfs_find_fd: idtree_fnum corruption\n");
53         }
54
55         if (req->session != f->session) {
56                 DEBUG(2,("pvfs_find_fd: attempt to use wrong session for fnum %d\n", 
57                          fnum));
58                 return NULL;
59         }
60
61         return f;
62 }
63
64
65 /*
66   cleanup a open directory handle
67 */
68 static int pvfs_dir_handle_destructor(void *p)
69 {
70         struct pvfs_file_handle *h = p;
71
72         if (h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
73                 NTSTATUS status = pvfs_xattr_unlink_hook(h->pvfs, h->name->full_name);
74                 if (!NT_STATUS_IS_OK(status)) {
75                         DEBUG(0,("Warning: xattr rmdir hook failed for '%s' - %s\n",
76                                  h->name->full_name, nt_errstr(status)));
77                 }
78                 if (rmdir(h->name->full_name) != 0) {
79                         DEBUG(0,("pvfs_close: failed to rmdir '%s' - %s\n", 
80                                  h->name->full_name, strerror(errno)));
81                 }
82         }
83
84         return 0;
85 }
86
87 /*
88   cleanup a open directory fnum
89 */
90 static int pvfs_dir_fnum_destructor(void *p)
91 {
92         struct pvfs_file *f = p;
93         DLIST_REMOVE(f->pvfs->open_files, f);
94         idr_remove(f->pvfs->idtree_fnum, f->fnum);
95         return 0;
96 }
97
98 /*
99   setup any EAs and the ACL on newly created files/directories
100 */
101 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
102                                         struct smbsrv_request *req,
103                                         struct pvfs_filename *name,
104                                         int fd, int fnum,
105                                         union smb_open *io)
106 {
107         NTSTATUS status;
108
109         /* setup any EAs that were asked for */
110         if (io->ntcreatex.in.ea_list) {
111                 status = pvfs_setfileinfo_ea_set(pvfs, name, fd, 
112                                                  io->ntcreatex.in.ea_list->num_eas,
113                                                  io->ntcreatex.in.ea_list->eas);
114                 if (!NT_STATUS_IS_OK(status)) {
115                         return status;
116                 }
117         }
118
119         /* setup an initial sec_desc if requested */
120         if (io->ntcreatex.in.sec_desc) {
121                 union smb_setfileinfo set;
122
123                 set.set_secdesc.file.fnum = fnum;
124                 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
125                 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
126
127                 status = pvfs_acl_set(pvfs, req, name, fd, &set);
128         } else {
129                 /* otherwise setup an inherited acl from the parent */
130                 status = pvfs_acl_inherit(pvfs, req, name, fd);
131         }
132
133         return status;
134 }
135
136 /*
137   open a directory
138 */
139 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, 
140                                     struct smbsrv_request *req, 
141                                     struct pvfs_filename *name, 
142                                     union smb_open *io)
143 {
144         struct pvfs_file *f;
145         int fnum;
146         NTSTATUS status;
147         uint32_t create_action;
148         uint32_t access_mask = io->generic.in.access_mask;
149
150         if (name->stream_name) {
151                 return NT_STATUS_NOT_A_DIRECTORY;
152         }
153
154         /* if the client says it must be a directory, and it isn't,
155            then fail */
156         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
157                 return NT_STATUS_NOT_A_DIRECTORY;
158         }
159
160         switch (io->generic.in.open_disposition) {
161         case NTCREATEX_DISP_OPEN_IF:
162                 break;
163
164         case NTCREATEX_DISP_OPEN:
165                 if (!name->exists) {
166                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
167                 }
168                 break;
169
170         case NTCREATEX_DISP_CREATE:
171                 if (name->exists) {
172                         return NT_STATUS_OBJECT_NAME_COLLISION;
173                 }
174                 break;
175
176         case NTCREATEX_DISP_OVERWRITE_IF:
177         case NTCREATEX_DISP_OVERWRITE:
178         case NTCREATEX_DISP_SUPERSEDE:
179         default:
180                 return NT_STATUS_INVALID_PARAMETER;
181         }
182
183         f = talloc_p(req, struct pvfs_file);
184         if (f == NULL) {
185                 return NT_STATUS_NO_MEMORY;
186         }
187
188         f->handle = talloc_p(f, struct pvfs_file_handle);
189         if (f->handle == NULL) {
190                 return NT_STATUS_NO_MEMORY;
191         }
192
193         fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_DIR_FNUM, UINT16_MAX);
194         if (fnum == -1) {
195                 return NT_STATUS_TOO_MANY_OPENED_FILES;
196         }
197
198         if (name->exists) {
199                 /* check the security descriptor */
200                 status = pvfs_access_check(pvfs, req, name, &access_mask);
201                 if (!NT_STATUS_IS_OK(status)) {
202                         idr_remove(pvfs->idtree_fnum, fnum);
203                         return status;
204                 }
205         }
206
207         f->fnum          = fnum;
208         f->session       = req->session;
209         f->smbpid        = req->smbpid;
210         f->pvfs          = pvfs;
211         f->pending_list  = NULL;
212         f->lock_count    = 0;
213         f->share_access  = io->generic.in.share_access;
214         f->impersonation = io->generic.in.impersonation;
215         f->access_mask   = access_mask;
216
217         f->handle->pvfs              = pvfs;
218         f->handle->name              = talloc_steal(f->handle, name);
219         f->handle->fd                = -1;
220         f->handle->odb_locking_key   = data_blob(NULL, 0);
221         f->handle->brl_locking_key   = data_blob(NULL, 0);
222         f->handle->create_options    = io->generic.in.create_options;
223         f->handle->seek_offset       = 0;
224         f->handle->position          = 0;
225         f->handle->mode              = 0;
226         f->handle->sticky_write_time = False;
227
228         DLIST_ADD(pvfs->open_files, f);
229
230         /* TODO: should we check in the opendb? Do directory opens 
231            follow the share_access rules? */
232
233         /* setup destructors to avoid leaks on abnormal termination */
234         talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
235         talloc_set_destructor(f, pvfs_dir_fnum_destructor);
236
237         if (!name->exists) {
238                 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
239                 mode_t mode = pvfs_fileperms(pvfs, attrib);
240                 if (mkdir(name->full_name, mode) == -1) {
241                         idr_remove(pvfs->idtree_fnum, fnum);
242                         return pvfs_map_errno(pvfs,errno);
243                 }
244
245                 pvfs_xattr_unlink_hook(pvfs, name->full_name);
246
247                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
248                 if (!NT_STATUS_IS_OK(status)) {
249                         goto cleanup_delete;
250                 }
251
252                 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, fnum, io);
253                 if (!NT_STATUS_IS_OK(status)) {
254                         goto cleanup_delete;
255                 }
256
257                 create_action = NTCREATEX_ACTION_CREATED;
258         } else {
259                 create_action = NTCREATEX_ACTION_EXISTED;
260         }
261
262         if (!name->exists) {
263                 idr_remove(pvfs->idtree_fnum, fnum);
264                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
265         }
266
267         /* the open succeeded, keep this handle permanently */
268         talloc_steal(pvfs, f);
269
270         io->generic.out.oplock_level  = OPLOCK_NONE;
271         io->generic.out.fnum          = f->fnum;
272         io->generic.out.create_action = create_action;
273         io->generic.out.create_time   = name->dos.create_time;
274         io->generic.out.access_time   = name->dos.access_time;
275         io->generic.out.write_time    = name->dos.write_time;
276         io->generic.out.change_time   = name->dos.change_time;
277         io->generic.out.attrib        = name->dos.attrib;
278         io->generic.out.alloc_size    = name->dos.alloc_size;
279         io->generic.out.size          = name->st.st_size;
280         io->generic.out.file_type     = FILE_TYPE_DISK;
281         io->generic.out.ipc_state     = 0;
282         io->generic.out.is_directory  = 1;
283
284         return NT_STATUS_OK;
285
286 cleanup_delete:
287         idr_remove(pvfs->idtree_fnum, fnum);
288         rmdir(name->full_name);
289         return status;
290 }
291
292 /*
293   destroy a struct pvfs_file_handle
294 */
295 static int pvfs_handle_destructor(void *p)
296 {
297         struct pvfs_file_handle *h = p;
298
299         /* the write time is no longer sticky */
300         if (h->sticky_write_time) {
301                 NTSTATUS status;
302                 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
303                 if (NT_STATUS_IS_OK(status)) {
304                         h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
305                         pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
306                 }
307         }
308         
309         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
310             h->name->stream_name) {
311                 NTSTATUS status;
312                 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
313                 if (!NT_STATUS_IS_OK(status)) {
314                         DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
315                                  h->name->stream_name, h->name->full_name));
316                 }
317         }
318
319         if (h->fd != -1) {
320                 if (close(h->fd) != 0) {
321                         DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
322                                  h->fd, h->name->full_name, strerror(errno)));
323                 }
324                 h->fd = -1;
325         }
326
327         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
328             h->name->stream_name == NULL) {
329                 NTSTATUS status;
330                 status = pvfs_xattr_unlink_hook(h->pvfs, h->name->full_name);
331                 if (!NT_STATUS_IS_OK(status)) {
332                         DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
333                                  h->name->full_name, nt_errstr(status)));
334                 }
335                 if (unlink(h->name->full_name) != 0) {
336                         DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", 
337                                  h->name->full_name, strerror(errno)));
338                 }
339         }
340
341         if (h->have_opendb_entry) {
342                 struct odb_lock *lck;
343                 NTSTATUS status;
344
345                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
346                 if (lck == NULL) {
347                         DEBUG(0,("Unable to lock opendb for close\n"));
348                         return 0;
349                 }
350
351                 status = odb_close_file(lck, h);
352                 if (!NT_STATUS_IS_OK(status)) {
353                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
354                                  h->name->full_name, nt_errstr(status)));
355                 }
356
357                 talloc_free(lck);
358         }
359
360         return 0;
361 }
362
363
364 /*
365   destroy a struct pvfs_file
366 */
367 static int pvfs_fnum_destructor(void *p)
368 {
369         struct pvfs_file *f = p;
370
371         DLIST_REMOVE(f->pvfs->open_files, f);
372         pvfs_lock_close(f->pvfs, f);
373         idr_remove(f->pvfs->idtree_fnum, f->fnum);
374
375         return 0;
376 }
377
378
379 /*
380   form the lock context used for opendb locking. Note that we must
381   zero here to take account of possible padding on some architectures
382 */
383 static NTSTATUS pvfs_locking_key(struct pvfs_filename *name, 
384                                  TALLOC_CTX *mem_ctx, DATA_BLOB *key)
385 {
386         struct {
387                 dev_t device;
388                 ino_t inode;
389         } lock_context;
390         ZERO_STRUCT(lock_context);
391
392         lock_context.device = name->st.st_dev;
393         lock_context.inode = name->st.st_ino;
394
395         *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
396         if (key->data == NULL) {
397                 return NT_STATUS_NO_MEMORY;
398         }
399         
400         return NT_STATUS_OK;
401 }
402
403 /*
404   form the lock context used for byte range locking. This is separate
405   from the locking key used for opendb locking as it needs to take
406   account of file streams (each stream is a separate byte range
407   locking space)
408 */
409 static NTSTATUS pvfs_brl_locking_key(struct pvfs_filename *name, 
410                                      TALLOC_CTX *mem_ctx, DATA_BLOB *key)
411 {
412         DATA_BLOB odb_key;
413         NTSTATUS status;
414         status = pvfs_locking_key(name, mem_ctx, &odb_key);
415         if (!NT_STATUS_IS_OK(status)) {
416                 return status;
417         }
418         if (name->stream_name == NULL) {
419                 *key = odb_key;
420                 return NT_STATUS_OK;
421         }
422         *key = data_blob_talloc(mem_ctx, NULL, 
423                                 odb_key.length + strlen(name->stream_name) + 1);
424         if (key->data == NULL) {
425                 return NT_STATUS_NO_MEMORY;
426         }
427         memcpy(key->data, odb_key.data, odb_key.length);
428         memcpy(key->data + odb_key.length, 
429                name->stream_name, strlen(name->stream_name)+1);
430         data_blob_free(&odb_key);
431         return NT_STATUS_OK;
432 }
433
434
435 /*
436   create a new file
437 */
438 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 
439                                  struct smbsrv_request *req, 
440                                  struct pvfs_filename *name, 
441                                  union smb_open *io)
442 {
443         struct pvfs_file *f;
444         NTSTATUS status;
445         int flags, fnum, fd;
446         struct odb_lock *lck;
447         uint32_t create_options = io->generic.in.create_options;
448         uint32_t share_access = io->generic.in.share_access;
449         uint32_t access_mask = io->generic.in.access_mask;
450         mode_t mode;
451         uint32_t attrib;
452
453         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
454             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
455                 return NT_STATUS_CANNOT_DELETE;
456         }
457         
458         if (access_mask & SEC_FLAG_MAXIMUM_ALLOWED) {
459                 access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
460         }
461
462         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
463                 flags = O_RDWR;
464         } else {
465                 flags = O_RDONLY;
466         }
467
468         f = talloc_p(req, struct pvfs_file);
469         if (f == NULL) {
470                 return NT_STATUS_NO_MEMORY;
471         }
472
473         f->handle = talloc_p(f, struct pvfs_file_handle);
474         if (f->handle == NULL) {
475                 return NT_STATUS_NO_MEMORY;
476         }
477
478         fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_NEW_FNUM, UINT16_MAX);
479         if (fnum == -1) {
480                 return NT_STATUS_TOO_MANY_OPENED_FILES;
481         }
482
483         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
484         mode = pvfs_fileperms(pvfs, attrib);
485
486         /* create the file */
487         fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
488         if (fd == -1) {
489                 idr_remove(pvfs->idtree_fnum, fnum);
490                 return pvfs_map_errno(pvfs, errno);
491         }
492
493         pvfs_xattr_unlink_hook(pvfs, name->full_name);
494
495         /* if this was a stream create then create the stream as well */
496         if (name->stream_name) {
497                 status = pvfs_stream_create(pvfs, name, fd);
498                 if (!NT_STATUS_IS_OK(status)) {
499                         idr_remove(pvfs->idtree_fnum, fnum);
500                         close(fd);
501                         return status;
502                 }
503         }
504
505         /* re-resolve the open fd */
506         status = pvfs_resolve_name_fd(pvfs, fd, name);
507         if (!NT_STATUS_IS_OK(status)) {
508                 idr_remove(pvfs->idtree_fnum, fnum);
509                 close(fd);
510                 return status;
511         }
512
513         name->dos.attrib = attrib;
514         status = pvfs_dosattrib_save(pvfs, name, fd);
515         if (!NT_STATUS_IS_OK(status)) {
516                 goto cleanup_delete;
517         }
518
519
520         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, fnum, io);
521         if (!NT_STATUS_IS_OK(status)) {
522                 goto cleanup_delete;
523         }
524
525         /* form the lock context used for byte range locking and
526            opendb locking */
527         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
528         if (!NT_STATUS_IS_OK(status)) {
529                 goto cleanup_delete;
530         }
531
532         status = pvfs_brl_locking_key(name, f->handle, &f->handle->brl_locking_key);
533         if (!NT_STATUS_IS_OK(status)) {
534                 goto cleanup_delete;
535         }
536
537         /* grab a lock on the open file record */
538         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
539         if (lck == NULL) {
540                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
541                          name->full_name));
542                 /* we were supposed to do a blocking lock, so something
543                    is badly wrong! */
544                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
545                 goto cleanup_delete;
546         }
547
548         status = odb_open_file(lck, f->handle, name->stream_id,
549                                share_access, create_options, access_mask);
550         talloc_free(lck);
551         if (!NT_STATUS_IS_OK(status)) {
552                 /* bad news, we must have hit a race - we don't delete the file
553                    here as the most likely scenario is that someone else created 
554                    the file at the same time */
555                 idr_remove(pvfs->idtree_fnum, fnum);
556                 close(fd);
557                 return status;
558         }
559
560         f->fnum              = fnum;
561         f->session           = req->session;
562         f->smbpid            = req->smbpid;
563         f->pvfs              = pvfs;
564         f->pending_list      = NULL;
565         f->lock_count        = 0;
566         f->share_access      = io->generic.in.share_access;
567         f->access_mask       = access_mask;
568         f->impersonation     = io->generic.in.impersonation;
569
570         f->handle->pvfs              = pvfs;
571         f->handle->name              = talloc_steal(f->handle, name);
572         f->handle->fd                = fd;
573         f->handle->create_options    = io->generic.in.create_options;
574         f->handle->seek_offset       = 0;
575         f->handle->position          = 0;
576         f->handle->mode              = 0;
577         f->handle->have_opendb_entry = True;
578         f->handle->sticky_write_time = False;
579
580         DLIST_ADD(pvfs->open_files, f);
581
582         /* setup a destructor to avoid file descriptor leaks on
583            abnormal termination */
584         talloc_set_destructor(f, pvfs_fnum_destructor);
585         talloc_set_destructor(f->handle, pvfs_handle_destructor);
586
587         
588         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
589                 io->generic.out.oplock_level  = OPLOCK_EXCLUSIVE;
590         } else {
591                 io->generic.out.oplock_level  = OPLOCK_NONE;
592         }
593         io->generic.out.fnum          = f->fnum;
594         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
595         io->generic.out.create_time   = name->dos.create_time;
596         io->generic.out.access_time   = name->dos.access_time;
597         io->generic.out.write_time    = name->dos.write_time;
598         io->generic.out.change_time   = name->dos.change_time;
599         io->generic.out.attrib        = name->dos.attrib;
600         io->generic.out.alloc_size    = name->dos.alloc_size;
601         io->generic.out.size          = name->st.st_size;
602         io->generic.out.file_type     = FILE_TYPE_DISK;
603         io->generic.out.ipc_state     = 0;
604         io->generic.out.is_directory  = 0;
605
606         /* success - keep the file handle */
607         talloc_steal(pvfs, f);
608
609         return NT_STATUS_OK;
610
611 cleanup_delete:
612         idr_remove(pvfs->idtree_fnum, fnum);
613         close(fd);
614         unlink(name->full_name);
615         return status;
616 }
617
618
619 /*
620   state of a pending open retry
621 */
622 struct pvfs_open_retry {
623         struct ntvfs_module_context *ntvfs;
624         struct smbsrv_request *req;
625         union smb_open *io;
626         void *wait_handle;
627         DATA_BLOB odb_locking_key;
628 };
629
630 /* destroy a pending open request */
631 static int pvfs_retry_destructor(void *ptr)
632 {
633         struct pvfs_open_retry *r = ptr;
634         struct pvfs_state *pvfs = r->ntvfs->private_data;
635         if (r->odb_locking_key.data) {
636                 struct odb_lock *lck;
637                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
638                 if (lck != NULL) {
639                         odb_remove_pending(lck, r);
640                 }
641                 talloc_free(lck);
642         }
643         return 0;
644 }
645
646 /*
647   retry an open
648 */
649 static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
650 {
651         struct pvfs_open_retry *r = private;
652         struct ntvfs_module_context *ntvfs = r->ntvfs;
653         struct smbsrv_request *req = r->req;
654         union smb_open *io = r->io;
655         NTSTATUS status;
656
657         /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
658            just a bug in their server, but we better do the same */
659         if (reason == PVFS_WAIT_CANCEL) {
660                 return;
661         }
662
663         talloc_free(r->wait_handle);
664
665         if (reason == PVFS_WAIT_TIMEOUT) {
666                 /* if it timed out, then give the failure
667                    immediately */
668                 talloc_free(r);
669                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
670                 req->async_states->send_fn(req);
671                 return;
672         }
673
674         /* the pending odb entry is already removed. We use a null locking
675            key to indicate this */
676         data_blob_free(&r->odb_locking_key);
677         talloc_free(r);
678
679         /* try the open again, which could trigger another retry setup
680            if it wants to, so we have to unmark the async flag so we
681            will know if it does a second async reply */
682         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
683
684         status = pvfs_open(ntvfs, req, io);
685         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
686                 /* the 2nd try also replied async, so we don't send
687                    the reply yet */
688                 return;
689         }
690
691         /* re-mark it async, just in case someone up the chain does
692            paranoid checking */
693         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
694
695         /* send the reply up the chain */
696         req->async_states->status = status;
697         req->async_states->send_fn(req);
698 }
699
700
701 /*
702   special handling for openx DENY_DOS semantics
703
704   This function attempts a reference open using an existing handle. If its allowed,
705   then it returns NT_STATUS_OK, otherwise it returns any other code and normal
706   open processing continues.
707 */
708 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
709                                    struct smbsrv_request *req, union smb_open *io,
710                                    struct pvfs_file *f, struct odb_lock *lck)
711 {
712         struct pvfs_state *pvfs = ntvfs->private_data;
713         struct pvfs_file *f2;
714         struct pvfs_filename *name;
715
716         /* search for an existing open with the right parameters. Note
717            the magic ntcreatex options flag, which is set in the
718            generic mapping code. This might look ugly, but its
719            actually pretty much now w2k does it internally as well. 
720            
721            If you look at the BASE-DENYDOS test you will see that a
722            DENY_DOS is a very special case, and in the right
723            circumstances you actually get the _same_ handle back
724            twice, rather than a new handle.
725         */
726         for (f2=pvfs->open_files;f2;f2=f2->next) {
727                 if (f2 != f &&
728                     f2->session == req->session &&
729                     f2->smbpid == req->smbpid &&
730                     (f2->handle->create_options & 
731                      (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
732                       NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
733                     (f2->access_mask & SEC_FILE_WRITE_DATA) &&
734                     StrCaseCmp(f2->handle->name->original_name, 
735                                io->generic.in.fname)==0) {
736                         break;
737                 }
738         }
739
740         if (!f2) {
741                 return NT_STATUS_SHARING_VIOLATION;
742         }
743
744         /* quite an insane set of semantics ... */
745         if (is_exe_filename(io->generic.in.fname) &&
746             (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
747                 return NT_STATUS_SHARING_VIOLATION;
748         }
749
750         /*
751           setup a reference to the existing handle
752          */
753         talloc_free(f->handle);
754         f->handle = talloc_reference(f, f2->handle);
755
756         talloc_free(lck);
757
758         name = f->handle->name;
759
760         io->generic.out.oplock_level  = OPLOCK_NONE;
761         io->generic.out.fnum          = f->fnum;
762         io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
763         io->generic.out.create_time   = name->dos.create_time;
764         io->generic.out.access_time   = name->dos.access_time;
765         io->generic.out.write_time    = name->dos.write_time;
766         io->generic.out.change_time   = name->dos.change_time;
767         io->generic.out.attrib        = name->dos.attrib;
768         io->generic.out.alloc_size    = name->dos.alloc_size;
769         io->generic.out.size          = name->st.st_size;
770         io->generic.out.file_type     = FILE_TYPE_DISK;
771         io->generic.out.ipc_state     = 0;
772         io->generic.out.is_directory  = 0;
773
774         talloc_steal(f->pvfs, f);
775
776         return NT_STATUS_OK;
777 }
778
779
780
781 /*
782   setup for a open retry after a sharing violation
783 */
784 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
785                                       struct smbsrv_request *req, 
786                                       union smb_open *io,
787                                       struct pvfs_file *f,
788                                       struct odb_lock *lck)
789 {
790         struct pvfs_state *pvfs = ntvfs->private_data;
791         struct pvfs_open_retry *r;
792         NTSTATUS status;
793         struct timeval end_time;
794
795         if (io->generic.in.create_options & 
796             (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
797                 /* see if we can satisfy the request using the special DENY_DOS
798                    code */
799                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
800                 if (NT_STATUS_IS_OK(status)) {
801                         return status;
802                 }
803         }
804
805         r = talloc_p(req, struct pvfs_open_retry);
806         if (r == NULL) {
807                 return NT_STATUS_NO_MEMORY;
808         }
809
810         r->ntvfs = ntvfs;
811         r->req = req;
812         r->io = io;
813         r->odb_locking_key = data_blob_talloc(r, 
814                                               f->handle->odb_locking_key.data, 
815                                               f->handle->odb_locking_key.length);
816
817         end_time = timeval_add(&req->request_time, 0, pvfs->sharing_violation_delay);
818
819         /* setup a pending lock */
820         status = odb_open_file_pending(lck, r);
821         if (!NT_STATUS_IS_OK(status)) {
822                 return status;
823         }
824
825         talloc_free(lck);
826         talloc_free(f);
827
828         talloc_set_destructor(r, pvfs_retry_destructor);
829
830         r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, end_time, 
831                                            pvfs_open_retry, r);
832         if (r->wait_handle == NULL) {
833                 return NT_STATUS_NO_MEMORY;
834         }
835
836         talloc_steal(pvfs, r);
837
838         return NT_STATUS_OK;
839 }
840
841 /*
842   open a file
843 */
844 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
845                    struct smbsrv_request *req, union smb_open *io)
846 {
847         struct pvfs_state *pvfs = ntvfs->private_data;
848         int flags;
849         struct pvfs_filename *name;
850         struct pvfs_file *f;
851         NTSTATUS status;
852         int fnum, fd;
853         struct odb_lock *lck;
854         uint32_t create_options;
855         uint32_t share_access;
856         uint32_t access_mask;
857         BOOL stream_existed;
858
859         /* use the generic mapping code to avoid implementing all the
860            different open calls. */
861         if (io->generic.level != RAW_OPEN_GENERIC &&
862             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
863                 return ntvfs_map_open(req, io, ntvfs);
864         }
865
866         /* resolve the cifs name to a posix name */
867         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
868                                    PVFS_RESOLVE_STREAMS, &name);
869         if (!NT_STATUS_IS_OK(status)) {
870                 return status;
871         }
872
873         /* directory opens are handled separately */
874         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
875             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
876                 return pvfs_open_directory(pvfs, req, name, io);
877         }
878
879         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
880            open doesn't match */
881         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
882
883         create_options = io->generic.in.create_options;
884         share_access   = io->generic.in.share_access;
885         access_mask    = io->generic.in.access_mask;
886
887         /* certain create options are not allowed */
888         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
889             !(access_mask & SEC_STD_DELETE)) {
890                 return NT_STATUS_INVALID_PARAMETER;
891         }
892
893         switch (io->generic.in.open_disposition) {
894         case NTCREATEX_DISP_SUPERSEDE:
895                 flags = O_TRUNC;
896                 break;
897
898         case NTCREATEX_DISP_OVERWRITE_IF:
899                 flags = O_TRUNC;
900                 break;
901
902         case NTCREATEX_DISP_OPEN:
903                 if (!name->stream_exists) {
904                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
905                 }
906                 flags = 0;
907                 break;
908
909         case NTCREATEX_DISP_OVERWRITE:
910                 if (!name->stream_exists) {
911                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
912                 }
913                 flags = O_TRUNC;
914                 break;
915
916         case NTCREATEX_DISP_CREATE:
917                 if (name->stream_exists) {
918                         return NT_STATUS_OBJECT_NAME_COLLISION;
919                 }
920                 flags = 0;
921                 break;
922
923         case NTCREATEX_DISP_OPEN_IF:
924                 flags = 0;
925                 break;
926
927         default:
928                 return NT_STATUS_INVALID_PARAMETER;
929         }
930
931         /* handle creating a new file separately */
932         if (!name->exists) {
933                 status = pvfs_create_file(pvfs, req, name, io);
934                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
935                         return status;
936                 }
937
938                 /* we've hit a race - the file was created during this call */
939                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
940                         return status;
941                 }
942
943                 /* try re-resolving the name */
944                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
945                 if (!NT_STATUS_IS_OK(status)) {
946                         return status;
947                 }
948                 /* fall through to a normal open */
949         }
950
951         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
952             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
953                 return NT_STATUS_CANNOT_DELETE;
954         }
955
956         /* check the security descriptor */
957         status = pvfs_access_check(pvfs, req, name, &access_mask);
958         if (!NT_STATUS_IS_OK(status)) {
959                 return status;
960         }
961
962         f = talloc_p(req, struct pvfs_file);
963         if (f == NULL) {
964                 return NT_STATUS_NO_MEMORY;
965         }
966
967         f->handle = talloc_p(f, struct pvfs_file_handle);
968         if (f->handle == NULL) {
969                 return NT_STATUS_NO_MEMORY;
970         }
971
972         /* allocate a fnum */
973         fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_FILE_FNUM, UINT16_MAX);
974         if (fnum == -1) {
975                 return NT_STATUS_TOO_MANY_OPENED_FILES;
976         }
977
978         f->fnum          = fnum;
979         f->session       = req->session;
980         f->smbpid        = req->smbpid;
981         f->pvfs          = pvfs;
982         f->pending_list  = NULL;
983         f->lock_count    = 0;
984         f->share_access  = io->generic.in.share_access;
985         f->access_mask   = access_mask;
986         f->impersonation = io->generic.in.impersonation;
987
988         f->handle->pvfs              = pvfs;
989         f->handle->fd                = -1;
990         f->handle->name              = talloc_steal(f->handle, name);
991         f->handle->create_options    = io->generic.in.create_options;
992         f->handle->seek_offset       = 0;
993         f->handle->position          = 0;
994         f->handle->mode              = 0;
995         f->handle->have_opendb_entry = False;
996         f->handle->sticky_write_time = False;
997
998         /* form the lock context used for byte range locking and
999            opendb locking */
1000         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1001         if (!NT_STATUS_IS_OK(status)) {
1002                 idr_remove(pvfs->idtree_fnum, f->fnum);
1003                 return status;
1004         }
1005
1006         status = pvfs_brl_locking_key(name, f->handle, &f->handle->brl_locking_key);
1007         if (!NT_STATUS_IS_OK(status)) {
1008                 idr_remove(pvfs->idtree_fnum, f->fnum);
1009                 return status;
1010         }
1011
1012         /* get a lock on this file before the actual open */
1013         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1014         if (lck == NULL) {
1015                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1016                          name->full_name));
1017                 /* we were supposed to do a blocking lock, so something
1018                    is badly wrong! */
1019                 idr_remove(pvfs->idtree_fnum, fnum);
1020                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1021         }
1022
1023         DLIST_ADD(pvfs->open_files, f);
1024
1025         /* setup a destructor to avoid file descriptor leaks on
1026            abnormal termination */
1027         talloc_set_destructor(f, pvfs_fnum_destructor);
1028         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1029
1030
1031         /* see if we are allowed to open at the same time as existing opens */
1032         status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
1033                                share_access, create_options, access_mask);
1034
1035         /* on a sharing violation we need to retry when the file is closed by 
1036            the other user, or after 1 second */
1037         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1038             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1039                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1040         }
1041
1042         if (!NT_STATUS_IS_OK(status)) {
1043                 talloc_free(lck);
1044                 return status;
1045         }
1046
1047         f->handle->have_opendb_entry = True;
1048
1049         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1050                 flags |= O_RDWR;
1051         } else {
1052                 flags |= O_RDONLY;
1053         }
1054
1055         /* do the actual open */
1056         fd = open(f->handle->name->full_name, flags);
1057         if (fd == -1) {
1058                 talloc_free(lck);
1059                 return pvfs_map_errno(f->pvfs, errno);
1060         }
1061
1062         f->handle->fd = fd;
1063
1064         stream_existed = name->stream_exists;
1065
1066         /* if this was a stream create then create the stream as well */
1067         if (!name->stream_exists) {
1068                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1069                 if (!NT_STATUS_IS_OK(status)) {
1070                         talloc_free(lck);
1071                         return status;
1072                 }
1073         }
1074
1075         /* re-resolve the open fd */
1076         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1077         if (!NT_STATUS_IS_OK(status)) {
1078                 talloc_free(lck);
1079                 return status;
1080         }
1081
1082         if (f->handle->name->stream_id == 0 &&
1083             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1084              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1085                 /* for overwrite we need to replace file permissions */
1086                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1087                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1088                 if (fchmod(fd, mode) == -1) {
1089                         talloc_free(lck);
1090                         return pvfs_map_errno(pvfs, errno);
1091                 }
1092                 name->dos.attrib = attrib;
1093                 status = pvfs_dosattrib_save(pvfs, name, fd);
1094                 if (!NT_STATUS_IS_OK(status)) {
1095                         talloc_free(lck);
1096                         return status;
1097                 }
1098         }
1099             
1100         talloc_free(lck);
1101
1102         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1103                 io->generic.out.oplock_level  = OPLOCK_EXCLUSIVE;
1104         } else {
1105                 io->generic.out.oplock_level  = OPLOCK_NONE;
1106         }
1107         io->generic.out.fnum          = f->fnum;
1108         io->generic.out.create_action = stream_existed?
1109                 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1110         io->generic.out.create_time   = name->dos.create_time;
1111         io->generic.out.access_time   = name->dos.access_time;
1112         io->generic.out.write_time    = name->dos.write_time;
1113         io->generic.out.change_time   = name->dos.change_time;
1114         io->generic.out.attrib        = name->dos.attrib;
1115         io->generic.out.alloc_size    = name->dos.alloc_size;
1116         io->generic.out.size          = name->st.st_size;
1117         io->generic.out.file_type     = FILE_TYPE_DISK;
1118         io->generic.out.ipc_state     = 0;
1119         io->generic.out.is_directory  = 0;
1120
1121         /* success - keep the file handle */
1122         talloc_steal(f->pvfs, f);
1123
1124         return NT_STATUS_OK;
1125 }
1126
1127
1128 /*
1129   close a file
1130 */
1131 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1132                     struct smbsrv_request *req, union smb_close *io)
1133 {
1134         struct pvfs_state *pvfs = ntvfs->private_data;
1135         struct pvfs_file *f;
1136         struct utimbuf unix_times;
1137
1138         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1139                 return NT_STATUS_UNSUCCESSFUL;
1140         }
1141
1142         if (io->generic.level != RAW_CLOSE_CLOSE) {
1143                 return ntvfs_map_close(req, io, ntvfs);
1144         }
1145
1146         f = pvfs_find_fd(pvfs, req, io->close.in.fnum);
1147         if (!f) {
1148                 return NT_STATUS_INVALID_HANDLE;
1149         }
1150
1151         if (!null_time(io->close.in.write_time)) {
1152                 unix_times.actime = 0;
1153                 unix_times.modtime = io->close.in.write_time;
1154                 utime(f->handle->name->full_name, &unix_times);
1155         } else if (f->handle->sticky_write_time) {
1156                 unix_times.actime = 0;
1157                 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1158                 utime(f->handle->name->full_name, &unix_times);
1159         }
1160
1161         talloc_free(f);
1162
1163         return NT_STATUS_OK;
1164 }
1165
1166
1167 /*
1168   logoff - close all file descriptors open by a vuid
1169 */
1170 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1171                      struct smbsrv_request *req)
1172 {
1173         struct pvfs_state *pvfs = ntvfs->private_data;
1174         struct pvfs_file *f, *next;
1175
1176         for (f=pvfs->open_files;f;f=next) {
1177                 next = f->next;
1178                 if (f->session == req->session) {
1179                         talloc_free(f);
1180                 }
1181         }
1182
1183         return NT_STATUS_OK;
1184 }
1185
1186
1187 /*
1188   exit - close files for the current pid
1189 */
1190 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1191                    struct smbsrv_request *req)
1192 {
1193         struct pvfs_state *pvfs = ntvfs->private_data;
1194         struct pvfs_file *f, *next;
1195
1196         for (f=pvfs->open_files;f;f=next) {
1197                 next = f->next;
1198                 if (f->smbpid == req->smbpid) {
1199                         talloc_free(f);
1200                 }
1201         }
1202
1203         return NT_STATUS_OK;
1204 }
1205
1206
1207 /*
1208   change the create options on an already open file
1209 */
1210 NTSTATUS pvfs_change_create_options(struct pvfs_state *pvfs,
1211                                     struct smbsrv_request *req, 
1212                                     struct pvfs_file *f, uint32_t create_options)
1213 {
1214         struct odb_lock *lck;
1215         NTSTATUS status;
1216
1217         if (f->handle->create_options == create_options) {
1218                 return NT_STATUS_OK;
1219         }
1220
1221         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1222             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1223                 return NT_STATUS_CANNOT_DELETE;
1224         }
1225
1226         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1227         if (lck == NULL) {
1228                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1229         }
1230
1231         status = odb_set_create_options(lck, f->handle, create_options);
1232         if (NT_STATUS_IS_OK(status)) {
1233                 f->handle->create_options = create_options;
1234         }
1235
1236         return status;
1237 }
1238
1239
1240 /*
1241   determine if a file can be deleted, or if it is prevented by an
1242   already open file
1243 */
1244 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1245                          struct smbsrv_request *req,
1246                          struct pvfs_filename *name)
1247 {
1248         NTSTATUS status;
1249         DATA_BLOB key;
1250
1251         status = pvfs_locking_key(name, name, &key);
1252         if (!NT_STATUS_IS_OK(status)) {
1253                 return NT_STATUS_NO_MEMORY;
1254         }
1255
1256         status = odb_can_open(pvfs->odb_context, &key, 
1257                               NTCREATEX_SHARE_ACCESS_READ |
1258                               NTCREATEX_SHARE_ACCESS_WRITE | 
1259                               NTCREATEX_SHARE_ACCESS_DELETE, 
1260                               NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 
1261                               SEC_STD_DELETE);
1262
1263         if (NT_STATUS_IS_OK(status)) {
1264                 status = pvfs_access_check_simple(pvfs, req, name, SEC_STD_DELETE);
1265         }
1266
1267         return status;
1268 }
1269
1270 /*
1271   determine if a file can be renamed, or if it is prevented by an
1272   already open file
1273 */
1274 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, struct pvfs_filename *name)
1275 {
1276         NTSTATUS status;
1277         DATA_BLOB key;
1278
1279         status = pvfs_locking_key(name, name, &key);
1280         if (!NT_STATUS_IS_OK(status)) {
1281                 return NT_STATUS_NO_MEMORY;
1282         }
1283
1284         status = odb_can_open(pvfs->odb_context, &key, 
1285                               NTCREATEX_SHARE_ACCESS_READ |
1286                               NTCREATEX_SHARE_ACCESS_WRITE,
1287                               0,
1288                               SEC_STD_DELETE);
1289
1290         return status;
1291 }