r5298: - got rid of pstring.h from includes.h. This at least makes it a bit
[kai/samba.git] / source4 / ntvfs / posix / pvfs_open.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - open and close
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "vfs_posix.h"
25 #include "system/time.h"
26 #include "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;
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         switch (io->generic.in.open_disposition) {
896         case NTCREATEX_DISP_SUPERSEDE:
897                 flags = O_TRUNC;
898                 break;
899
900         case NTCREATEX_DISP_OVERWRITE_IF:
901                 flags = O_TRUNC;
902                 break;
903
904         case NTCREATEX_DISP_OPEN:
905                 if (!name->stream_exists) {
906                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
907                 }
908                 flags = 0;
909                 break;
910
911         case NTCREATEX_DISP_OVERWRITE:
912                 if (!name->stream_exists) {
913                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
914                 }
915                 flags = O_TRUNC;
916                 break;
917
918         case NTCREATEX_DISP_CREATE:
919                 if (name->stream_exists) {
920                         return NT_STATUS_OBJECT_NAME_COLLISION;
921                 }
922                 flags = 0;
923                 break;
924
925         case NTCREATEX_DISP_OPEN_IF:
926                 flags = 0;
927                 break;
928
929         default:
930                 return NT_STATUS_INVALID_PARAMETER;
931         }
932
933         /* handle creating a new file separately */
934         if (!name->exists) {
935                 status = pvfs_create_file(pvfs, req, name, io);
936                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
937                         return status;
938                 }
939
940                 /* we've hit a race - the file was created during this call */
941                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
942                         return status;
943                 }
944
945                 /* try re-resolving the name */
946                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
947                 if (!NT_STATUS_IS_OK(status)) {
948                         return status;
949                 }
950                 /* fall through to a normal open */
951         }
952
953         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
954             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
955                 return NT_STATUS_CANNOT_DELETE;
956         }
957
958         /* check the security descriptor */
959         status = pvfs_access_check(pvfs, req, name, &access_mask);
960         if (!NT_STATUS_IS_OK(status)) {
961                 return status;
962         }
963
964         f = talloc(req, struct pvfs_file);
965         if (f == NULL) {
966                 return NT_STATUS_NO_MEMORY;
967         }
968
969         f->handle = talloc(f, struct pvfs_file_handle);
970         if (f->handle == NULL) {
971                 return NT_STATUS_NO_MEMORY;
972         }
973
974         /* allocate a fnum */
975         fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_FILE_FNUM, UINT16_MAX);
976         if (fnum == -1) {
977                 return NT_STATUS_TOO_MANY_OPENED_FILES;
978         }
979
980         f->fnum          = fnum;
981         f->session       = req->session;
982         f->smbpid        = req->smbpid;
983         f->pvfs          = pvfs;
984         f->pending_list  = NULL;
985         f->lock_count    = 0;
986         f->share_access  = io->generic.in.share_access;
987         f->access_mask   = access_mask;
988         f->impersonation = io->generic.in.impersonation;
989
990         f->handle->pvfs              = pvfs;
991         f->handle->fd                = -1;
992         f->handle->name              = talloc_steal(f->handle, name);
993         f->handle->create_options    = io->generic.in.create_options;
994         f->handle->seek_offset       = 0;
995         f->handle->position          = 0;
996         f->handle->mode              = 0;
997         f->handle->have_opendb_entry = False;
998         f->handle->sticky_write_time = False;
999
1000         /* form the lock context used for byte range locking and
1001            opendb locking */
1002         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1003         if (!NT_STATUS_IS_OK(status)) {
1004                 idr_remove(pvfs->idtree_fnum, f->fnum);
1005                 return status;
1006         }
1007
1008         status = pvfs_brl_locking_key(name, f->handle, &f->handle->brl_locking_key);
1009         if (!NT_STATUS_IS_OK(status)) {
1010                 idr_remove(pvfs->idtree_fnum, f->fnum);
1011                 return status;
1012         }
1013
1014         /* get a lock on this file before the actual open */
1015         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1016         if (lck == NULL) {
1017                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1018                          name->full_name));
1019                 /* we were supposed to do a blocking lock, so something
1020                    is badly wrong! */
1021                 idr_remove(pvfs->idtree_fnum, fnum);
1022                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1023         }
1024
1025         DLIST_ADD(pvfs->open_files, f);
1026
1027         /* setup a destructor to avoid file descriptor leaks on
1028            abnormal termination */
1029         talloc_set_destructor(f, pvfs_fnum_destructor);
1030         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1031
1032
1033         /* see if we are allowed to open at the same time as existing opens */
1034         status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
1035                                share_access, create_options, access_mask);
1036
1037         /* on a sharing violation we need to retry when the file is closed by 
1038            the other user, or after 1 second */
1039         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1040             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1041                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1042         }
1043
1044         if (!NT_STATUS_IS_OK(status)) {
1045                 talloc_free(lck);
1046                 return status;
1047         }
1048
1049         f->handle->have_opendb_entry = True;
1050
1051         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1052                 flags |= O_RDWR;
1053         } else {
1054                 flags |= O_RDONLY;
1055         }
1056
1057         /* do the actual open */
1058         fd = open(f->handle->name->full_name, flags);
1059         if (fd == -1) {
1060                 talloc_free(lck);
1061                 return pvfs_map_errno(f->pvfs, errno);
1062         }
1063
1064         f->handle->fd = fd;
1065
1066         stream_existed = name->stream_exists;
1067
1068         /* if this was a stream create then create the stream as well */
1069         if (!name->stream_exists) {
1070                 if (!(access_mask & SEC_FILE_WRITE_ATTRIBUTE)) {
1071                         return NT_STATUS_ACCESS_DENIED;
1072                 }
1073                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1074                 if (!NT_STATUS_IS_OK(status)) {
1075                         talloc_free(lck);
1076                         return status;
1077                 }
1078         }
1079
1080         /* re-resolve the open fd */
1081         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1082         if (!NT_STATUS_IS_OK(status)) {
1083                 talloc_free(lck);
1084                 return status;
1085         }
1086
1087         if (f->handle->name->stream_id == 0 &&
1088             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1089              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1090                 /* for overwrite we need to replace file permissions */
1091                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1092                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1093                 if (fchmod(fd, mode) == -1) {
1094                         talloc_free(lck);
1095                         return pvfs_map_errno(pvfs, errno);
1096                 }
1097                 name->dos.attrib = attrib;
1098                 status = pvfs_dosattrib_save(pvfs, name, fd);
1099                 if (!NT_STATUS_IS_OK(status)) {
1100                         talloc_free(lck);
1101                         return status;
1102                 }
1103         }
1104             
1105         talloc_free(lck);
1106
1107         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1108                 io->generic.out.oplock_level  = OPLOCK_EXCLUSIVE;
1109         } else {
1110                 io->generic.out.oplock_level  = OPLOCK_NONE;
1111         }
1112         io->generic.out.fnum          = f->fnum;
1113         io->generic.out.create_action = stream_existed?
1114                 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1115         io->generic.out.create_time   = name->dos.create_time;
1116         io->generic.out.access_time   = name->dos.access_time;
1117         io->generic.out.write_time    = name->dos.write_time;
1118         io->generic.out.change_time   = name->dos.change_time;
1119         io->generic.out.attrib        = name->dos.attrib;
1120         io->generic.out.alloc_size    = name->dos.alloc_size;
1121         io->generic.out.size          = name->st.st_size;
1122         io->generic.out.file_type     = FILE_TYPE_DISK;
1123         io->generic.out.ipc_state     = 0;
1124         io->generic.out.is_directory  = 0;
1125
1126         /* success - keep the file handle */
1127         talloc_steal(f->pvfs, f);
1128
1129         return NT_STATUS_OK;
1130 }
1131
1132
1133 /*
1134   close a file
1135 */
1136 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1137                     struct smbsrv_request *req, union smb_close *io)
1138 {
1139         struct pvfs_state *pvfs = ntvfs->private_data;
1140         struct pvfs_file *f;
1141         struct utimbuf unix_times;
1142
1143         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1144                 return NT_STATUS_UNSUCCESSFUL;
1145         }
1146
1147         if (io->generic.level != RAW_CLOSE_CLOSE) {
1148                 return ntvfs_map_close(req, io, ntvfs);
1149         }
1150
1151         f = pvfs_find_fd(pvfs, req, io->close.in.fnum);
1152         if (!f) {
1153                 return NT_STATUS_INVALID_HANDLE;
1154         }
1155
1156         if (!null_time(io->close.in.write_time)) {
1157                 unix_times.actime = 0;
1158                 unix_times.modtime = io->close.in.write_time;
1159                 utime(f->handle->name->full_name, &unix_times);
1160         } else if (f->handle->sticky_write_time) {
1161                 unix_times.actime = 0;
1162                 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1163                 utime(f->handle->name->full_name, &unix_times);
1164         }
1165
1166         talloc_free(f);
1167
1168         return NT_STATUS_OK;
1169 }
1170
1171
1172 /*
1173   logoff - close all file descriptors open by a vuid
1174 */
1175 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1176                      struct smbsrv_request *req)
1177 {
1178         struct pvfs_state *pvfs = ntvfs->private_data;
1179         struct pvfs_file *f, *next;
1180
1181         for (f=pvfs->open_files;f;f=next) {
1182                 next = f->next;
1183                 if (f->session == req->session) {
1184                         talloc_free(f);
1185                 }
1186         }
1187
1188         return NT_STATUS_OK;
1189 }
1190
1191
1192 /*
1193   exit - close files for the current pid
1194 */
1195 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1196                    struct smbsrv_request *req)
1197 {
1198         struct pvfs_state *pvfs = ntvfs->private_data;
1199         struct pvfs_file *f, *next;
1200
1201         for (f=pvfs->open_files;f;f=next) {
1202                 next = f->next;
1203                 if (f->smbpid == req->smbpid) {
1204                         talloc_free(f);
1205                 }
1206         }
1207
1208         return NT_STATUS_OK;
1209 }
1210
1211
1212 /*
1213   change the create options on an already open file
1214 */
1215 NTSTATUS pvfs_change_create_options(struct pvfs_state *pvfs,
1216                                     struct smbsrv_request *req, 
1217                                     struct pvfs_file *f, uint32_t create_options)
1218 {
1219         struct odb_lock *lck;
1220         NTSTATUS status;
1221
1222         if (f->handle->create_options == create_options) {
1223                 return NT_STATUS_OK;
1224         }
1225
1226         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1227             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1228                 return NT_STATUS_CANNOT_DELETE;
1229         }
1230
1231         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1232         if (lck == NULL) {
1233                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1234         }
1235
1236         status = odb_set_create_options(lck, f->handle, create_options);
1237         if (NT_STATUS_IS_OK(status)) {
1238                 f->handle->create_options = create_options;
1239         }
1240
1241         return status;
1242 }
1243
1244
1245 /*
1246   determine if a file can be deleted, or if it is prevented by an
1247   already open file
1248 */
1249 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
1250                          struct smbsrv_request *req,
1251                          struct pvfs_filename *name)
1252 {
1253         NTSTATUS status;
1254         DATA_BLOB key;
1255
1256         status = pvfs_locking_key(name, name, &key);
1257         if (!NT_STATUS_IS_OK(status)) {
1258                 return NT_STATUS_NO_MEMORY;
1259         }
1260
1261         status = odb_can_open(pvfs->odb_context, &key, 
1262                               NTCREATEX_SHARE_ACCESS_READ |
1263                               NTCREATEX_SHARE_ACCESS_WRITE | 
1264                               NTCREATEX_SHARE_ACCESS_DELETE, 
1265                               NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 
1266                               SEC_STD_DELETE);
1267
1268         if (NT_STATUS_IS_OK(status)) {
1269                 status = pvfs_access_check_simple(pvfs, req, name, SEC_STD_DELETE);
1270         }
1271
1272         return status;
1273 }
1274
1275 /*
1276   determine if a file can be renamed, or if it is prevented by an
1277   already open file
1278 */
1279 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, struct pvfs_filename *name)
1280 {
1281         NTSTATUS status;
1282         DATA_BLOB key;
1283
1284         status = pvfs_locking_key(name, name, &key);
1285         if (!NT_STATUS_IS_OK(status)) {
1286                 return NT_STATUS_NO_MEMORY;
1287         }
1288
1289         status = odb_can_open(pvfs->odb_context, &key, 
1290                               NTCREATEX_SHARE_ACCESS_READ |
1291                               NTCREATEX_SHARE_ACCESS_WRITE,
1292                               0,
1293                               SEC_STD_DELETE);
1294
1295         return status;
1296 }