• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/ntvfs/posix/
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}
2029