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