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