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