summaryrefslogtreecommitdiff
path: root/source3/modules/onefs_open.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/modules/onefs_open.c')
-rw-r--r--source3/modules/onefs_open.c2200
1 files changed, 0 insertions, 2200 deletions
diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c
deleted file mode 100644
index a77d6f3e7e..0000000000
--- a/source3/modules/onefs_open.c
+++ /dev/null
@@ -1,2200 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- *
- * This file began with some code from source3/smbd/open.c and has been
- * modified it work with ifs_createfile.
- *
- * ifs_createfile is a CIFS-specific syscall for opening/files and
- * directories. It adds support for:
- * - Full in-kernel access checks using a windows access_mask
- * - Cluster-coherent share mode locks
- * - Cluster-coherent oplocks
- * - Streams
- * - Setting security descriptors at create time
- * - Setting dos_attributes at create time
- *
- * Copyright (C) Andrew Tridgell 1992-1998
- * Copyright (C) Jeremy Allison 2001-2004
- * Copyright (C) Volker Lendecke 2005
- * Copyright (C) Tim Prouty, 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "smbd/smbd.h"
-#include "onefs.h"
-#include "onefs_config.h"
-#include "oplock_onefs.h"
-#include "smbd/globals.h"
-
-extern const struct generic_mapping file_generic_mapping;
-
-struct onefs_fsp_data {
- uint64_t oplock_callback_id;
-};
-
-static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
- struct smb_request *req,
- struct smb_filename *smb_fname,
- uint32_t access_mask,
- uint32_t share_access,
- uint32_t create_disposition,
- uint32_t create_options,
- uint32_t file_attributes,
- uint32_t oplock_request,
- uint64_t allocation_size,
- uint32_t private_flags,
- struct security_descriptor *sd,
- struct ea_list *ea_list,
- files_struct **result,
- int *pinfo,
- struct onefs_fsp_data *fsp_data);
-
-/****************************************************************************
- Open a file.
-****************************************************************************/
-
-static NTSTATUS onefs_open_file(files_struct *fsp,
- connection_struct *conn,
- struct smb_request *req,
- const char *parent_dir,
- struct smb_filename *smb_fname,
- int flags,
- mode_t unx_mode,
- uint32 access_mask,
- uint32 open_access_mask,
- int oplock_request,
- uint64 id,
- uint32 share_access,
- uint32 create_options,
- uint32_t new_dos_attributes,
- struct security_descriptor *sd,
- int *granted_oplock)
-{
- struct smb_filename *smb_fname_onefs = NULL;
- NTSTATUS status = NT_STATUS_OK;
- int accmode = (flags & O_ACCMODE);
- int local_flags = flags;
- bool file_existed = VALID_STAT(smb_fname->st);
- const char *wild;
- int base_fd = -1;
-
- fsp->fh->fd = -1;
- errno = EPERM;
-
- /* Check permissions */
-
- /*
- * This code was changed after seeing a client open request
- * containing the open mode of (DENY_WRITE/read-only) with
- * the 'create if not exist' bit set. The previous code
- * would fail to open the file read only on a read-only share
- * as it was checking the flags parameter directly against O_RDONLY,
- * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
- * JRA.
- */
-
- if (!CAN_WRITE(conn)) {
- /* It's a read-only share - fail if we wanted to write. */
- if(accmode != O_RDONLY) {
- DEBUG(3, ("Permission denied opening %s\n",
- smb_fname_str_dbg(smb_fname)));
- return NT_STATUS_ACCESS_DENIED;
- } else if(flags & O_CREAT) {
- /* We don't want to write - but we must make sure that
- O_CREAT doesn't create the file if we have write
- access into the directory.
- */
- flags &= ~O_CREAT;
- local_flags &= ~O_CREAT;
- }
- }
-
- /*
- * This little piece of insanity is inspired by the
- * fact that an NT client can open a file for O_RDONLY,
- * but set the create disposition to FILE_EXISTS_TRUNCATE.
- * If the client *can* write to the file, then it expects to
- * truncate the file, even though it is opening for readonly.
- * Quicken uses this stupid trick in backup file creation...
- * Thanks *greatly* to "David W. Chapman Jr." <dwcjr@inethouston.net>
- * for helping track this one down. It didn't bite us in 2.0.x
- * as we always opened files read-write in that release. JRA.
- */
-
- if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
- DEBUG(10,("onefs_open_file: truncate requested on read-only "
- "open for file %s\n", smb_fname_str_dbg(smb_fname)));
- local_flags = (flags & ~O_ACCMODE)|O_RDWR;
- }
-
-#if defined(O_NONBLOCK) && defined(S_ISFIFO)
- /*
- * We would block on opening a FIFO with no one else on the
- * other end. Do what we used to do and add O_NONBLOCK to the
- * open flags. JRA.
- */
-
- if (file_existed && S_ISFIFO(smb_fname->st.st_ex_mode)) {
- local_flags |= O_NONBLOCK;
- }
-#endif
-
- /* Don't create files with Microsoft wildcard characters. */
- if (fsp->base_fsp) {
- /*
- * wildcard characters are allowed in stream names
- * only test the basefilename
- */
- wild = fsp->base_fsp->fsp_name->base_name;
- } else {
- wild = smb_fname->base_name;
- }
- if ((local_flags & O_CREAT) && !file_existed &&
- ms_has_wild(wild)) {
- /*
- * XXX: may need to remvoe this return...
- *
- * We dont think this check needs to exist. All it does is
- * block creating files with Microsoft wildcards, which is
- * fine if the creation originated from NFS or locally and
- * then was copied via Samba.
- */
- DEBUG(1, ("onefs_open_file: creating file with wildcard: %s\n",
- smb_fname_str_dbg(smb_fname)));
- return NT_STATUS_OBJECT_NAME_INVALID;
- }
-
- /* Actually do the open */
-
-#ifdef O_NOFOLLOW
- /*
- * Never follow symlinks on a POSIX client. The
- * client should be doing this.
- */
-
- if (fsp->posix_open || !lp_symlinks(SNUM(conn))) {
- flags |= O_NOFOLLOW;
- }
-#endif
- /* Setup a onefs-style smb_fname struct. */
- status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname,
- &smb_fname_onefs);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- /* If it's a stream pass in the base_fd */
- if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
- is_ntfs_stream_smb_fname(smb_fname_onefs)) {
- SMB_ASSERT(fsp->base_fsp);
-
- DEBUG(10, ("Opening a stream: base=%s(%d), stream=%s\n",
- smb_fname_onefs->base_name, fsp->base_fsp->fh->fd,
- smb_fname_onefs->stream_name));
-
- base_fd = fsp->base_fsp->fh->fd;
- }
-
- fsp->fh->fd = onefs_sys_create_file(conn,
- base_fd,
- smb_fname_onefs->stream_name != NULL ?
- smb_fname_onefs->stream_name :
- smb_fname_onefs->base_name,
- access_mask,
- open_access_mask,
- share_access,
- create_options,
- flags,
- unx_mode,
- oplock_request,
- id,
- sd,
- new_dos_attributes,
- granted_oplock);
- TALLOC_FREE(smb_fname_onefs);
-
- if (fsp->fh->fd == -1) {
- if (errno == EMFILE) {
- static time_t last_warned = 0L;
-
- if (time((time_t *) NULL) > last_warned) {
- DEBUG(0, ("Too many open files, unable "
- "to open more! smbd's max "
- "open files = %d, also check "
- "sysctl kern.maxfiles and "
- "sysctl kern.maxfilesperproc\n",
- lp_max_open_files()));
- last_warned = time((time_t *) NULL);
- }
- }
-
- status = map_nt_error_from_unix(errno);
- DEBUG(3, ("Error opening file %s (%s) (local_flags=%d) "
- "(flags=%d)\n", smb_fname_str_dbg(smb_fname),
- strerror(errno), local_flags, flags));
- return status;
- }
-
- if ((local_flags & O_CREAT) && !file_existed) {
-
- /* Inherit the ACL if required */
- if (lp_inherit_perms(SNUM(conn))) {
- inherit_access_posix_acl(conn, parent_dir,
- smb_fname->base_name, unx_mode);
- }
-
- /* Change the owner if required. */
- if (lp_inherit_owner(SNUM(conn))) {
- change_file_owner_to_parent(conn, parent_dir,
- fsp);
- }
-
- notify_fname(conn, NOTIFY_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_FILE_NAME, smb_fname->base_name);
- }
-
- if (!file_existed) {
- int ret;
-
- if (fsp->fh->fd == -1) {
- ret = SMB_VFS_STAT(conn, smb_fname);
- } else {
- ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
- /* If we have an fd, this stat should succeed. */
- if (ret == -1) {
- DEBUG(0, ("Error doing fstat on open file %s "
- "(%s)\n",
- smb_fname_str_dbg(smb_fname),
- strerror(errno) ));
- }
- }
-
- /* For a non-io open, this stat failing means file not found. JRA */
- if (ret == -1) {
- status = map_nt_error_from_unix(errno);
- fd_close(fsp);
- return status;
- }
- }
-
- /*
- * POSIX allows read-only opens of directories. We don't
- * want to do this (we use a different code path for this)
- * so catch a directory open and return an EISDIR. JRA.
- */
-
- if(S_ISDIR(smb_fname->st.st_ex_mode)) {
- fd_close(fsp);
- errno = EISDIR;
- return NT_STATUS_FILE_IS_A_DIRECTORY;
- }
-
- fsp->mode = smb_fname->st.st_ex_mode;
- fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
- fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
- fsp->file_pid = req ? req->smbpid : 0;
- fsp->can_lock = True;
- fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
- if (!CAN_WRITE(conn)) {
- fsp->can_write = False;
- } else {
- fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ?
- True : False;
- }
- fsp->print_file = NULL;
- fsp->modified = False;
- fsp->sent_oplock_break = NO_BREAK_SENT;
- fsp->is_directory = False;
- if (conn->aio_write_behind_list &&
- is_in_path(smb_fname->base_name, conn->aio_write_behind_list,
- conn->case_sensitive)) {
- fsp->aio_write_behind = True;
- }
-
- fsp->wcp = NULL; /* Write cache pointer. */
-
- DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
- conn->session_info->unix_info->unix_name,
- smb_fname_str_dbg(smb_fname),
- BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
- conn->num_files_open));
-
- errno = 0;
- return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Handle the 1 second delay in returning a SHARING_VIOLATION error.
-****************************************************************************/
-
-static void defer_open(struct share_mode_lock *lck,
- struct timeval request_time,
- struct timeval timeout,
- struct smb_request *req,
- struct deferred_open_record *state)
-{
- int i;
-
- /* Paranoia check */
-
- for (i=0; i<lck->num_share_modes; i++) {
- struct share_mode_entry *e = &lck->share_modes[i];
-
- if (!is_deferred_open_entry(e)) {
- continue;
- }
-
- if (procid_is_me(&e->pid) && (e->op_mid == req->mid)) {
- DEBUG(0, ("Trying to defer an already deferred "
- "request: mid=%llu, exiting\n",
- (unsigned long long)req->mid));
- exit_server("attempt to defer a deferred request");
- }
- }
-
- /* End paranoia check */
-
- DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred "
- "open entry for mid %llu\n",
- (unsigned int)request_time.tv_sec,
- (unsigned int)request_time.tv_usec,
- (unsigned long long)req->mid));
-
- if (!push_deferred_open_message_smb(req, request_time, timeout,
- state->id, (char *)state, sizeof(*state))) {
- exit_server("push_deferred_open_message_smb failed");
- }
- add_deferred_open(lck, req->mid, request_time, state->id);
-}
-
-static void schedule_defer_open(struct share_mode_lock *lck,
- struct timeval request_time,
- struct smb_request *req)
-{
- struct deferred_open_record state;
-
- /* This is a relative time, added to the absolute
- request_time value to get the absolute timeout time.
- Note that if this is the second or greater time we enter
- this codepath for this particular request mid then
- request_time is left as the absolute time of the *first*
- time this request mid was processed. This is what allows
- the request to eventually time out. */
-
- struct timeval timeout;
-
- /* Normally the smbd we asked should respond within
- * OPLOCK_BREAK_TIMEOUT seconds regardless of whether
- * the client did, give twice the timeout as a safety
- * measure here in case the other smbd is stuck
- * somewhere else. */
-
- /*
- * On OneFS, the kernel will always send an oplock_revoked message
- * before this timeout is hit.
- */
- timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*10, 0);
-
- /* Nothing actually uses state.delayed_for_oplocks
- but it's handy to differentiate in debug messages
- between a 30 second delay due to oplock break, and
- a 1 second delay for share mode conflicts. */
-
- state.delayed_for_oplocks = True;
- state.failed = false;
- state.id = lck->id;
-
- if (!request_timed_out(request_time, timeout)) {
- defer_open(lck, request_time, timeout, req, &state);
- } else {
- /* A delayed-for-oplocks deferred open timing out should only
- * happen if there is a bug or extreme load, since we set the
- * timeout to 300 seconds. */
- DEBUG(0, ("Deferred open timeout! request_time=%d.%d, "
- "mid=%d\n", request_time.tv_sec, request_time.tv_usec,
- req->mid));
- }
-}
-
-/****************************************************************************
- Open a file with a share mode. Passed in an already created files_struct.
-****************************************************************************/
-NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
- struct smb_request *req,
- struct smb_filename *smb_fname,
- uint32 access_mask,
- uint32 share_access,
- uint32 create_disposition,
- uint32 create_options,
- uint32 new_dos_attributes,
- int oplock_request,
- uint32_t private_flags,
- struct security_descriptor *sd,
- files_struct *fsp,
- int *pinfo,
- struct onefs_fsp_data *fsp_data)
-{
- int flags=0;
- int flags2=0;
- bool file_existed = VALID_STAT(smb_fname->st);
- bool def_acl = False;
- bool posix_open = False;
- bool new_file_created = False;
- bool clear_ads = False;
- struct file_id id;
- mode_t new_unx_mode = (mode_t)0;
- mode_t unx_mode = (mode_t)0;
- int info;
- uint32 existing_dos_attributes = 0;
- struct timeval request_time = timeval_zero();
- struct share_mode_lock *lck = NULL;
- uint32 open_access_mask = access_mask;
- NTSTATUS status;
- int ret_flock;
- char *parent_dir;
- int granted_oplock;
- uint64_t oplock_callback_id = 0;
- uint32 createfile_attributes = 0;
-
- ZERO_STRUCT(id);
-
- if (conn->printer) {
- /*
- * Printers are handled completely differently.
- * Most of the passed parameters are ignored.
- */
-
- if (pinfo) {
- *pinfo = FILE_WAS_CREATED;
- }
-
- DEBUG(10, ("onefs_open_file_ntcreate: printer open fname=%s\n",
- smb_fname_str_dbg(smb_fname)));
-
- return print_spool_open(fsp, smb_fname->base_name,
- req->vuid);
- }
-
- if (!parent_dirname(talloc_tos(), smb_fname->base_name, &parent_dir,
- NULL)) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (new_dos_attributes & FILE_FLAG_POSIX_SEMANTICS) {
- posix_open = True;
- unx_mode = (mode_t)(new_dos_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
- new_dos_attributes = 0;
- } else {
- /* We add FILE_ATTRIBUTE_ARCHIVE to this as this mode is only used if the file is
- * created new. */
- unx_mode = unix_mode(conn, new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE,
- smb_fname, parent_dir);
- }
-
- DEBUG(10,("onefs_open_file_ntcreate: fname=%s, dos_attrs=0x%x "
- "access_mask=0x%x share_access=0x%x "
- "create_disposition = 0x%x create_options=0x%x "
- "unix mode=0%o oplock_request=0x%x\n",
- smb_fname_str_dbg(smb_fname), new_dos_attributes,
- access_mask, share_access, create_disposition,
- create_options, unx_mode, oplock_request));
-
- /*
- * Any non-stat-only open has the potential to contend oplocks, which
- * means to avoid blocking in the kernel (which is unacceptable), the
- * open must be deferred. In order to defer opens, req must not be
- * NULL. The known cases of calling with a NULL req:
- *
- * 1. Open the base file of a stream: Always done stat-only
- *
- * 2. open_file_fchmod(), which is called from 3 places:
- * A. try_chown: Posix acls only. Never called on onefs.
- * B. set_ea_dos_attributes: Can't be called from onefs, because
- * SMB_VFS_SETXATTR return ENOSYS.
- * C. file_set_dos_mode: This would only happen if the "dos
- * filemode" smb.conf parameter is set to yes. We ship with
- * it off, but if a customer were to turn it on it would be
- * bad.
- */
- if (req == NULL && !is_stat_open(access_mask) &&
- !is_ntfs_stream_smb_fname(smb_fname)) {
- smb_panic("NULL req on a non-stat-open!");
- }
-
- if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) {
- DEBUG(0, ("No smb request but not an internal only open!\n"));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- /*
- * Only non-internal opens can be deferred at all
- */
-
- if (req) {
- void *ptr;
- if (get_deferred_open_message_state(req,
- &request_time,
- &ptr)) {
- struct deferred_open_record *state = (struct deferred_open_record *)ptr;
-
- /* Remember the absolute time of the original
- request with this mid. We'll use it later to
- see if this has timed out. */
-
- /* Remove the deferred open entry under lock. */
- remove_deferred_open_entry(state->id, req->mid);
-
- /* Ensure we don't reprocess this message. */
- remove_deferred_open_message_smb(req->mid);
-
- /*
- * When receiving a semlock_async_failure message, the
- * deferred open will be marked as "failed". Returning
- * INTERNAL_ERROR.
- */
- if (state->failed) {
- DEBUG(0, ("onefs_open_file_ntcreate: "
- "semlock_async_failure detected!\n"));
- return NT_STATUS_INTERNAL_ERROR;
- }
- }
- }
-
- status = check_name(conn, smb_fname->base_name);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- if (!posix_open) {
- new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
- if (file_existed) {
- existing_dos_attributes = dos_mode(conn, smb_fname);
- }
- }
-
- /* Setup dos_attributes to be set by ifs_createfile */
- if (lp_store_dos_attributes(SNUM(conn))) {
- createfile_attributes = (new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE) &
- ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED);
- }
-
- /* Ignore oplock requests if oplocks are disabled. */
- if (!lp_oplocks(SNUM(conn)) ||
- IS_VETO_OPLOCK_PATH(conn, smb_fname->base_name)) {
- /* Mask off everything except the private Samba bits. */
- oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK;
- }
-
- /* this is for OS/2 long file names - say we don't support them */
- if (!lp_posix_pathnames() && strstr(smb_fname->base_name,".+,;=[].")) {
- /* OS/2 Workplace shell fix may be main code stream in a later
- * release. */
- DEBUG(5,("onefs_open_file_ntcreate: OS/2 long filenames are "
- "not supported.\n"));
- if (use_nt_status()) {
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
- return NT_STATUS_DOS(ERRDOS, ERRcannotopen);
- }
-
- switch( create_disposition ) {
- /*
- * Currently we're using FILE_SUPERSEDE as the same as
- * FILE_OVERWRITE_IF but they really are
- * different. FILE_SUPERSEDE deletes an existing file
- * (requiring delete access) then recreates it.
- */
- case FILE_SUPERSEDE:
- /**
- * @todo: Clear all file attributes?
- * http://www.osronline.com/article.cfm?article=302
- * create if not exist, trunc if exist
- *
- * If file exists replace/overwrite. If file doesn't
- * exist create.
- */
- flags2 |= (O_CREAT | O_TRUNC);
- clear_ads = true;
- break;
-
- case FILE_OVERWRITE_IF:
- /* If file exists replace/overwrite. If file doesn't
- * exist create. */
- flags2 |= (O_CREAT | O_TRUNC);
- clear_ads = true;
- break;
-
- case FILE_OPEN:
- /* If file exists open. If file doesn't exist error. */
- if (!file_existed) {
- DEBUG(5,("onefs_open_file_ntcreate: FILE_OPEN "
- "requested for file %s and file "
- "doesn't exist.\n",
- smb_fname_str_dbg(smb_fname)));
- errno = ENOENT;
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
- break;
-
- case FILE_OVERWRITE:
- /* If file exists overwrite. If file doesn't exist
- * error. */
- if (!file_existed) {
- DEBUG(5, ("onefs_open_file_ntcreate: "
- "FILE_OVERWRITE requested for file "
- "%s and file doesn't exist.\n",
- smb_fname_str_dbg(smb_fname)));
- errno = ENOENT;
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
- flags2 |= O_TRUNC;
- clear_ads = true;
- break;
-
- case FILE_CREATE:
- /* If file exists error. If file doesn't exist
- * create. */
- if (file_existed) {
- DEBUG(5, ("onefs_open_file_ntcreate: "
- "FILE_CREATE requested for file %s "
- "and file already exists.\n",
- smb_fname_str_dbg(smb_fname)));
- if (S_ISDIR(smb_fname->st.st_ex_mode)) {
- errno = EISDIR;
- } else {
- errno = EEXIST;
- }
- return map_nt_error_from_unix(errno);
- }
- flags2 |= (O_CREAT|O_EXCL);
- break;
-
- case FILE_OPEN_IF:
- /* If file exists open. If file doesn't exist
- * create. */
- flags2 |= O_CREAT;
- break;
-
- default:
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- /* Match attributes on file exists and overwrite. */
- if (!posix_open && file_existed &&
- ((create_disposition == FILE_OVERWRITE) ||
- (create_disposition == FILE_OVERWRITE_IF))) {
- if (!open_match_attributes(conn, existing_dos_attributes,
- new_dos_attributes,
- smb_fname->st.st_ex_mode,
- unx_mode, &new_unx_mode)) {
- DEBUG(5, ("onefs_open_file_ntcreate: attributes "
- "missmatch for file %s (%x %x) (0%o, 0%o)\n",
- smb_fname_str_dbg(smb_fname),
- existing_dos_attributes,
- new_dos_attributes,
- (unsigned int)smb_fname->st.st_ex_mode,
- (unsigned int)unx_mode ));
- errno = EACCES;
- return NT_STATUS_ACCESS_DENIED;
- }
- }
-
- /*
- * OneFS understands MAXIMUM_ALLOWED_ACCESS, so only hack the
- * access_mask, but leave the MAA for the actual open in
- * open_access_mask.
- */
- open_access_mask = access_mask;
- if (open_access_mask & MAXIMUM_ALLOWED_ACCESS) {
- access_mask |= FILE_GENERIC_ALL;
- }
-
- /* Convert GENERIC bits to specific bits. */
- se_map_generic(&access_mask, &file_generic_mapping);
- se_map_generic(&open_access_mask, &file_generic_mapping);
-
- if ((flags2 & O_TRUNC) || (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) {
- /* This will cause oplock breaks. */
- open_access_mask |= FILE_WRITE_DATA;
- }
-
- DEBUG(10, ("onefs_open_file_ntcreate: fname=%s, after mapping "
- "open_access_mask=%#x, access_mask=0x%x\n",
- smb_fname_str_dbg(smb_fname), open_access_mask,
- access_mask));
-
- /*
- * Note that we ignore the append flag as append does not
- * mean the same thing under DOS and Unix.
- */
-
- if ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ||
- (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) {
-
- /*
- * DENY_DOS opens are always underlying read-write on the
- * file handle, no matter what the requested access mask
- * says. Stock samba just sets the flags, but since
- * ifs_createfile uses the access_mask, it must be updated as
- * well. This allows BASE-DENY* to pass.
- */
- if (create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) {
-
- DEBUG(10,("onefs_open_file_ntcreate: deny_dos: "
- "Adding O_RDWR to flags "
- "(0x%x) and some READ bits to "
- "open_access_mask (0x%x)\n",
- flags, open_access_mask));
-
- flags = O_RDWR;
- open_access_mask |= (FILE_READ_ATTRIBUTES |
- FILE_READ_DATA | FILE_READ_EA | FILE_EXECUTE);
-
- } else if (access_mask & (FILE_READ_ATTRIBUTES |
- FILE_READ_DATA |
- FILE_READ_EA |
- FILE_EXECUTE)) {
- flags = O_RDWR;
- } else {
- flags = O_WRONLY;
- }
- } else {
- flags = O_RDONLY;
- }
-
- /* Currently we only look at FILE_WRITE_THROUGH for create options. */
-#if defined(O_SYNC)
- if ((create_options & FILE_WRITE_THROUGH) &&
- lp_strict_sync(SNUM(conn))) {
- flags2 |= O_SYNC;
- }
-#endif /* O_SYNC */
-
- if (posix_open && (access_mask & FILE_APPEND_DATA)) {
- flags2 |= O_APPEND;
- }
-
- if (!posix_open && !CAN_WRITE(conn)) {
- /*
- * We should really return a permission denied error if either
- * O_CREAT or O_TRUNC are set, but for compatibility with
- * older versions of Samba we just AND them out.
- */
- flags2 &= ~(O_CREAT|O_TRUNC);
-
- /* Deny DELETE_ACCESS explicitly if the share is read only. */
- if (access_mask & DELETE_ACCESS) {
- return map_nt_error_from_unix(EACCES);
- }
- }
-
- /* Ensure we can't write on a read-only share or file. */
- if (flags != O_RDONLY && file_existed &&
- (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) {
- DEBUG(5, ("onefs_open_file_ntcreate: write access requested "
- "for file %s on read only %s\n",
- smb_fname_str_dbg(smb_fname),
- !CAN_WRITE(conn) ? "share" : "file" ));
- errno = EACCES;
- return NT_STATUS_ACCESS_DENIED;
- }
-
- DEBUG(10, ("fsp = %p\n", fsp));
-
- fsp->share_access = share_access;
- fsp->fh->private_options = private_flags;
- fsp->access_mask = open_access_mask; /* We change this to the
- * requested access_mask after
- * the open is done. */
- fsp->posix_open = posix_open;
-
- /* Ensure no SAMBA_PRIVATE bits can be set. */
- fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
-
- if (timeval_is_zero(&request_time)) {
- request_time = fsp->open_time;
- }
-
- if (file_existed) {
- struct timespec old_write_time = smb_fname->st.st_ex_mtime;
- id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
-
- lck = get_share_mode_lock(talloc_tos(), id,
- conn->connectpath,
- smb_fname, &old_write_time);
-
- if (lck == NULL) {
- DEBUG(0, ("Could not get share mode lock\n"));
- return NT_STATUS_SHARING_VIOLATION;
- }
-
- if (lck->delete_on_close) {
- /* DELETE_PENDING is not deferred for a second */
- TALLOC_FREE(lck);
- return NT_STATUS_DELETE_PENDING;
- }
- }
-
- SMB_ASSERT(!file_existed || (lck != NULL));
-
- /*
- * Ensure we pay attention to default ACLs on directories. May be
- * neccessary depending on ACL policies.
- */
- if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) &&
- (def_acl = directory_has_default_acl(conn, parent_dir))) {
- unx_mode = 0777;
- }
-
- DEBUG(4,("calling onefs_open_file with flags=0x%X flags2=0x%X "
- "mode=0%o, access_mask = 0x%x, open_access_mask = 0x%x\n",
- (unsigned int)flags, (unsigned int)flags2,
- (unsigned int)unx_mode, (unsigned int)access_mask,
- (unsigned int)open_access_mask));
-
- /*
- * Since the open is guaranteed to be stat only if req == NULL, a
- * callback record is only needed if req != NULL.
- */
- if (req) {
- SMB_ASSERT(fsp_data);
- oplock_callback_id = onefs_oplock_wait_record(req->sconn,
- req->mid);
- if (oplock_callback_id == 0) {
- return NT_STATUS_NO_MEMORY;
- }
- } else {
- /*
- * It is also already asserted it's either a stream or a
- * stat-only open at this point.
- */
- SMB_ASSERT(fsp->oplock_type == NO_OPLOCK);
-
- /* The kernel and Samba's version of stat-only differs
- * slightly: The kernel doesn't think its stat-only if we're
- * truncating. We'd better have a req in order to defer the
- * open. */
- SMB_ASSERT(!((flags|flags2) & O_TRUNC));
- }
-
- /* Do the open. */
- status = onefs_open_file(fsp,
- conn,
- req,
- parent_dir,
- smb_fname,
- flags|flags2,
- unx_mode,
- access_mask,
- open_access_mask,
- fsp->oplock_type,
- oplock_callback_id,
- share_access,
- create_options,
- createfile_attributes,
- sd,
- &granted_oplock);
-
- if (!NT_STATUS_IS_OK(status)) {
-
- /* OneFS Oplock Handling */
- if (errno == EINPROGRESS) {
-
- /* If we get EINPROGRESS, the kernel will send us an
- * asynchronous semlock event back. Ensure we can defer
- * the open, by asserting req. */
- SMB_ASSERT(req);
-
- if (lck == NULL) {
- /*
- * We hit the race that when we did the stat
- * on the file it did not exist, and someone
- * has created it in between the stat and the
- * open_file() call. Defer our open waiting,
- * to break the oplock of the first opener.
- */
-
- struct timespec old_write_time;
-
- DEBUG(3, ("Someone created file %s with an "
- "oplock after we looked: Retrying\n",
- smb_fname_str_dbg(smb_fname)));
- /*
- * We hit the race that when we did the stat
- * on the file it did not exist, and someone
- * has created it in between the stat and the
- * open_file() call. Just retry immediately.
- */
- id = vfs_file_id_from_sbuf(conn,
- &smb_fname->st);
- if (!(lck = get_share_mode_lock(talloc_tos(),
- id, conn->connectpath, smb_fname,
- &old_write_time))) {
- /*
- * Emergency exit
- */
- DEBUG(0, ("onefs_open_file_ntcreate: "
- "Could not get share mode "
- "lock for %s\n",
- smb_fname_str_dbg(smb_fname)));
- status = NT_STATUS_SHARING_VIOLATION;
-
- /* XXXZLK: This will cause us to get a
- * semlock event when we aren't
- * expecting one. */
- goto cleanup_destroy;
- }
-
- schedule_defer_open(lck, request_time, req);
- goto cleanup;
- }
- /* Waiting for an oplock */
- DEBUG(5,("Async createfile because a client has an "
- "oplock on %s\n",
- smb_fname_str_dbg(smb_fname)));
-
- SMB_ASSERT(req);
- schedule_defer_open(lck, request_time, req);
- goto cleanup;
- }
-
- /* Check for a sharing violation */
- if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
- uint32 can_access_mask;
- bool can_access = True;
-
- /* If we raced on open we may not have a valid file_id
- * or stat buf. Get them again. */
- if (SMB_VFS_STAT(conn, fname, psbuf) == -1) {
- DEBUG(0,("Error doing stat on file %s "
- "(%s)\n", fname, strerror(errno)));
- status = NT_STATUS_SHARING_VIOLATION;
- goto cleanup_destroy;
- }
- id = vfs_file_id_from_sbuf(conn, psbuf);
-
- /* Check if this can be done with the deny_dos and fcb
- * calls. */
-
- /* Try to find dup fsp if possible. */
- if (private_flags &
- (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
- NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
-
- if (req == NULL) {
- DEBUG(0, ("DOS open without an SMB "
- "request!\n"));
- status = NT_STATUS_INTERNAL_ERROR;
- goto cleanup_destroy;
- }
-
- /* Use the client requested access mask here,
- * not the one we open with. */
- status = fcb_or_dos_open(req,
- conn,
- fsp,
- smb_fname,
- id,
- req->smbpid,
- req->vuid,
- access_mask,
- share_access,
- create_options);
-
- if (NT_STATUS_IS_OK(status)) {
- if (pinfo) {
- *pinfo = FILE_WAS_OPENED;
- }
- status = NT_STATUS_OK;
- goto cleanup;
- }
- }
-
- /*
- * This next line is a subtlety we need for
- * MS-Access. If a file open will fail due to share
- * permissions and also for security (access) reasons,
- * we need to return the access failed error, not the
- * share error. We can't open the file due to kernel
- * oplock deadlock (it's possible we failed above on
- * the open_mode_check()) so use a userspace check.
- */
-
- if (flags & O_RDWR) {
- can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
- } else if (flags & O_WRONLY) {
- can_access_mask = FILE_WRITE_DATA;
- } else {
- can_access_mask = FILE_READ_DATA;
- }
-
- if (((can_access_mask & FILE_WRITE_DATA) &&
- !CAN_WRITE(conn)) ||
- !NT_STATUS_IS_OK(smbd_check_access_rights(conn,
- smb_fname, can_access_mask))) {
- can_access = False;
- }
-
- /*
- * If we're returning a share violation, ensure we
- * cope with the braindead 1 second delay.
- */
- if (!(oplock_request & INTERNAL_OPEN_ONLY) &&
- lp_defer_sharing_violations()) {
- struct timeval timeout;
- struct deferred_open_record state;
- int timeout_usecs;
-
- /* this is a hack to speed up torture tests
- in 'make test' */
- timeout_usecs = lp_parm_int(SNUM(conn),
- "smbd","sharedelay",
- SHARING_VIOLATION_USEC_WAIT);
-
- /* This is a relative time, added to the
- absolute request_time value to get the
- absolute timeout time. Note that if this
- is the second or greater time we enter this
- codepath for this particular request mid
- then request_time is left as the absolute
- time of the *first* time this request mid
- was processed. This is what allows the
- request to eventually time out. */
-
- timeout = timeval_set(0, timeout_usecs);
-
- /* Nothing actually uses
- state.delayed_for_oplocks but it's handy to
- differentiate in debug messages between a
- 30 second delay due to oplock break, and a
- 1 second delay for share mode conflicts. */
-
- state.delayed_for_oplocks = False;
- state.id = id;
- state.failed = false;
-
- /*
- * We hit the race that when we did the stat
- * on the file it did not exist, and someone
- * has created it in between the stat and the
- * open_file() call. Retrieve the share_mode
- * lock on the newly opened file so we can
- * defer our request.
- */
- if (lck == NULL) {
- struct timespec old_write_time;
- old_write_time = get_mtimespec(psbuf);
-
- lck = get_share_mode_lock(talloc_tos(),
- id, conn->connectpath, fname,
- &old_write_time);
- if (lck == NULL) {
- DEBUG(0,
- ("onefs_open_file_ntcreate:"
- " Could not get share "
- "mode lock for %s\n",
- fname));
- /* This will cause us to return
- * immediately skipping the
- * the 1 second delay, which
- * isn't a big deal */
- status = NT_STATUS_SHARING_VIOLATION;
- goto cleanup_destroy;
- }
- }
-
- if ((req != NULL) &&
- !request_timed_out(request_time, timeout))
- {
- defer_open(lck, request_time, timeout,
- req, &state);
- }
- }
-
- if (can_access) {
- /*
- * We have detected a sharing violation here
- * so return the correct error code
- */
- status = NT_STATUS_SHARING_VIOLATION;
- } else {
- status = NT_STATUS_ACCESS_DENIED;
- }
-
- goto cleanup_destroy;
- }
-
- /*
- * Normal error, for example EACCES
- */
- cleanup_destroy:
- if (oplock_callback_id != 0) {
- destroy_onefs_callback_record(oplock_callback_id);
- }
- cleanup:
- TALLOC_FREE(lck);
- return status;
- }
-
- fsp->oplock_type = granted_oplock;
-
- if (oplock_callback_id != 0) {
- onefs_set_oplock_callback(oplock_callback_id, fsp);
- fsp_data->oplock_callback_id = oplock_callback_id;
- } else {
- SMB_ASSERT(fsp->oplock_type == NO_OPLOCK);
- }
-
- if (!file_existed) {
- struct timespec old_write_time = smb_fname->st.st_ex_mtime;
- /*
- * Deal with the race condition where two smbd's detect the
- * file doesn't exist and do the create at the same time. One
- * of them will win and set a share mode, the other (ie. this
- * one) should check if the requested share mode for this
- * create is allowed.
- */
-
- /*
- * Now the file exists and fsp is successfully opened,
- * fsp->file_id is valid and should replace the
- * dev=0, inode=0 from a non existent file. Spotted by
- * Nadav Danieli <nadavd@exanet.com>. JRA.
- */
-
- id = fsp->file_id;
-
- lck = get_share_mode_lock(talloc_tos(), id,
- conn->connectpath,
- smb_fname, &old_write_time);
-
- if (lck == NULL) {
- DEBUG(0, ("onefs_open_file_ntcreate: Could not get "
- "share mode lock for %s\n",
- smb_fname_str_dbg(smb_fname)));
- fd_close(fsp);
- return NT_STATUS_SHARING_VIOLATION;
- }
-
- if (lck->delete_on_close) {
- status = NT_STATUS_DELETE_PENDING;
- }
-
- if (!NT_STATUS_IS_OK(status)) {
- struct deferred_open_record state;
-
- fd_close(fsp);
-
- state.delayed_for_oplocks = False;
- state.id = id;
-
- /* Do it all over again immediately. In the second
- * round we will find that the file existed and handle
- * the DELETE_PENDING and FCB cases correctly. No need
- * to duplicate the code here. Essentially this is a
- * "goto top of this function", but don't tell
- * anybody... */
-
- if (req != NULL) {
- defer_open(lck, request_time, timeval_zero(),
- req, &state);
- }
- TALLOC_FREE(lck);
- return status;
- }
-
- /*
- * We exit this block with the share entry *locked*.....
- */
-
- }
-
- SMB_ASSERT(lck != NULL);
-
- /* Delete streams if create_disposition requires it */
- if (file_existed && clear_ads &&
- !is_ntfs_stream_smb_fname(smb_fname)) {
- status = delete_all_streams(conn, smb_fname->base_name);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(lck);
- fd_close(fsp);
- return status;
- }
- }
-
- /* note that we ignore failure for the following. It is
- basically a hack for NFS, and NFS will never set one of
- these only read them. Nobody but Samba can ever set a deny
- mode and we have already checked our more authoritative
- locking database for permission to set this deny mode. If
- the kernel refuses the operations then the kernel is wrong.
- note that GPFS supports it as well - jmcd */
-
- if (fsp->fh->fd != -1) {
- ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access, access_mask);
- if(ret_flock == -1 ){
-
- TALLOC_FREE(lck);
- fd_close(fsp);
- return NT_STATUS_SHARING_VIOLATION;
- }
- }
-
- /*
- * At this point onwards, we can guarentee that the share entry
- * is locked, whether we created the file or not, and that the
- * deny mode is compatible with all current opens.
- */
-
- /*
- * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted,
- */
- fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES;
-
- if (file_existed) {
- /* stat opens on existing files don't get oplocks. */
- if (is_stat_open(open_access_mask)) {
- fsp->oplock_type = NO_OPLOCK;
- }
-
- if (!(flags2 & O_TRUNC)) {
- info = FILE_WAS_OPENED;
- } else {
- info = FILE_WAS_OVERWRITTEN;
- }
- } else {
- info = FILE_WAS_CREATED;
- }
-
- if (pinfo) {
- *pinfo = info;
- }
-
- /*
- * Setup the oplock info in both the shared memory and
- * file structs.
- */
-
- if ((fsp->oplock_type != NO_OPLOCK) &&
- (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
- if (!set_file_oplock(fsp, fsp->oplock_type)) {
- /* Could not get the kernel oplock */
- fsp->oplock_type = NO_OPLOCK;
- }
- }
-
- if (fsp->oplock_type == LEVEL_II_OPLOCK &&
- (!lp_level2_oplocks(SNUM(conn)) ||
- !(global_client_caps & CAP_LEVEL_II_OPLOCKS))) {
-
- DEBUG(5, ("Downgrading level2 oplock on open "
- "because level2 oplocks = off\n"));
-
- release_file_oplock(fsp);
- }
-
- if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
- info == FILE_WAS_SUPERSEDED) {
- new_file_created = True;
- }
-
- set_share_mode(lck, fsp, get_current_uid(conn),
- req ? req->mid : 0,
- fsp->oplock_type);
-
- /* Handle strange delete on close create semantics. */
- if (create_options & FILE_DELETE_ON_CLOSE) {
- status = can_set_delete_on_close(fsp, new_dos_attributes);
-
- if (!NT_STATUS_IS_OK(status)) {
- /* Remember to delete the mode we just added. */
- del_share_mode(lck, fsp);
- TALLOC_FREE(lck);
- fd_close(fsp);
- return status;
- }
- /* Note that here we set the *inital* delete on close flag,
- not the regular one. The magic gets handled in close. */
- fsp->initial_delete_on_close = True;
- }
-
- /*
- * Take care of inherited ACLs on created files - if default ACL not
- * selected.
- * May be necessary depending on acl policies.
- */
- if (!posix_open && !file_existed && !def_acl &&
- !(VALID_STAT(smb_fname->st) &&
- (smb_fname->st.st_ex_flags & SF_HASNTFSACL))) {
-
- int saved_errno = errno; /* We might get ENOSYS in the next
- * call.. */
-
- if (SMB_VFS_FCHMOD_ACL(fsp, unx_mode) == -1 &&
- errno == ENOSYS) {
- errno = saved_errno; /* Ignore ENOSYS */
- }
-
- } else if (new_unx_mode) {
-
- int ret = -1;
-
- /* Attributes need changing. File already existed. */
-
- {
- int saved_errno = errno; /* We might get ENOSYS in the
- * next call.. */
- ret = SMB_VFS_FCHMOD_ACL(fsp, new_unx_mode);
-
- if (ret == -1 && errno == ENOSYS) {
- errno = saved_errno; /* Ignore ENOSYS */
- } else {
- DEBUG(5, ("onefs_open_file_ntcreate: reset "
- "attributes of file %s to 0%o\n",
- smb_fname_str_dbg(smb_fname),
- (unsigned int)new_unx_mode));
- ret = 0; /* Don't do the fchmod below. */
- }
- }
-
- if ((ret == -1) &&
- (SMB_VFS_FCHMOD(fsp, new_unx_mode) == -1))
- DEBUG(5, ("onefs_open_file_ntcreate: failed to reset "
- "attributes of file %s to 0%o\n",
- smb_fname_str_dbg(smb_fname),
- (unsigned int)new_unx_mode));
- }
-
- /* If this is a successful open, we must remove any deferred open
- * records. */
- if (req != NULL) {
- del_deferred_open_entry(lck, req->mid);
- }
- TALLOC_FREE(lck);
-
- return NT_STATUS_OK;
-}
-
-
-/****************************************************************************
- Open a directory from an NT SMB call.
-****************************************************************************/
-static NTSTATUS onefs_open_directory(connection_struct *conn,
- struct smb_request *req,
- struct smb_filename *smb_dname,
- uint32 access_mask,
- uint32 share_access,
- uint32 create_disposition,
- uint32 create_options,
- uint32 file_attributes,
- struct security_descriptor *sd,
- files_struct **result,
- int *pinfo)
-{
- files_struct *fsp = NULL;
- struct share_mode_lock *lck = NULL;
- NTSTATUS status;
- struct timespec mtimespec;
- int info = 0;
- char *parent_dir;
- bool posix_open = false;
- uint32 create_flags = 0;
- uint32 mode = lp_dir_mask(SNUM(conn));
-
- DEBUG(5, ("onefs_open_directory: opening directory %s, "
- "access_mask = 0x%x, "
- "share_access = 0x%x create_options = 0x%x, "
- "create_disposition = 0x%x, file_attributes = 0x%x\n",
- smb_fname_str_dbg(smb_dname), (unsigned int)access_mask,
- (unsigned int)share_access, (unsigned int)create_options,
- (unsigned int)create_disposition,
- (unsigned int)file_attributes));
-
- if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) &&
- (conn->fs_capabilities & FILE_NAMED_STREAMS) &&
- is_ntfs_stream_smb_fname(smb_dname)) {
- DEBUG(2, ("onefs_open_directory: %s is a stream name!\n",
- smb_fname_str_dbg(smb_dname)));
- return NT_STATUS_NOT_A_DIRECTORY;
- }
-
- switch (create_disposition) {
- case FILE_OPEN:
- /* If directory exists open. If directory doesn't
- * exist error. */
- create_flags = 0;
- info = FILE_WAS_OPENED;
- break;
- case FILE_CREATE:
- /* If directory exists error. If directory doesn't
- * exist create. */
- create_flags = O_CREAT | O_EXCL;
- info = FILE_WAS_CREATED;
- break;
- case FILE_OPEN_IF:
- /* If directory exists open. If directory doesn't
- * exist create. */
-
- /* Note: in order to return whether the directory was
- * opened or created, we first try to open and then try
- * to create. */
- create_flags = 0;
- info = FILE_WAS_OPENED;
- break;
- case FILE_SUPERSEDE:
- case FILE_OVERWRITE:
- case FILE_OVERWRITE_IF:
- default:
- DEBUG(5, ("onefs_open_directory: invalid "
- "create_disposition 0x%x for directory %s\n",
- (unsigned int)create_disposition,
- smb_fname_str_dbg(smb_dname)));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- /*
- * Check for write access to the share. Done in mkdir_internal() in
- * mainline samba.
- */
- if (!CAN_WRITE(conn) && (create_flags & O_CREAT)) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- /* Get parent dirname */
- if (!parent_dirname(talloc_tos(), smb_dname->base_name, &parent_dir,
- NULL)) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
- posix_open = true;
- mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
- file_attributes = 0;
- } else {
- mode = unix_mode(conn, FILE_ATTRIBUTE_DIRECTORY, smb_dname, parent_dir);
- }
-
- /*
- * The NONINDEXED and COMPRESSED bits seem to always be cleared on
- * directories, no matter if you specify that they should be set.
- */
- file_attributes &=
- ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED);
-
- status = file_new(req, conn, &fsp);
- if(!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- /*
- * Actual open with retry magic to handle FILE_OPEN_IF which is
- * unique because the kernel won't tell us if the file was opened or
- * created.
- */
- retry_open:
- fsp->fh->fd = onefs_sys_create_file(conn,
- -1,
- smb_dname->base_name,
- access_mask,
- access_mask,
- share_access,
- create_options,
- create_flags | O_DIRECTORY,
- mode,
- 0,
- 0,
- sd,
- file_attributes,
- NULL);
-
- if (fsp->fh->fd == -1) {
- DEBUG(3, ("Error opening %s. Errno=%d (%s).\n",
- smb_fname_str_dbg(smb_dname), errno,
- strerror(errno)));
- SMB_ASSERT(errno != EINPROGRESS);
-
- if (create_disposition == FILE_OPEN_IF) {
- if (errno == ENOENT) {
- /* Try again, creating it this time. */
- create_flags = O_CREAT | O_EXCL;
- info = FILE_WAS_CREATED;
- goto retry_open;
- } else if (errno == EEXIST) {
- /* Uggh. Try again again. */
- create_flags = 0;
- info = FILE_WAS_OPENED;
- goto retry_open;
- }
- }
-
- /* Error cases below: */
- file_free(req, fsp);
-
- if ((errno == ENOENT) && (create_disposition == FILE_OPEN)) {
- DEBUG(5, ("onefs_open_directory: FILE_OPEN requested "
- "for directory %s and it doesn't "
- "exist.\n", smb_fname_str_dbg(smb_dname)));
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- } else if ((errno == EEXIST) &&
- (create_disposition == FILE_CREATE)) {
- DEBUG(5, ("onefs_open_directory: FILE_CREATE "
- "requested for directory %s and it "
- "already exists.\n",
- smb_fname_str_dbg(smb_dname)));
- return NT_STATUS_OBJECT_NAME_COLLISION;
- } else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
- /* Catch sharing violations. */
- return NT_STATUS_SHARING_VIOLATION;
- }
-
- return map_nt_error_from_unix(errno);
- }
-
- if (info == FILE_WAS_CREATED) {
-
- /* Pulled from mkdir_internal() */
- if (SMB_VFS_LSTAT(conn, smb_dname) == -1) {
- DEBUG(2, ("Could not stat directory '%s' just "
- "created: %s\n",
- smb_fname_str_dbg(smb_dname),
- strerror(errno)));
- return map_nt_error_from_unix(errno);
- }
-
- if (!S_ISDIR(smb_dname->st.st_ex_mode)) {
- DEBUG(0, ("Directory just '%s' created is not a "
- "directory\n",
- smb_fname_str_dbg(smb_dname)));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- if (!posix_open) {
- /*
- * Check if high bits should have been set, then (if
- * bits are missing): add them. Consider bits
- * automagically set by UNIX, i.e. SGID bit from
- * parent dir.
- */
- if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
- (mode & ~smb_dname->st.st_ex_mode)) {
- SMB_VFS_CHMOD(conn, smb_dname->base_name,
- (smb_dname->st.st_ex_mode |
- (mode & ~smb_dname->st.st_ex_mode)));
- }
- }
-
- /* Change the owner if required. */
- if (lp_inherit_owner(SNUM(conn))) {
- change_dir_owner_to_parent(conn, parent_dir,
- smb_dname->base_name,
- &smb_dname->st);
- }
-
- notify_fname(conn, NOTIFY_ACTION_ADDED,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- smb_dname->base_name);
- }
-
- /* Stat the fd for Samba bookkeeping. */
- if(SMB_VFS_FSTAT(fsp, &smb_dname->st) != 0) {
- fd_close(fsp);
- file_free(req, fsp);
- return map_nt_error_from_unix(errno);
- }
-
- /* Setup the files_struct for it. */
- fsp->mode = smb_dname->st.st_ex_mode;
- fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_dname->st);
- fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
- fsp->file_pid = req ? req->smbpid : 0;
- fsp->can_lock = False;
- fsp->can_read = False;
- fsp->can_write = False;
-
- fsp->share_access = share_access;
- fsp->fh->private_options = 0;
- /*
- * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted,
- */
- fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES;
- fsp->print_file = NULL;
- fsp->modified = False;
- fsp->oplock_type = NO_OPLOCK;
- fsp->sent_oplock_break = NO_BREAK_SENT;
- fsp->is_directory = True;
- fsp->posix_open = posix_open;
-
- status = fsp_set_smb_fname(fsp, smb_dname);
- if (!NT_STATUS_IS_OK(status)) {
- fd_close(fsp);
- file_free(req, fsp);
- return status;
- }
-
- mtimespec = smb_dname->st.st_ex_mtime;
-
- /*
- * Still set the samba share mode lock for correct delete-on-close
- * semantics and to make smbstatus more useful.
- */
- lck = get_share_mode_lock(talloc_tos(), fsp->file_id,
- conn->connectpath, smb_dname, &mtimespec);
-
- if (lck == NULL) {
- DEBUG(0, ("onefs_open_directory: Could not get share mode "
- "lock for %s\n", smb_fname_str_dbg(smb_dname)));
- fd_close(fsp);
- file_free(req, fsp);
- return NT_STATUS_SHARING_VIOLATION;
- }
-
- if (lck->delete_on_close) {
- TALLOC_FREE(lck);
- fd_close(fsp);
- file_free(req, fsp);
- return NT_STATUS_DELETE_PENDING;
- }
-
- set_share_mode(lck, fsp, get_current_uid(conn),
- req ? req->mid : 0, NO_OPLOCK);
-
- /*
- * For directories the delete on close bit at open time seems
- * always to be honored on close... See test 19 in Samba4 BASE-DELETE.
- */
- if (create_options & FILE_DELETE_ON_CLOSE) {
- status = can_set_delete_on_close(fsp, 0);
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
- TALLOC_FREE(lck);
- fd_close(fsp);
- file_free(req, fsp);
- return status;
- }
-
- if (NT_STATUS_IS_OK(status)) {
- /* Note that here we set the *inital* delete on close flag,
- not the regular one. The magic gets handled in close. */
- fsp->initial_delete_on_close = True;
- }
- }
-
- TALLOC_FREE(lck);
-
- if (pinfo) {
- *pinfo = info;
- }
-
- *result = fsp;
- return NT_STATUS_OK;
-}
-
-/*
- * Wrapper around onefs_open_file_ntcreate and onefs_open_directory.
- */
-static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
- struct smb_request *req,
- struct smb_filename *smb_fname,
- uint32_t access_mask,
- uint32_t share_access,
- uint32_t create_disposition,
- uint32_t create_options,
- uint32_t file_attributes,
- uint32_t oplock_request,
- uint64_t allocation_size,
- uint32_t private_flags,
- struct security_descriptor *sd,
- struct ea_list *ea_list,
- files_struct **result,
- int *pinfo,
- struct onefs_fsp_data *fsp_data)
-{
- int info = FILE_WAS_OPENED;
- files_struct *base_fsp = NULL;
- files_struct *fsp = NULL;
- NTSTATUS status;
-
- DEBUG(10,("onefs_create_file_unixpath: access_mask = 0x%x "
- "file_attributes = 0x%x, share_access = 0x%x, "
- "create_disposition = 0x%x create_options = 0x%x "
- "oplock_request = 0x%x private_flags = 0x%x "
- "ea_list = 0x%p, sd = 0x%p, "
- "fname = %s\n",
- (unsigned int)access_mask,
- (unsigned int)file_attributes,
- (unsigned int)share_access,
- (unsigned int)create_disposition,
- (unsigned int)create_options,
- (unsigned int)oplock_request,
- (unsigned int)private_flags,
- ea_list, sd, smb_fname_str_dbg(smb_fname)));
-
- if (create_options & FILE_OPEN_BY_FILE_ID) {
- status = NT_STATUS_NOT_SUPPORTED;
- goto fail;
- }
-
- if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
- status = NT_STATUS_INVALID_PARAMETER;
- goto fail;
- }
-
- if (req == NULL) {
- SMB_ASSERT((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) ==
- NO_OPLOCK);
- oplock_request |= INTERNAL_OPEN_ONLY;
- }
-
- if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE,
- PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) {
- access_mask &= ~SYSTEM_SECURITY_ACCESS;
- }
-
- if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
- && (access_mask & DELETE_ACCESS)
- && !is_ntfs_stream_smb_fname(smb_fname)) {
- /*
- * We can't open a file with DELETE access if any of the
- * streams is open without FILE_SHARE_DELETE
- */
- status = open_streams_for_delete(conn, smb_fname->base_name);
-
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- }
-
- if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
- && is_ntfs_stream_smb_fname(smb_fname)) {
- uint32 base_create_disposition;
- struct smb_filename *smb_fname_base = NULL;
-
- if (create_options & FILE_DIRECTORY_FILE) {
- status = NT_STATUS_NOT_A_DIRECTORY;
- goto fail;
- }
-
- switch (create_disposition) {
- case FILE_OPEN:
- base_create_disposition = FILE_OPEN;
- break;
- default:
- base_create_disposition = FILE_OPEN_IF;
- break;
- }
-
- /* Create an smb_filename with stream_name == NULL. */
- status = create_synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- NULL, NULL,
- &smb_fname_base);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
-
- if (SMB_VFS_STAT(conn, smb_fname_base) == -1) {
- DEBUG(10, ("Unable to stat stream: %s\n",
- smb_fname_str_dbg(smb_fname_base)));
- }
-
- status = onefs_create_file_unixpath(
- conn, /* conn */
- NULL, /* req */
- smb_fname_base, /* fname */
- SYNCHRONIZE_ACCESS, /* access_mask */
- (FILE_SHARE_READ |
- FILE_SHARE_WRITE |
- FILE_SHARE_DELETE), /* share_access */
- base_create_disposition, /* create_disposition*/
- 0, /* create_options */
- file_attributes, /* file_attributes */
- NO_OPLOCK, /* oplock_request */
- 0, /* allocation_size */
- 0, /* private_flags */
- NULL, /* sd */
- NULL, /* ea_list */
- &base_fsp, /* result */
- NULL, /* pinfo */
- NULL); /* fsp_data */
-
- TALLOC_FREE(smb_fname_base);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("onefs_create_file_unixpath for base %s "
- "failed: %s\n", smb_fname->base_name,
- nt_errstr(status)));
- goto fail;
- }
-
- /*
- * Testing against windows xp/2003/vista shows that oplocks
- * can actually be requested and granted on streams (see the
- * RAW-OPLOCK-STREAM1 smbtorture test).
- */
- if ((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) !=
- NO_OPLOCK) {
- DEBUG(5, ("Oplock(%d) being requested on a stream! "
- "Ignoring oplock request: fname=%s\n",
- oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK,
- smb_fname_str_dbg(smb_fname)));
- /* Request NO_OPLOCK instead. */
- oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK;
- }
- }
-
- /* Covert generic bits in the security descriptor. */
- if (sd != NULL) {
- security_acl_map_generic(sd->dacl, &file_generic_mapping);
- security_acl_map_generic(sd->sacl, &file_generic_mapping);
- }
-
- /*
- * If it's a request for a directory open, deal with it separately.
- */
-
- if (create_options & FILE_DIRECTORY_FILE) {
-
- if (create_options & FILE_NON_DIRECTORY_FILE) {
- status = NT_STATUS_INVALID_PARAMETER;
- goto fail;
- }
-
- /* Can't open a temp directory. IFS kit test. */
- if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) &&
- (file_attributes & FILE_ATTRIBUTE_TEMPORARY)) {
- status = NT_STATUS_INVALID_PARAMETER;
- goto fail;
- }
-
- /*
- * We will get a create directory here if the Win32
- * app specified a security descriptor in the
- * CreateDirectory() call.
- */
-
- status = onefs_open_directory(
- conn, /* conn */
- req, /* req */
- smb_fname, /* fname */
- access_mask, /* access_mask */
- share_access, /* share_access */
- create_disposition, /* create_disposition*/
- create_options, /* create_options */
- file_attributes, /* file_attributes */
- sd, /* sd */
- &fsp, /* result */
- &info); /* pinfo */
- } else {
-
- /*
- * Ordinary file case.
- */
-
- status = file_new(req, conn, &fsp);
- if(!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
-
- /*
- * We're opening the stream element of a base_fsp
- * we already opened. Set up the base_fsp pointer.
- */
- if (base_fsp) {
- fsp->base_fsp = base_fsp;
- }
-
- status = onefs_open_file_ntcreate(
- conn, /* conn */
- req, /* req */
- smb_fname, /* fname */
- access_mask, /* access_mask */
- share_access, /* share_access */
- create_disposition, /* create_disposition*/
- create_options, /* create_options */
- file_attributes, /* file_attributes */
- oplock_request, /* oplock_request */
- sd, /* sd */
- fsp, /* result */
- &info, /* pinfo */
- fsp_data); /* fsp_data */
-
- if(!NT_STATUS_IS_OK(status)) {
- file_free(req, fsp);
- fsp = NULL;
- }
-
- if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
-
- /* A stream open never opens a directory */
-
- if (base_fsp) {
- status = NT_STATUS_FILE_IS_A_DIRECTORY;
- goto fail;
- }
-
- /*
- * Fail the open if it was explicitly a non-directory
- * file.
- */
-
- if (create_options & FILE_NON_DIRECTORY_FILE) {
- status = NT_STATUS_FILE_IS_A_DIRECTORY;
- goto fail;
- }
-
- create_options |= FILE_DIRECTORY_FILE;
-
- status = onefs_open_directory(
- conn, /* conn */
- req, /* req */
- smb_fname, /* fname */
- access_mask, /* access_mask */
- share_access, /* share_access */
- create_disposition, /* create_disposition*/
- create_options, /* create_options */
- file_attributes, /* file_attributes */
- sd, /* sd */
- &fsp, /* result */
- &info); /* pinfo */
- }
- }
-
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
-
- fsp->base_fsp = base_fsp;
-
- SMB_ASSERT(fsp);
-
- if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) {
- status = set_ea(conn, fsp, smb_fname, ea_list);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- }
-
- if (!fsp->is_directory && S_ISDIR(smb_fname->st.st_ex_mode)) {
- status = NT_STATUS_ACCESS_DENIED;
- goto fail;
- }
-
- /* Save the requested allocation size. */
- if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
- if (allocation_size
- && (allocation_size > smb_fname->st.st_ex_size)) {
- fsp->initial_allocation_size = smb_roundup(
- fsp->conn, allocation_size);
- if (fsp->is_directory) {
- /* Can't set allocation size on a directory. */
- status = NT_STATUS_ACCESS_DENIED;
- goto fail;
- }
- if (vfs_allocate_file_space(
- fsp, fsp->initial_allocation_size) == -1) {
- status = NT_STATUS_DISK_FULL;
- goto fail;
- }
- } else {
- fsp->initial_allocation_size = smb_roundup(
- fsp->conn, (uint64_t)smb_fname->st.st_ex_size);
- }
- }
-
- DEBUG(10, ("onefs_create_file_unixpath: info=%d\n", info));
-
- *result = fsp;
- if (pinfo != NULL) {
- *pinfo = info;
- }
- if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
- SMB_VFS_FSTAT(fsp, &smb_fname->st);
- }
- return NT_STATUS_OK;
-
- fail:
- DEBUG(10, ("onefs_create_file_unixpath: %s\n", nt_errstr(status)));
-
- if (fsp != NULL) {
- if (base_fsp && fsp->base_fsp == base_fsp) {
- /*
- * The close_file below will close
- * fsp->base_fsp.
- */
- base_fsp = NULL;
- }
- close_file(req, fsp, ERROR_CLOSE);
- fsp = NULL;
- }
- if (base_fsp != NULL) {
- close_file(req, base_fsp, ERROR_CLOSE);
- base_fsp = NULL;
- }
- return status;
-}
-
-static void destroy_onefs_fsp_data(void *p_data)
-{
- struct onefs_fsp_data *fsp_data = (struct onefs_fsp_data *)p_data;
-
- destroy_onefs_callback_record(fsp_data->oplock_callback_id);
-}
-
-/**
- * SMB_VFS_CREATE_FILE interface to onefs.
- */
-NTSTATUS onefs_create_file(vfs_handle_struct *handle,
- struct smb_request *req,
- uint16_t root_dir_fid,
- struct smb_filename *smb_fname,
- uint32_t access_mask,
- uint32_t share_access,
- uint32_t create_disposition,
- uint32_t create_options,
- uint32_t file_attributes,
- uint32_t oplock_request,
- uint64_t allocation_size,
- uint32_t private_flags,
- struct security_descriptor *sd,
- struct ea_list *ea_list,
- files_struct **result,
- int *pinfo)
-{
- connection_struct *conn = handle->conn;
- struct onefs_fsp_data fsp_data = {};
- int info = FILE_WAS_OPENED;
- files_struct *fsp = NULL;
- NTSTATUS status;
-
- DEBUG(10,("onefs_create_file: access_mask = 0x%x "
- "file_attributes = 0x%x, share_access = 0x%x, "
- "create_disposition = 0x%x create_options = 0x%x "
- "oplock_request = 0x%x private_flags = 0x%x"
- "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, "
- "fname = %s\n",
- (unsigned int)access_mask,
- (unsigned int)file_attributes,
- (unsigned int)share_access,
- (unsigned int)create_disposition,
- (unsigned int)create_options,
- (unsigned int)oplock_request,
- (unsigned int)private_flags,
- (unsigned int)root_dir_fid,
- ea_list, sd, smb_fname_str_dbg(smb_fname)));
-
- /* Get the file name if root_dir_fid was specified. */
- if (root_dir_fid != 0) {
- struct smb_filename *smb_fname_out = NULL;
- status = get_relative_fid_filename(conn, req, root_dir_fid,
- smb_fname, &smb_fname_out);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- smb_fname = smb_fname_out;
- }
-
- /* All file access must go through check_name() */
- status = check_name(conn, smb_fname->base_name);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
-
- if (is_ntfs_stream_smb_fname(smb_fname)) {
- if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) {
- status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- goto fail;
- }
-
- if (is_ntfs_default_stream_smb_fname(smb_fname)) {
- int ret;
- smb_fname->stream_name = NULL;
- /* We have to handle this error here. */
- if (create_options & FILE_DIRECTORY_FILE) {
- status = NT_STATUS_NOT_A_DIRECTORY;
- goto fail;
- }
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LSTAT(conn, smb_fname);
- } else {
- ret = SMB_VFS_STAT(conn, smb_fname);
- }
-
- if (ret == 0 && VALID_STAT_OF_DIR(smb_fname->st)) {
- status = NT_STATUS_FILE_IS_A_DIRECTORY;
- goto fail;
- }
- }
- }
-
- status = onefs_create_file_unixpath(
- conn, /* conn */
- req, /* req */
- smb_fname, /* fname */
- access_mask, /* access_mask */
- share_access, /* share_access */
- create_disposition, /* create_disposition*/
- create_options, /* create_options */
- file_attributes, /* file_attributes */
- oplock_request, /* oplock_request */
- allocation_size, /* allocation_size */
- private_flags,
- sd, /* sd */
- ea_list, /* ea_list */
- &fsp, /* result */
- &info, /* pinfo */
- &fsp_data); /* psbuf */
-
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
-
- DEBUG(10, ("onefs_create_file: info=%d\n", info));
-
- /*
- * Setup private onefs_fsp_data. Currently the private data struct is
- * only used to store the oplock_callback_id so that when the file is
- * closed, the onefs_callback_record can be properly cleaned up in the
- * oplock_onefs sub-system.
- */
- if (fsp) {
- struct onefs_fsp_data *fsp_data_tmp = NULL;
- fsp_data_tmp = (struct onefs_fsp_data *)
- VFS_ADD_FSP_EXTENSION(handle, fsp, struct onefs_fsp_data,
- &destroy_onefs_fsp_data);
-
- if (fsp_data_tmp == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- *fsp_data_tmp = fsp_data;
- }
-
- *result = fsp;
- if (pinfo != NULL) {
- *pinfo = info;
- }
- return NT_STATUS_OK;
-
- fail:
- DEBUG(10, ("onefs_create_file: %s\n", nt_errstr(status)));
-
- if (fsp != NULL) {
- close_file(req, fsp, ERROR_CLOSE);
- fsp = NULL;
- }
- return status;
-}