source: branches/samba-3.5.x/source4/ntvfs/posix/pvfs_open.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

File size: 54.7 KB
Line 
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 3 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, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "vfs_posix.h"
24#include "system/dir.h"
25#include "system/time.h"
26#include "../lib/util/dlinklist.h"
27#include "messaging/messaging.h"
28#include "librpc/gen_ndr/xattr.h"
29
30/*
31 find open file handle given fnum
32*/
33struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
34 struct ntvfs_request *req, struct ntvfs_handle *h)
35{
36 void *p;
37 struct pvfs_file *f;
38
39 p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
40 if (!p) return NULL;
41
42 f = talloc_get_type(p, struct pvfs_file);
43 if (!f) return NULL;
44
45 return f;
46}
47
48/*
49 cleanup a open directory handle
50*/
51static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
52{
53 if (h->have_opendb_entry) {
54 struct odb_lock *lck;
55 NTSTATUS status;
56 const char *delete_path = NULL;
57
58 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
59 if (lck == NULL) {
60 DEBUG(0,("Unable to lock opendb for close\n"));
61 return 0;
62 }
63
64 status = odb_close_file(lck, h, &delete_path);
65 if (!NT_STATUS_IS_OK(status)) {
66 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
67 h->name->full_name, nt_errstr(status)));
68 }
69
70 if (h->name->stream_name == NULL && delete_path) {
71 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
72 if (!NT_STATUS_IS_OK(status)) {
73 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
74 delete_path, nt_errstr(status)));
75 }
76 if (rmdir(delete_path) != 0) {
77 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 delete_path, strerror(errno)));
79 }
80 }
81
82 talloc_free(lck);
83 }
84
85 return 0;
86}
87
88/*
89 cleanup a open directory fnum
90*/
91static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
92{
93 DLIST_REMOVE(f->pvfs->files.list, f);
94 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
95
96 return 0;
97}
98
99/*
100 setup any EAs and the ACL on newly created files/directories
101*/
102static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
103 struct ntvfs_request *req,
104 struct pvfs_filename *name,
105 int fd, struct pvfs_file *f,
106 union smb_open *io)
107{
108 NTSTATUS status;
109 struct security_descriptor *sd;
110
111 /* setup any EAs that were asked for */
112 if (io->ntcreatex.in.ea_list) {
113 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
114 io->ntcreatex.in.ea_list->num_eas,
115 io->ntcreatex.in.ea_list->eas);
116 if (!NT_STATUS_IS_OK(status)) {
117 return status;
118 }
119 }
120
121 sd = io->ntcreatex.in.sec_desc;
122 /* setup an initial sec_desc if requested */
123 if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
124 union smb_setfileinfo set;
125/*
126 * TODO: set the full ACL!
127 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
128 * when a SACL is present on the sd,
129 * but the user doesn't have SeSecurityPrivilege
130 * - w2k3 allows it
131 */
132 set.set_secdesc.in.file.ntvfs = f->ntvfs;
133 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
134 set.set_secdesc.in.sd = sd;
135
136 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
137 } else {
138 /* otherwise setup an inherited acl from the parent */
139 status = pvfs_acl_inherit(pvfs, req, name, fd);
140 }
141
142 return status;
143}
144
145/*
146 form the lock context used for opendb locking. Note that we must
147 zero here to take account of possible padding on some architectures
148*/
149NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
150 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
151{
152 struct {
153 dev_t device;
154 ino_t inode;
155 } lock_context;
156 ZERO_STRUCT(lock_context);
157
158 lock_context.device = name->st.st_dev;
159 lock_context.inode = name->st.st_ino;
160
161 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
162 if (key->data == NULL) {
163 return NT_STATUS_NO_MEMORY;
164 }
165
166 return NT_STATUS_OK;
167}
168
169
170/*
171 open a directory
172*/
173static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
174 struct ntvfs_request *req,
175 struct pvfs_filename *name,
176 union smb_open *io)
177{
178 struct pvfs_file *f;
179 struct ntvfs_handle *h;
180 NTSTATUS status;
181 uint32_t create_action;
182 uint32_t access_mask = io->generic.in.access_mask;
183 struct odb_lock *lck;
184 bool del_on_close;
185 uint32_t create_options;
186 uint32_t share_access;
187 bool forced;
188
189 create_options = io->generic.in.create_options;
190 share_access = io->generic.in.share_access;
191
192 forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
193
194 if (name->stream_name) {
195 if (forced) {
196 return NT_STATUS_NOT_A_DIRECTORY;
197 } else {
198 return NT_STATUS_FILE_IS_A_DIRECTORY;
199 }
200 }
201
202 /* if the client says it must be a directory, and it isn't,
203 then fail */
204 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
205 return NT_STATUS_NOT_A_DIRECTORY;
206 }
207
208 /* found with gentest */
209 if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
210 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
211 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
212 return NT_STATUS_INVALID_PARAMETER;
213 }
214
215 switch (io->generic.in.open_disposition) {
216 case NTCREATEX_DISP_OPEN_IF:
217 break;
218
219 case NTCREATEX_DISP_OPEN:
220 if (!name->exists) {
221 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
222 }
223 break;
224
225 case NTCREATEX_DISP_CREATE:
226 if (name->exists) {
227 return NT_STATUS_OBJECT_NAME_COLLISION;
228 }
229 break;
230
231 case NTCREATEX_DISP_OVERWRITE_IF:
232 case NTCREATEX_DISP_OVERWRITE:
233 case NTCREATEX_DISP_SUPERSEDE:
234 default:
235 return NT_STATUS_INVALID_PARAMETER;
236 }
237
238 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
239 NT_STATUS_NOT_OK_RETURN(status);
240
241 f = talloc(h, struct pvfs_file);
242 if (f == NULL) {
243 return NT_STATUS_NO_MEMORY;
244 }
245
246 f->handle = talloc(f, struct pvfs_file_handle);
247 if (f->handle == NULL) {
248 return NT_STATUS_NO_MEMORY;
249 }
250
251 if (name->exists) {
252 /* check the security descriptor */
253 status = pvfs_access_check(pvfs, req, name, &access_mask);
254 } else {
255 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
256 }
257 NT_STATUS_NOT_OK_RETURN(status);
258
259 if (io->generic.in.query_maximal_access) {
260 status = pvfs_access_maximal_allowed(pvfs, req, name,
261 &io->generic.out.maximal_access);
262 NT_STATUS_NOT_OK_RETURN(status);
263 }
264
265 f->ntvfs = h;
266 f->pvfs = pvfs;
267 f->pending_list = NULL;
268 f->lock_count = 0;
269 f->share_access = io->generic.in.share_access;
270 f->impersonation = io->generic.in.impersonation;
271 f->access_mask = access_mask;
272 f->brl_handle = NULL;
273 f->notify_buffer = NULL;
274 f->search = NULL;
275
276 f->handle->pvfs = pvfs;
277 f->handle->name = talloc_steal(f->handle, name);
278 f->handle->fd = -1;
279 f->handle->odb_locking_key = data_blob(NULL, 0);
280 f->handle->create_options = io->generic.in.create_options;
281 f->handle->seek_offset = 0;
282 f->handle->position = 0;
283 f->handle->mode = 0;
284 f->handle->oplock = NULL;
285 ZERO_STRUCT(f->handle->write_time);
286 f->handle->open_completed = false;
287
288 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
289 pvfs_directory_empty(pvfs, f->handle->name)) {
290 del_on_close = true;
291 } else {
292 del_on_close = false;
293 }
294
295 if (name->exists) {
296 /* form the lock context used for opendb locking */
297 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
298 if (!NT_STATUS_IS_OK(status)) {
299 return status;
300 }
301
302 /* get a lock on this file before the actual open */
303 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
304 if (lck == NULL) {
305 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
306 name->full_name));
307 /* we were supposed to do a blocking lock, so something
308 is badly wrong! */
309 return NT_STATUS_INTERNAL_DB_CORRUPTION;
310 }
311
312 /* see if we are allowed to open at the same time as existing opens */
313 status = odb_can_open(lck, name->stream_id,
314 share_access, access_mask, del_on_close,
315 io->generic.in.open_disposition, false);
316 if (!NT_STATUS_IS_OK(status)) {
317 talloc_free(lck);
318 return status;
319 }
320
321 /* now really mark the file as open */
322 status = odb_open_file(lck, f->handle, name->full_name,
323 NULL, name->dos.write_time,
324 false, OPLOCK_NONE, NULL);
325
326 if (!NT_STATUS_IS_OK(status)) {
327 talloc_free(lck);
328 return status;
329 }
330
331 f->handle->have_opendb_entry = true;
332 }
333
334 DLIST_ADD(pvfs->files.list, f);
335
336 /* setup destructors to avoid leaks on abnormal termination */
337 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
338 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
339
340 if (!name->exists) {
341 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
342 mode_t mode = pvfs_fileperms(pvfs, attrib);
343
344 if (mkdir(name->full_name, mode) == -1) {
345 return pvfs_map_errno(pvfs,errno);
346 }
347
348 pvfs_xattr_unlink_hook(pvfs, name->full_name);
349
350 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
351 if (!NT_STATUS_IS_OK(status)) {
352 goto cleanup_delete;
353 }
354
355 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
356 if (!NT_STATUS_IS_OK(status)) {
357 goto cleanup_delete;
358 }
359
360 /* form the lock context used for opendb locking */
361 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
362 if (!NT_STATUS_IS_OK(status)) {
363 return status;
364 }
365
366 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
367 if (lck == NULL) {
368 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
369 name->full_name));
370 /* we were supposed to do a blocking lock, so something
371 is badly wrong! */
372 return NT_STATUS_INTERNAL_DB_CORRUPTION;
373 }
374
375 status = odb_can_open(lck, name->stream_id,
376 share_access, access_mask, del_on_close,
377 io->generic.in.open_disposition, false);
378
379 if (!NT_STATUS_IS_OK(status)) {
380 goto cleanup_delete;
381 }
382
383 status = odb_open_file(lck, f->handle, name->full_name,
384 NULL, name->dos.write_time,
385 false, OPLOCK_NONE, NULL);
386
387 if (!NT_STATUS_IS_OK(status)) {
388 goto cleanup_delete;
389 }
390
391 f->handle->have_opendb_entry = true;
392
393 create_action = NTCREATEX_ACTION_CREATED;
394
395 notify_trigger(pvfs->notify_context,
396 NOTIFY_ACTION_ADDED,
397 FILE_NOTIFY_CHANGE_DIR_NAME,
398 name->full_name);
399 } else {
400 create_action = NTCREATEX_ACTION_EXISTED;
401 }
402
403 if (!name->exists) {
404 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
405 }
406
407 /* the open succeeded, keep this handle permanently */
408 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
409 if (!NT_STATUS_IS_OK(status)) {
410 goto cleanup_delete;
411 }
412
413 f->handle->open_completed = true;
414
415 io->generic.out.oplock_level = OPLOCK_NONE;
416 io->generic.out.file.ntvfs = h;
417 io->generic.out.create_action = create_action;
418 io->generic.out.create_time = name->dos.create_time;
419 io->generic.out.access_time = name->dos.access_time;
420 io->generic.out.write_time = name->dos.write_time;
421 io->generic.out.change_time = name->dos.change_time;
422 io->generic.out.attrib = name->dos.attrib;
423 io->generic.out.alloc_size = name->dos.alloc_size;
424 io->generic.out.size = name->st.st_size;
425 io->generic.out.file_type = FILE_TYPE_DISK;
426 io->generic.out.ipc_state = 0;
427 io->generic.out.is_directory = 1;
428
429 return NT_STATUS_OK;
430
431cleanup_delete:
432 rmdir(name->full_name);
433 return status;
434}
435
436/*
437 destroy a struct pvfs_file_handle
438*/
439static int pvfs_handle_destructor(struct pvfs_file_handle *h)
440{
441 talloc_free(h->write_time.update_event);
442 h->write_time.update_event = NULL;
443
444 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
445 h->name->stream_name) {
446 NTSTATUS status;
447 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
448 if (!NT_STATUS_IS_OK(status)) {
449 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
450 h->name->stream_name, h->name->full_name));
451 }
452 }
453
454 if (h->fd != -1) {
455 if (close(h->fd) != 0) {
456 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
457 h->fd, h->name->full_name, strerror(errno)));
458 }
459 h->fd = -1;
460 }
461
462 if (!h->write_time.update_forced &&
463 h->write_time.update_on_close &&
464 h->write_time.close_time == 0) {
465 struct timeval tv;
466 tv = timeval_current();
467 h->write_time.close_time = timeval_to_nttime(&tv);
468 }
469
470 if (h->have_opendb_entry) {
471 struct odb_lock *lck;
472 NTSTATUS status;
473 const char *delete_path = NULL;
474
475 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
476 if (lck == NULL) {
477 DEBUG(0,("Unable to lock opendb for close\n"));
478 return 0;
479 }
480
481 if (h->write_time.update_forced) {
482 status = odb_get_file_infos(h->pvfs->odb_context,
483 &h->odb_locking_key,
484 NULL,
485 &h->write_time.close_time);
486 if (!NT_STATUS_IS_OK(status)) {
487 DEBUG(0,("Unable get write time for '%s' - %s\n",
488 h->name->full_name, nt_errstr(status)));
489 }
490
491 h->write_time.update_forced = false;
492 h->write_time.update_on_close = true;
493 } else if (h->write_time.update_on_close) {
494 status = odb_set_write_time(lck, h->write_time.close_time, true);
495 if (!NT_STATUS_IS_OK(status)) {
496 DEBUG(0,("Unable set write time for '%s' - %s\n",
497 h->name->full_name, nt_errstr(status)));
498 }
499 }
500
501 status = odb_close_file(lck, h, &delete_path);
502 if (!NT_STATUS_IS_OK(status)) {
503 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
504 h->name->full_name, nt_errstr(status)));
505 }
506
507 if (h->name->stream_name == NULL &&
508 h->open_completed && delete_path) {
509 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
512 delete_path, nt_errstr(status)));
513 }
514 if (unlink(delete_path) != 0) {
515 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
516 delete_path, strerror(errno)));
517 } else {
518 notify_trigger(h->pvfs->notify_context,
519 NOTIFY_ACTION_REMOVED,
520 FILE_NOTIFY_CHANGE_FILE_NAME,
521 delete_path);
522 }
523 h->write_time.update_on_close = false;
524 }
525
526 talloc_free(lck);
527 }
528
529 if (h->write_time.update_on_close) {
530 struct timeval tv[2];
531
532 nttime_to_timeval(&tv[0], h->name->dos.access_time);
533 nttime_to_timeval(&tv[1], h->write_time.close_time);
534
535 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
536 if (utimes(h->name->full_name, tv) == -1) {
537 DEBUG(3,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
538 h->name->full_name, strerror(errno)));
539 }
540 }
541 }
542
543 return 0;
544}
545
546
547/*
548 destroy a struct pvfs_file
549*/
550static int pvfs_fnum_destructor(struct pvfs_file *f)
551{
552 DLIST_REMOVE(f->pvfs->files.list, f);
553 pvfs_lock_close(f->pvfs, f);
554 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
555
556 return 0;
557}
558
559
560/*
561 form the lock context used for byte range locking. This is separate
562 from the locking key used for opendb locking as it needs to take
563 account of file streams (each stream is a separate byte range
564 locking space)
565*/
566static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
567 struct pvfs_filename *name,
568 struct ntvfs_handle *ntvfs,
569 struct brl_handle **_h)
570{
571 DATA_BLOB odb_key, key;
572 NTSTATUS status;
573 struct brl_handle *h;
574
575 status = pvfs_locking_key(name, mem_ctx, &odb_key);
576 NT_STATUS_NOT_OK_RETURN(status);
577
578 if (name->stream_name == NULL) {
579 key = odb_key;
580 } else {
581 key = data_blob_talloc(mem_ctx, NULL,
582 odb_key.length + strlen(name->stream_name) + 1);
583 NT_STATUS_HAVE_NO_MEMORY(key.data);
584 memcpy(key.data, odb_key.data, odb_key.length);
585 memcpy(key.data + odb_key.length,
586 name->stream_name, strlen(name->stream_name) + 1);
587 data_blob_free(&odb_key);
588 }
589
590 h = brl_create_handle(mem_ctx, ntvfs, &key);
591 NT_STATUS_HAVE_NO_MEMORY(h);
592
593 *_h = h;
594 return NT_STATUS_OK;
595}
596
597/*
598 create a new file
599*/
600static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
601 struct ntvfs_request *req,
602 struct pvfs_filename *name,
603 union smb_open *io)
604{
605 struct pvfs_file *f;
606 NTSTATUS status;
607 struct ntvfs_handle *h;
608 int flags, fd;
609 struct odb_lock *lck;
610 uint32_t create_options = io->generic.in.create_options;
611 uint32_t share_access = io->generic.in.share_access;
612 uint32_t access_mask = io->generic.in.access_mask;
613 mode_t mode;
614 uint32_t attrib;
615 bool del_on_close;
616 struct pvfs_filename *parent;
617 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
618 bool allow_level_II_oplock = false;
619
620 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
621 return NT_STATUS_INVALID_PARAMETER;
622 }
623
624 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
625 return NT_STATUS_ACCESS_DENIED;
626 }
627
628 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
629 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
630 return NT_STATUS_CANNOT_DELETE;
631 }
632
633 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
634 NT_STATUS_NOT_OK_RETURN(status);
635
636 /* check that the parent isn't opened with delete on close set */
637 status = pvfs_resolve_parent(pvfs, req, name, &parent);
638 if (NT_STATUS_IS_OK(status)) {
639 DATA_BLOB locking_key;
640 status = pvfs_locking_key(parent, req, &locking_key);
641 NT_STATUS_NOT_OK_RETURN(status);
642 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
643 &del_on_close, NULL);
644 NT_STATUS_NOT_OK_RETURN(status);
645 if (del_on_close) {
646 return NT_STATUS_DELETE_PENDING;
647 }
648 }
649
650 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
651 flags = O_RDWR;
652 } else {
653 flags = O_RDONLY;
654 }
655
656 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
657 NT_STATUS_NOT_OK_RETURN(status);
658
659 f = talloc(h, struct pvfs_file);
660 NT_STATUS_HAVE_NO_MEMORY(f);
661
662 f->handle = talloc(f, struct pvfs_file_handle);
663 NT_STATUS_HAVE_NO_MEMORY(f->handle);
664
665 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
666 mode = pvfs_fileperms(pvfs, attrib);
667
668 /* create the file */
669 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
670 if (fd == -1) {
671 return pvfs_map_errno(pvfs, errno);
672 }
673
674 pvfs_xattr_unlink_hook(pvfs, name->full_name);
675
676 /* if this was a stream create then create the stream as well */
677 if (name->stream_name) {
678 status = pvfs_stream_create(pvfs, name, fd);
679 if (!NT_STATUS_IS_OK(status)) {
680 close(fd);
681 return status;
682 }
683 }
684
685 /* re-resolve the open fd */
686 status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
687 if (!NT_STATUS_IS_OK(status)) {
688 close(fd);
689 return status;
690 }
691
692 /* support initial alloc sizes */
693 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
694 name->dos.attrib = attrib;
695 status = pvfs_dosattrib_save(pvfs, name, fd);
696 if (!NT_STATUS_IS_OK(status)) {
697 goto cleanup_delete;
698 }
699
700
701 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
702 if (!NT_STATUS_IS_OK(status)) {
703 goto cleanup_delete;
704 }
705
706 if (io->generic.in.query_maximal_access) {
707 status = pvfs_access_maximal_allowed(pvfs, req, name,
708 &io->generic.out.maximal_access);
709 NT_STATUS_NOT_OK_RETURN(status);
710 }
711
712 /* form the lock context used for byte range locking and
713 opendb locking */
714 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
715 if (!NT_STATUS_IS_OK(status)) {
716 goto cleanup_delete;
717 }
718
719 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
720 if (!NT_STATUS_IS_OK(status)) {
721 goto cleanup_delete;
722 }
723
724 /* grab a lock on the open file record */
725 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
726 if (lck == NULL) {
727 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
728 name->full_name));
729 /* we were supposed to do a blocking lock, so something
730 is badly wrong! */
731 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
732 goto cleanup_delete;
733 }
734
735 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
736 del_on_close = true;
737 } else {
738 del_on_close = false;
739 }
740
741 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
742 oplock_level = OPLOCK_NONE;
743 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
744 oplock_level = OPLOCK_BATCH;
745 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
746 oplock_level = OPLOCK_EXCLUSIVE;
747 }
748
749 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
750 allow_level_II_oplock = true;
751 }
752
753 status = odb_can_open(lck, name->stream_id,
754 share_access, access_mask, del_on_close,
755 io->generic.in.open_disposition, false);
756 if (!NT_STATUS_IS_OK(status)) {
757 talloc_free(lck);
758 /* bad news, we must have hit a race - we don't delete the file
759 here as the most likely scenario is that someone else created
760 the file at the same time */
761 close(fd);
762 return status;
763 }
764
765 f->ntvfs = h;
766 f->pvfs = pvfs;
767 f->pending_list = NULL;
768 f->lock_count = 0;
769 f->share_access = io->generic.in.share_access;
770 f->access_mask = access_mask;
771 f->impersonation = io->generic.in.impersonation;
772 f->notify_buffer = NULL;
773 f->search = NULL;
774
775 f->handle->pvfs = pvfs;
776 f->handle->name = talloc_steal(f->handle, name);
777 f->handle->fd = fd;
778 f->handle->create_options = io->generic.in.create_options;
779 f->handle->seek_offset = 0;
780 f->handle->position = 0;
781 f->handle->mode = 0;
782 f->handle->oplock = NULL;
783 f->handle->have_opendb_entry = true;
784 ZERO_STRUCT(f->handle->write_time);
785 f->handle->open_completed = false;
786
787 status = odb_open_file(lck, f->handle, name->full_name,
788 &f->handle->fd, name->dos.write_time,
789 allow_level_II_oplock,
790 oplock_level, &oplock_granted);
791 talloc_free(lck);
792 if (!NT_STATUS_IS_OK(status)) {
793 /* bad news, we must have hit a race - we don't delete the file
794 here as the most likely scenario is that someone else created
795 the file at the same time */
796 close(fd);
797 return status;
798 }
799
800 DLIST_ADD(pvfs->files.list, f);
801
802 /* setup a destructor to avoid file descriptor leaks on
803 abnormal termination */
804 talloc_set_destructor(f, pvfs_fnum_destructor);
805 talloc_set_destructor(f->handle, pvfs_handle_destructor);
806
807 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
808 oplock_granted = OPLOCK_BATCH;
809 } else if (oplock_granted != OPLOCK_NONE) {
810 status = pvfs_setup_oplock(f, oplock_granted);
811 if (!NT_STATUS_IS_OK(status)) {
812 return status;
813 }
814 }
815
816 io->generic.out.oplock_level = oplock_granted;
817 io->generic.out.file.ntvfs = f->ntvfs;
818 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
819 io->generic.out.create_time = name->dos.create_time;
820 io->generic.out.access_time = name->dos.access_time;
821 io->generic.out.write_time = name->dos.write_time;
822 io->generic.out.change_time = name->dos.change_time;
823 io->generic.out.attrib = name->dos.attrib;
824 io->generic.out.alloc_size = name->dos.alloc_size;
825 io->generic.out.size = name->st.st_size;
826 io->generic.out.file_type = FILE_TYPE_DISK;
827 io->generic.out.ipc_state = 0;
828 io->generic.out.is_directory = 0;
829
830 /* success - keep the file handle */
831 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
832 if (!NT_STATUS_IS_OK(status)) {
833 goto cleanup_delete;
834 }
835
836 f->handle->open_completed = true;
837
838 notify_trigger(pvfs->notify_context,
839 NOTIFY_ACTION_ADDED,
840 FILE_NOTIFY_CHANGE_FILE_NAME,
841 name->full_name);
842
843 return NT_STATUS_OK;
844
845cleanup_delete:
846 close(fd);
847 unlink(name->full_name);
848 return status;
849}
850
851/*
852 state of a pending retry
853*/
854struct pvfs_odb_retry {
855 struct ntvfs_module_context *ntvfs;
856 struct ntvfs_request *req;
857 DATA_BLOB odb_locking_key;
858 void *io;
859 void *private_data;
860 void (*callback)(struct pvfs_odb_retry *r,
861 struct ntvfs_module_context *ntvfs,
862 struct ntvfs_request *req,
863 void *io,
864 void *private_data,
865 enum pvfs_wait_notice reason);
866};
867
868/* destroy a pending request */
869static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
870{
871 struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
872 struct pvfs_state);
873 if (r->odb_locking_key.data) {
874 struct odb_lock *lck;
875 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
876 if (lck != NULL) {
877 odb_remove_pending(lck, r);
878 }
879 talloc_free(lck);
880 }
881 return 0;
882}
883
884static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
885{
886 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
887
888 if (reason == PVFS_WAIT_EVENT) {
889 /*
890 * The pending odb entry is already removed.
891 * We use a null locking key to indicate this
892 * to the destructor.
893 */
894 data_blob_free(&r->odb_locking_key);
895 }
896
897 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
898}
899
900/*
901 setup for a retry of a request that was rejected
902 by odb_can_open()
903*/
904NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
905 struct ntvfs_request *req,
906 struct odb_lock *lck,
907 struct timeval end_time,
908 void *io,
909 void *private_data,
910 void (*callback)(struct pvfs_odb_retry *r,
911 struct ntvfs_module_context *ntvfs,
912 struct ntvfs_request *req,
913 void *io,
914 void *private_data,
915 enum pvfs_wait_notice reason))
916{
917 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
918 struct pvfs_state);
919 struct pvfs_odb_retry *r;
920 struct pvfs_wait *wait_handle;
921 NTSTATUS status;
922
923 r = talloc(req, struct pvfs_odb_retry);
924 NT_STATUS_HAVE_NO_MEMORY(r);
925
926 r->ntvfs = ntvfs;
927 r->req = req;
928 r->io = io;
929 r->private_data = private_data;
930 r->callback = callback;
931 r->odb_locking_key = odb_get_key(r, lck);
932 if (r->odb_locking_key.data == NULL) {
933 return NT_STATUS_NO_MEMORY;
934 }
935
936 /* setup a pending lock */
937 status = odb_open_file_pending(lck, r);
938 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
939 /*
940 * maybe only a unix application
941 * has the file open
942 */
943 data_blob_free(&r->odb_locking_key);
944 } else if (!NT_STATUS_IS_OK(status)) {
945 return status;
946 }
947
948 talloc_free(lck);
949
950 talloc_set_destructor(r, pvfs_odb_retry_destructor);
951
952 wait_handle = pvfs_wait_message(pvfs, req,
953 MSG_PVFS_RETRY_OPEN, end_time,
954 pvfs_odb_retry_callback, r);
955 if (wait_handle == NULL) {
956 return NT_STATUS_NO_MEMORY;
957 }
958
959 talloc_steal(r, wait_handle);
960
961 return NT_STATUS_OK;
962}
963
964/*
965 retry an open after a sharing violation
966*/
967static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
968 struct ntvfs_module_context *ntvfs,
969 struct ntvfs_request *req,
970 void *_io,
971 void *private_data,
972 enum pvfs_wait_notice reason)
973{
974 union smb_open *io = talloc_get_type(_io, union smb_open);
975 struct timeval *final_timeout = NULL;
976 NTSTATUS status;
977
978 if (private_data) {
979 final_timeout = talloc_get_type(private_data,
980 struct timeval);
981 }
982
983 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
984 just a bug in their server, but we better do the same */
985 if (reason == PVFS_WAIT_CANCEL) {
986 return;
987 }
988
989 if (reason == PVFS_WAIT_TIMEOUT) {
990 if (final_timeout &&
991 !timeval_expired(final_timeout)) {
992 /*
993 * we need to retry periodictly
994 * after an EAGAIN as there's
995 * no way the kernel tell us
996 * an oplock is released.
997 */
998 goto retry;
999 }
1000 /* if it timed out, then give the failure
1001 immediately */
1002 talloc_free(r);
1003 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1004 req->async_states->send_fn(req);
1005 return;
1006 }
1007
1008retry:
1009 talloc_free(r);
1010
1011 /* try the open again, which could trigger another retry setup
1012 if it wants to, so we have to unmark the async flag so we
1013 will know if it does a second async reply */
1014 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1015
1016 status = pvfs_open(ntvfs, req, io);
1017 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1018 /* the 2nd try also replied async, so we don't send
1019 the reply yet */
1020 return;
1021 }
1022
1023 /* re-mark it async, just in case someone up the chain does
1024 paranoid checking */
1025 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1026
1027 /* send the reply up the chain */
1028 req->async_states->status = status;
1029 req->async_states->send_fn(req);
1030}
1031
1032
1033/*
1034 special handling for openx DENY_DOS semantics
1035
1036 This function attempts a reference open using an existing handle. If its allowed,
1037 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1038 open processing continues.
1039*/
1040static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1041 struct ntvfs_request *req, union smb_open *io,
1042 struct pvfs_file *f, struct odb_lock *lck)
1043{
1044 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1045 struct pvfs_state);
1046 struct pvfs_file *f2;
1047 struct pvfs_filename *name;
1048 NTSTATUS status;
1049
1050 /* search for an existing open with the right parameters. Note
1051 the magic ntcreatex options flag, which is set in the
1052 generic mapping code. This might look ugly, but its
1053 actually pretty much now w2k does it internally as well.
1054
1055 If you look at the BASE-DENYDOS test you will see that a
1056 DENY_DOS is a very special case, and in the right
1057 circumstances you actually get the _same_ handle back
1058 twice, rather than a new handle.
1059 */
1060 for (f2=pvfs->files.list;f2;f2=f2->next) {
1061 if (f2 != f &&
1062 f2->ntvfs->session_info == req->session_info &&
1063 f2->ntvfs->smbpid == req->smbpid &&
1064 (f2->handle->create_options &
1065 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1066 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1067 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1068 strcasecmp_m(f2->handle->name->original_name,
1069 io->generic.in.fname)==0) {
1070 break;
1071 }
1072 }
1073
1074 if (!f2) {
1075 return NT_STATUS_SHARING_VIOLATION;
1076 }
1077
1078 /* quite an insane set of semantics ... */
1079 if (is_exe_filename(io->generic.in.fname) &&
1080 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1081 return NT_STATUS_SHARING_VIOLATION;
1082 }
1083
1084 /*
1085 setup a reference to the existing handle
1086 */
1087 talloc_free(f->handle);
1088 f->handle = talloc_reference(f, f2->handle);
1089
1090 talloc_free(lck);
1091
1092 name = f->handle->name;
1093
1094 io->generic.out.oplock_level = OPLOCK_NONE;
1095 io->generic.out.file.ntvfs = f->ntvfs;
1096 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1097 io->generic.out.create_time = name->dos.create_time;
1098 io->generic.out.access_time = name->dos.access_time;
1099 io->generic.out.write_time = name->dos.write_time;
1100 io->generic.out.change_time = name->dos.change_time;
1101 io->generic.out.attrib = name->dos.attrib;
1102 io->generic.out.alloc_size = name->dos.alloc_size;
1103 io->generic.out.size = name->st.st_size;
1104 io->generic.out.file_type = FILE_TYPE_DISK;
1105 io->generic.out.ipc_state = 0;
1106 io->generic.out.is_directory = 0;
1107
1108 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1109 NT_STATUS_NOT_OK_RETURN(status);
1110
1111 return NT_STATUS_OK;
1112}
1113
1114
1115
1116/*
1117 setup for a open retry after a sharing violation
1118*/
1119static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1120 struct ntvfs_request *req,
1121 union smb_open *io,
1122 struct pvfs_file *f,
1123 struct odb_lock *lck,
1124 NTSTATUS parent_status)
1125{
1126 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1127 struct pvfs_state);
1128 NTSTATUS status;
1129 struct timeval end_time;
1130 struct timeval *final_timeout = NULL;
1131
1132 if (io->generic.in.create_options &
1133 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1134 /* see if we can satisfy the request using the special DENY_DOS
1135 code */
1136 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1137 if (NT_STATUS_IS_OK(status)) {
1138 return status;
1139 }
1140 }
1141
1142 /* the retry should allocate a new file handle */
1143 talloc_free(f);
1144
1145 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1146 end_time = timeval_add(&req->statistics.request_time,
1147 0, pvfs->sharing_violation_delay);
1148 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1149 end_time = timeval_add(&req->statistics.request_time,
1150 pvfs->oplock_break_timeout, 0);
1151 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1152 /*
1153 * we got EAGAIN which means a unix application
1154 * has an oplock or share mode
1155 *
1156 * we retry every 4/5 of the sharing violation delay
1157 * to see if the unix application
1158 * has released the oplock or share mode.
1159 */
1160 final_timeout = talloc(req, struct timeval);
1161 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1162 *final_timeout = timeval_add(&req->statistics.request_time,
1163 pvfs->oplock_break_timeout,
1164 0);
1165 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1166 end_time = timeval_min(final_timeout, &end_time);
1167 } else {
1168 return NT_STATUS_INTERNAL_ERROR;
1169 }
1170
1171 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1172 final_timeout, pvfs_retry_open_sharing);
1173}
1174
1175/*
1176 open a file
1177*/
1178NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1179 struct ntvfs_request *req, union smb_open *io)
1180{
1181 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1182 struct pvfs_state);
1183 int flags = 0;
1184 struct pvfs_filename *name;
1185 struct pvfs_file *f;
1186 struct ntvfs_handle *h;
1187 NTSTATUS status;
1188 int fd;
1189 struct odb_lock *lck;
1190 uint32_t create_options;
1191 uint32_t create_options_must_ignore_mask;
1192 uint32_t share_access;
1193 uint32_t access_mask;
1194 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1195 bool del_on_close;
1196 bool stream_existed, stream_truncate=false;
1197 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1198 bool allow_level_II_oplock = false;
1199
1200 /* use the generic mapping code to avoid implementing all the
1201 different open calls. */
1202 if (io->generic.level != RAW_OPEN_GENERIC &&
1203 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1204 return ntvfs_map_open(ntvfs, req, io);
1205 }
1206
1207 ZERO_STRUCT(io->generic.out);
1208
1209 create_options = io->generic.in.create_options;
1210 share_access = io->generic.in.share_access;
1211 access_mask = io->generic.in.access_mask;
1212
1213 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1214 return NT_STATUS_INVALID_PARAMETER;
1215 }
1216
1217 /*
1218 * These options are ignored,
1219 * but we reuse some of them as private values for the generic mapping
1220 */
1221 create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1222 create_options_must_ignore_mask &= ~NTCREATEX_OPTIONS_PRIVATE_MASK;
1223 create_options &= ~create_options_must_ignore_mask;
1224
1225 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1226 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
1227 create_options));
1228 return NT_STATUS_NOT_SUPPORTED;
1229 }
1230
1231 if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1232 return NT_STATUS_INVALID_PARAMETER;
1233 }
1234
1235 /* TODO: When we implement HSM, add a hook here not to pull
1236 * the actual file off tape, when this option is passed from
1237 * the client */
1238 if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1239 /* no-op */
1240 }
1241
1242 /* TODO: If (unlikely) Linux does a good compressed
1243 * filesystem, we might need an ioctl call for this */
1244 if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1245 /* no-op */
1246 }
1247
1248 if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1249 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1250 }
1251
1252 /* Open the file with sync, if they asked for it, but
1253 'strict sync = no' turns this client request into a no-op */
1254 if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1255 flags |= O_SYNC;
1256 }
1257
1258
1259 /* other create options are not allowed */
1260 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1261 !(access_mask & SEC_STD_DELETE)) {
1262 return NT_STATUS_INVALID_PARAMETER;
1263 }
1264
1265 if (access_mask & SEC_MASK_INVALID) {
1266 return NT_STATUS_ACCESS_DENIED;
1267 }
1268
1269 /* what does this bit really mean?? */
1270 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1271 access_mask == SEC_STD_SYNCHRONIZE) {
1272 return NT_STATUS_ACCESS_DENIED;
1273 }
1274
1275 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1276 FILE_ATTRIBUTE_VOLUME|
1277 (~FILE_ATTRIBUTE_ALL_MASK))) {
1278 return NT_STATUS_INVALID_PARAMETER;
1279 }
1280
1281 /* we ignore some file_attr bits */
1282 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1283 FILE_ATTRIBUTE_COMPRESSED |
1284 FILE_ATTRIBUTE_REPARSE_POINT |
1285 FILE_ATTRIBUTE_SPARSE |
1286 FILE_ATTRIBUTE_NORMAL);
1287
1288 /* resolve the cifs name to a posix name */
1289 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1290 PVFS_RESOLVE_STREAMS, &name);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 return status;
1293 }
1294
1295 /* if the client specified that it must not be a directory then
1296 check that it isn't */
1297 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1298 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1299 return NT_STATUS_FILE_IS_A_DIRECTORY;
1300 }
1301
1302 /* if the client specified that it must be a directory then
1303 check that it is */
1304 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1305 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1306 return NT_STATUS_NOT_A_DIRECTORY;
1307 }
1308
1309 /* directory opens are handled separately */
1310 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1311 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1312 return pvfs_open_directory(pvfs, req, name, io);
1313 }
1314
1315 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1316 open doesn't match */
1317 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1318
1319 switch (io->generic.in.open_disposition) {
1320 case NTCREATEX_DISP_SUPERSEDE:
1321 case NTCREATEX_DISP_OVERWRITE_IF:
1322 if (name->stream_name == NULL) {
1323 flags = O_TRUNC;
1324 } else {
1325 stream_truncate = true;
1326 }
1327 create_action = NTCREATEX_ACTION_TRUNCATED;
1328 break;
1329
1330 case NTCREATEX_DISP_OPEN:
1331 if (!name->stream_exists) {
1332 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1333 }
1334 flags = 0;
1335 break;
1336
1337 case NTCREATEX_DISP_OVERWRITE:
1338 if (!name->stream_exists) {
1339 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1340 }
1341 if (name->stream_name == NULL) {
1342 flags = O_TRUNC;
1343 } else {
1344 stream_truncate = true;
1345 }
1346 create_action = NTCREATEX_ACTION_TRUNCATED;
1347 break;
1348
1349 case NTCREATEX_DISP_CREATE:
1350 if (name->stream_exists) {
1351 return NT_STATUS_OBJECT_NAME_COLLISION;
1352 }
1353 flags = 0;
1354 break;
1355
1356 case NTCREATEX_DISP_OPEN_IF:
1357 flags = 0;
1358 break;
1359
1360 default:
1361 return NT_STATUS_INVALID_PARAMETER;
1362 }
1363
1364 /* handle creating a new file separately */
1365 if (!name->exists) {
1366 status = pvfs_create_file(pvfs, req, name, io);
1367 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1368 return status;
1369 }
1370
1371 /* we've hit a race - the file was created during this call */
1372 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1373 return status;
1374 }
1375
1376 /* try re-resolving the name */
1377 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1378 if (!NT_STATUS_IS_OK(status)) {
1379 return status;
1380 }
1381 /* fall through to a normal open */
1382 }
1383
1384 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1385 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1386 return NT_STATUS_CANNOT_DELETE;
1387 }
1388
1389 /* check the security descriptor */
1390 status = pvfs_access_check(pvfs, req, name, &access_mask);
1391 NT_STATUS_NOT_OK_RETURN(status);
1392
1393 if (io->generic.in.query_maximal_access) {
1394 status = pvfs_access_maximal_allowed(pvfs, req, name,
1395 &io->generic.out.maximal_access);
1396 NT_STATUS_NOT_OK_RETURN(status);
1397 }
1398
1399 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1400 NT_STATUS_NOT_OK_RETURN(status);
1401
1402 f = talloc(h, struct pvfs_file);
1403 if (f == NULL) {
1404 return NT_STATUS_NO_MEMORY;
1405 }
1406
1407 f->handle = talloc(f, struct pvfs_file_handle);
1408 if (f->handle == NULL) {
1409 return NT_STATUS_NO_MEMORY;
1410 }
1411
1412 f->ntvfs = h;
1413 f->pvfs = pvfs;
1414 f->pending_list = NULL;
1415 f->lock_count = 0;
1416 f->share_access = io->generic.in.share_access;
1417 f->access_mask = access_mask;
1418 f->impersonation = io->generic.in.impersonation;
1419 f->notify_buffer = NULL;
1420 f->search = NULL;
1421
1422 f->handle->pvfs = pvfs;
1423 f->handle->fd = -1;
1424 f->handle->name = talloc_steal(f->handle, name);
1425 f->handle->create_options = io->generic.in.create_options;
1426 f->handle->seek_offset = 0;
1427 f->handle->position = 0;
1428 f->handle->mode = 0;
1429 f->handle->oplock = NULL;
1430 f->handle->have_opendb_entry = false;
1431 ZERO_STRUCT(f->handle->write_time);
1432 f->handle->open_completed = false;
1433
1434 /* form the lock context used for byte range locking and
1435 opendb locking */
1436 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1437 if (!NT_STATUS_IS_OK(status)) {
1438 return status;
1439 }
1440
1441 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1442 if (!NT_STATUS_IS_OK(status)) {
1443 return status;
1444 }
1445
1446 /* get a lock on this file before the actual open */
1447 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1448 if (lck == NULL) {
1449 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1450 name->full_name));
1451 /* we were supposed to do a blocking lock, so something
1452 is badly wrong! */
1453 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1454 }
1455
1456 DLIST_ADD(pvfs->files.list, f);
1457
1458 /* setup a destructor to avoid file descriptor leaks on
1459 abnormal termination */
1460 talloc_set_destructor(f, pvfs_fnum_destructor);
1461 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1462
1463 /*
1464 * Only SMB2 takes care of the delete_on_close,
1465 * on existing files
1466 */
1467 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1468 req->ctx->protocol == PROTOCOL_SMB2) {
1469 del_on_close = true;
1470 } else {
1471 del_on_close = false;
1472 }
1473
1474 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1475 oplock_level = OPLOCK_NONE;
1476 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1477 oplock_level = OPLOCK_BATCH;
1478 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1479 oplock_level = OPLOCK_EXCLUSIVE;
1480 }
1481
1482 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1483 allow_level_II_oplock = true;
1484 }
1485
1486 /* see if we are allowed to open at the same time as existing opens */
1487 status = odb_can_open(lck, name->stream_id,
1488 share_access, access_mask, del_on_close,
1489 io->generic.in.open_disposition, false);
1490
1491 /*
1492 * on a sharing violation we need to retry when the file is closed by
1493 * the other user, or after 1 second
1494 * on a non granted oplock we need to retry when the file is closed by
1495 * the other user, or after 30 seconds
1496 */
1497 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1498 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1499 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1500 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1501 }
1502
1503 if (!NT_STATUS_IS_OK(status)) {
1504 talloc_free(lck);
1505 return status;
1506 }
1507
1508 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1509 flags |= O_RDWR;
1510 } else {
1511 flags |= O_RDONLY;
1512 }
1513
1514 /* do the actual open */
1515 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1516 if (fd == -1) {
1517 status = pvfs_map_errno(f->pvfs, errno);
1518
1519 DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n",
1520 nt_errstr(status), f->handle->name->full_name, errno));
1521 /*
1522 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1523 */
1524 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1525 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1526 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1527 }
1528
1529 talloc_free(lck);
1530 return status;
1531 }
1532
1533 f->handle->fd = fd;
1534
1535 /* now really mark the file as open */
1536 status = odb_open_file(lck, f->handle, name->full_name,
1537 &f->handle->fd, name->dos.write_time,
1538 allow_level_II_oplock,
1539 oplock_level, &oplock_granted);
1540
1541 if (!NT_STATUS_IS_OK(status)) {
1542 talloc_free(lck);
1543 return status;
1544 }
1545
1546 f->handle->have_opendb_entry = true;
1547
1548 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1549 oplock_granted = OPLOCK_BATCH;
1550 } else if (oplock_granted != OPLOCK_NONE) {
1551 status = pvfs_setup_oplock(f, oplock_granted);
1552 if (!NT_STATUS_IS_OK(status)) {
1553 talloc_free(lck);
1554 return status;
1555 }
1556 }
1557
1558 stream_existed = name->stream_exists;
1559
1560 /* if this was a stream create then create the stream as well */
1561 if (!name->stream_exists) {
1562 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1563 if (!NT_STATUS_IS_OK(status)) {
1564 talloc_free(lck);
1565 return status;
1566 }
1567 if (stream_truncate) {
1568 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1569 if (!NT_STATUS_IS_OK(status)) {
1570 talloc_free(lck);
1571 return status;
1572 }
1573 }
1574 }
1575
1576 /* re-resolve the open fd */
1577 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1578 if (!NT_STATUS_IS_OK(status)) {
1579 talloc_free(lck);
1580 return status;
1581 }
1582
1583 if (f->handle->name->stream_id == 0 &&
1584 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1585 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1586 /* for overwrite we may need to replace file permissions */
1587 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1588 mode_t mode = pvfs_fileperms(pvfs, attrib);
1589 if (f->handle->name->st.st_mode != mode &&
1590 f->handle->name->dos.attrib != attrib &&
1591 fchmod(fd, mode) == -1) {
1592 talloc_free(lck);
1593 return pvfs_map_errno(pvfs, errno);
1594 }
1595 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1596 name->dos.attrib = attrib;
1597 status = pvfs_dosattrib_save(pvfs, name, fd);
1598 if (!NT_STATUS_IS_OK(status)) {
1599 talloc_free(lck);
1600 return status;
1601 }
1602 }
1603
1604 talloc_free(lck);
1605
1606 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1607 NT_STATUS_NOT_OK_RETURN(status);
1608
1609 /* mark the open as having completed fully, so delete on close
1610 can now be used */
1611 f->handle->open_completed = true;
1612
1613 io->generic.out.oplock_level = oplock_granted;
1614 io->generic.out.file.ntvfs = h;
1615 io->generic.out.create_action = stream_existed?
1616 create_action:NTCREATEX_ACTION_CREATED;
1617
1618 io->generic.out.create_time = name->dos.create_time;
1619 io->generic.out.access_time = name->dos.access_time;
1620 io->generic.out.write_time = name->dos.write_time;
1621 io->generic.out.change_time = name->dos.change_time;
1622 io->generic.out.attrib = name->dos.attrib;
1623 io->generic.out.alloc_size = name->dos.alloc_size;
1624 io->generic.out.size = name->st.st_size;
1625 io->generic.out.file_type = FILE_TYPE_DISK;
1626 io->generic.out.ipc_state = 0;
1627 io->generic.out.is_directory = 0;
1628
1629 return NT_STATUS_OK;
1630}
1631
1632
1633/*
1634 close a file
1635*/
1636NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1637 struct ntvfs_request *req, union smb_close *io)
1638{
1639 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1640 struct pvfs_state);
1641 struct pvfs_file *f;
1642
1643 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1644 return NT_STATUS_DOS(ERRSRV, ERRerror);
1645 }
1646
1647 if (io->generic.level != RAW_CLOSE_GENERIC) {
1648 return ntvfs_map_close(ntvfs, req, io);
1649 }
1650
1651 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1652 if (!f) {
1653 return NT_STATUS_INVALID_HANDLE;
1654 }
1655
1656 if (!null_time(io->generic.in.write_time)) {
1657 f->handle->write_time.update_forced = false;
1658 f->handle->write_time.update_on_close = true;
1659 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1660 }
1661
1662 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1663 struct pvfs_filename *name;
1664 NTSTATUS status;
1665 struct pvfs_file_handle *h = f->handle;
1666
1667 status = pvfs_resolve_name_handle(pvfs, h);
1668 if (!NT_STATUS_IS_OK(status)) {
1669 return status;
1670 }
1671 name = h->name;
1672
1673 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1674 io->generic.out.create_time = name->dos.create_time;
1675 io->generic.out.access_time = name->dos.access_time;
1676 io->generic.out.write_time = name->dos.write_time;
1677 io->generic.out.change_time = name->dos.change_time;
1678 io->generic.out.alloc_size = name->dos.alloc_size;
1679 io->generic.out.size = name->st.st_size;
1680 io->generic.out.file_attr = name->dos.attrib;
1681 } else {
1682 ZERO_STRUCT(io->generic.out);
1683 }
1684
1685 talloc_free(f);
1686
1687 return NT_STATUS_OK;
1688}
1689
1690
1691/*
1692 logoff - close all file descriptors open by a vuid
1693*/
1694NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1695 struct ntvfs_request *req)
1696{
1697 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1698 struct pvfs_state);
1699 struct pvfs_file *f, *next;
1700
1701 for (f=pvfs->files.list;f;f=next) {
1702 next = f->next;
1703 if (f->ntvfs->session_info == req->session_info) {
1704 talloc_free(f);
1705 }
1706 }
1707
1708 return NT_STATUS_OK;
1709}
1710
1711
1712/*
1713 exit - close files for the current pid
1714*/
1715NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1716 struct ntvfs_request *req)
1717{
1718 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1719 struct pvfs_state);
1720 struct pvfs_file *f, *next;
1721
1722 for (f=pvfs->files.list;f;f=next) {
1723 next = f->next;
1724 if (f->ntvfs->session_info == req->session_info &&
1725 f->ntvfs->smbpid == req->smbpid) {
1726 talloc_free(f);
1727 }
1728 }
1729
1730 return NT_STATUS_OK;
1731}
1732
1733
1734/*
1735 change the delete on close flag on an already open file
1736*/
1737NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1738 struct ntvfs_request *req,
1739 struct pvfs_file *f, bool del_on_close)
1740{
1741 struct odb_lock *lck;
1742 NTSTATUS status;
1743
1744 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1745 return NT_STATUS_CANNOT_DELETE;
1746 }
1747
1748 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1749 !pvfs_directory_empty(pvfs, f->handle->name)) {
1750 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1751 }
1752
1753 if (del_on_close) {
1754 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1755 } else {
1756 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1757 }
1758
1759 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1760 if (lck == NULL) {
1761 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1762 }
1763
1764 status = odb_set_delete_on_close(lck, del_on_close);
1765
1766 talloc_free(lck);
1767
1768 return status;
1769}
1770
1771
1772/*
1773 determine if a file can be deleted, or if it is prevented by an
1774 already open file
1775*/
1776NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1777 struct ntvfs_request *req,
1778 struct pvfs_filename *name,
1779 struct odb_lock **lckp)
1780{
1781 NTSTATUS status;
1782 DATA_BLOB key;
1783 struct odb_lock *lck;
1784 uint32_t share_access;
1785 uint32_t access_mask;
1786 bool delete_on_close;
1787
1788 status = pvfs_locking_key(name, name, &key);
1789 if (!NT_STATUS_IS_OK(status)) {
1790 return NT_STATUS_NO_MEMORY;
1791 }
1792
1793 lck = odb_lock(req, pvfs->odb_context, &key);
1794 if (lck == NULL) {
1795 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1796 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1797 }
1798
1799 share_access = NTCREATEX_SHARE_ACCESS_READ |
1800 NTCREATEX_SHARE_ACCESS_WRITE |
1801 NTCREATEX_SHARE_ACCESS_DELETE;
1802 access_mask = SEC_STD_DELETE;
1803 delete_on_close = true;
1804
1805 status = odb_can_open(lck, name->stream_id,
1806 share_access, access_mask, delete_on_close,
1807 NTCREATEX_DISP_OPEN, false);
1808
1809 if (NT_STATUS_IS_OK(status)) {
1810 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1811 }
1812
1813 /*
1814 * if it's a sharing violation or we got no oplock
1815 * only keep the lock if the caller requested access
1816 * to the lock
1817 */
1818 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1819 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1820 if (lckp) {
1821 *lckp = lck;
1822 } else {
1823 talloc_free(lck);
1824 }
1825 } else if (!NT_STATUS_IS_OK(status)) {
1826 talloc_free(lck);
1827 if (lckp) {
1828 *lckp = NULL;
1829 }
1830 } else if (lckp) {
1831 *lckp = lck;
1832 }
1833
1834 return status;
1835}
1836
1837/*
1838 determine if a file can be renamed, or if it is prevented by an
1839 already open file
1840*/
1841NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1842 struct ntvfs_request *req,
1843 struct pvfs_filename *name,
1844 struct odb_lock **lckp)
1845{
1846 NTSTATUS status;
1847 DATA_BLOB key;
1848 struct odb_lock *lck;
1849 uint32_t share_access;
1850 uint32_t access_mask;
1851 bool delete_on_close;
1852
1853 status = pvfs_locking_key(name, name, &key);
1854 if (!NT_STATUS_IS_OK(status)) {
1855 return NT_STATUS_NO_MEMORY;
1856 }
1857
1858 lck = odb_lock(req, pvfs->odb_context, &key);
1859 if (lck == NULL) {
1860 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1861 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1862 }
1863
1864 share_access = NTCREATEX_SHARE_ACCESS_READ |
1865 NTCREATEX_SHARE_ACCESS_WRITE;
1866 access_mask = SEC_STD_DELETE;
1867 delete_on_close = false;
1868
1869 status = odb_can_open(lck, name->stream_id,
1870 share_access, access_mask, delete_on_close,
1871 NTCREATEX_DISP_OPEN, false);
1872
1873 /*
1874 * if it's a sharing violation or we got no oplock
1875 * only keep the lock if the caller requested access
1876 * to the lock
1877 */
1878 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1879 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1880 if (lckp) {
1881 *lckp = lck;
1882 } else {
1883 talloc_free(lck);
1884 }
1885 } else if (!NT_STATUS_IS_OK(status)) {
1886 talloc_free(lck);
1887 if (lckp) {
1888 *lckp = NULL;
1889 }
1890 } else if (lckp) {
1891 *lckp = lck;
1892 }
1893
1894 return status;
1895}
1896
1897/*
1898 determine if the file size of a file can be changed,
1899 or if it is prevented by an already open file
1900*/
1901NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1902 struct ntvfs_request *req,
1903 struct pvfs_filename *name,
1904 struct odb_lock **lckp)
1905{
1906 NTSTATUS status;
1907 DATA_BLOB key;
1908 struct odb_lock *lck;
1909 uint32_t share_access;
1910 uint32_t access_mask;
1911 bool break_to_none;
1912 bool delete_on_close;
1913
1914 status = pvfs_locking_key(name, name, &key);
1915 if (!NT_STATUS_IS_OK(status)) {
1916 return NT_STATUS_NO_MEMORY;
1917 }
1918
1919 lck = odb_lock(req, pvfs->odb_context, &key);
1920 if (lck == NULL) {
1921 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1922 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1923 }
1924
1925 share_access = NTCREATEX_SHARE_ACCESS_READ |
1926 NTCREATEX_SHARE_ACCESS_WRITE |
1927 NTCREATEX_SHARE_ACCESS_DELETE;
1928 /*
1929 * I would have thought that we would need to pass
1930 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1931 *
1932 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1933 * to set the filesize.
1934 *
1935 * --metze
1936 */
1937 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1938 delete_on_close = false;
1939 break_to_none = true;
1940
1941 status = odb_can_open(lck, name->stream_id,
1942 share_access, access_mask, delete_on_close,
1943 NTCREATEX_DISP_OPEN, break_to_none);
1944
1945 /*
1946 * if it's a sharing violation or we got no oplock
1947 * only keep the lock if the caller requested access
1948 * to the lock
1949 */
1950 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1951 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1952 if (lckp) {
1953 *lckp = lck;
1954 } else {
1955 talloc_free(lck);
1956 }
1957 } else if (!NT_STATUS_IS_OK(status)) {
1958 talloc_free(lck);
1959 if (lckp) {
1960 *lckp = NULL;
1961 }
1962 } else if (lckp) {
1963 *lckp = lck;
1964 }
1965
1966 return status;
1967}
1968
1969/*
1970 determine if file meta data can be accessed, or if it is prevented by an
1971 already open file
1972*/
1973NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1974 struct ntvfs_request *req,
1975 struct pvfs_filename *name)
1976{
1977 NTSTATUS status;
1978 DATA_BLOB key;
1979 struct odb_lock *lck;
1980 uint32_t share_access;
1981 uint32_t access_mask;
1982 bool delete_on_close;
1983
1984 status = pvfs_locking_key(name, name, &key);
1985 if (!NT_STATUS_IS_OK(status)) {
1986 return NT_STATUS_NO_MEMORY;
1987 }
1988
1989 lck = odb_lock(req, pvfs->odb_context, &key);
1990 if (lck == NULL) {
1991 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1992 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1993 }
1994
1995 share_access = NTCREATEX_SHARE_ACCESS_READ |
1996 NTCREATEX_SHARE_ACCESS_WRITE;
1997 access_mask = SEC_FILE_READ_ATTRIBUTE;
1998 delete_on_close = false;
1999
2000 status = odb_can_open(lck, name->stream_id,
2001 share_access, access_mask, delete_on_close,
2002 NTCREATEX_DISP_OPEN, false);
2003
2004 if (!NT_STATUS_IS_OK(status)) {
2005 talloc_free(lck);
2006 }
2007
2008 return status;
2009}
2010
2011
2012/*
2013 determine if delete on close is set on
2014*/
2015bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2016{
2017 NTSTATUS status;
2018 bool del_on_close;
2019
2020 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2021 &del_on_close, NULL);
2022 if (!NT_STATUS_IS_OK(status)) {
2023 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2024 return false;
2025 }
2026
2027 return del_on_close;
2028}
Note: See TracBrowser for help on using the repository browser.