Merge branch 'master' of ssh://git.samba.org/data/git/abartlet/samba into extended...
[abartlet/samba.git/.git] / source3 / modules / onefs_open.c
diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c
new file mode 100644 (file)
index 0000000..d0310d0
--- /dev/null
@@ -0,0 +1,2153 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * This file began with some code from source3/smbd/open.c and modified it to
+ * 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 "onefs.h"
+
+extern const struct generic_mapping file_generic_mapping;
+extern bool global_client_failed_oplock_break;
+
+struct deferred_open_record {
+       bool delayed_for_oplocks;
+       bool failed; /* added for onefs_oplocks */
+       struct file_id id;
+};
+
+static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
+                             struct smb_request *req,
+                             const char *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,
+                             struct security_descriptor *sd,
+                             struct ea_list *ea_list,
+
+                             files_struct **result,
+                             int *pinfo,
+                             SMB_STRUCT_STAT *psbuf);
+
+/****************************************************************************
+ Open a file.
+****************************************************************************/
+
+static NTSTATUS onefs_open_file(files_struct *fsp,
+                               connection_struct *conn,
+                               struct smb_request *req,
+                               const char *parent_dir,
+                               const char *name,
+                               const char *path,
+                               SMB_STRUCT_STAT *psbuf,
+                               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)
+{
+       NTSTATUS status = NT_STATUS_OK;
+       int accmode = (flags & O_ACCMODE);
+       int local_flags = flags;
+       bool file_existed = VALID_STAT(*psbuf);
+       const char *wild;
+
+       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", path));
+                       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", path));
+               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(psbuf->st_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;
+       } else {
+               wild = path;
+       }
+       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",
+                         path));
+               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
+       /* Don't request an oplock if oplocks are turned off for the
+        * share. */
+       if (!lp_oplocks(SNUM(conn)))
+               oplock_request = 0;
+
+       fsp->fh->fd = onefs_sys_create_file(conn,
+                                           -1,
+                                           path,
+                                           access_mask,
+                                           open_access_mask,
+                                           share_access,
+                                           create_options,
+                                           flags,
+                                           unx_mode,
+                                           oplock_request,
+                                           id,
+                                           sd,
+                                           new_dos_attributes,
+                                           granted_oplock);
+
+       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",
+                         path,nt_errstr(status),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, path,
+                           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, path);
+       }
+
+       if (!file_existed) {
+               int ret;
+
+               if (fsp->fh->fd == -1) {
+                       ret = SMB_VFS_STAT(conn, path, psbuf);
+               } else {
+                       ret = SMB_VFS_FSTAT(fsp, psbuf);
+                       /* If we have an fd, this stat should succeed. */
+                       if (ret == -1) {
+                               DEBUG(0,("Error doing fstat on open file %s "
+                                        "(%s)\n", path,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(psbuf->st_mode)) {
+               fd_close(fsp);
+               errno = EISDIR;
+               return NT_STATUS_FILE_IS_A_DIRECTORY;
+       }
+
+       fsp->mode = psbuf->st_mode;
+       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+       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 = False;
+       fsp->modified = False;
+       fsp->sent_oplock_break = NO_BREAK_SENT;
+       fsp->is_directory = False;
+       if (conn->aio_write_behind_list &&
+           is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) {
+               fsp->aio_write_behind = True;
+       }
+
+       string_set(&fsp->fsp_name, path);
+       fsp->wcp = NULL; /* Write cache pointer. */
+
+       DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
+                conn->server_info->unix_name,
+                fsp->fsp_name,
+                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=%d, exiting\n", 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 %u\n",
+                 (unsigned int)request_time.tv_sec,
+                 (unsigned int)request_time.tv_usec,
+                 (unsigned int)req->mid));
+
+       if (!push_deferred_smb_message(req, request_time, timeout,
+                                      (char *)state, sizeof(*state))) {
+               exit_server("push_deferred_smb_message failed");
+       }
+       add_deferred_open(lck, req->mid, request_time, state->id);
+
+       /*
+        * Push the MID of this packet on the signing queue.
+        * We only do this once, the first time we push the packet
+        * onto the deferred open queue, as this has a side effect
+        * of incrementing the response sequence number.
+        */
+
+       srv_defer_sign_response(req->mid);
+}
+
+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. */
+
+       timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 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);
+       }
+}
+
+/****************************************************************************
+ 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,
+                                 const char *fname,
+                                 uint32 access_mask,
+                                 uint32 share_access,
+                                 uint32 create_disposition,
+                                 uint32 create_options,
+                                 uint32 new_dos_attributes,
+                                 int oplock_request,
+                                 struct security_descriptor *sd,
+                                 files_struct *fsp,
+                                 int *pinfo,
+                                 SMB_STRUCT_STAT *psbuf)
+{
+       int flags=0;
+       int flags2=0;
+       bool file_existed = VALID_STAT(*psbuf);
+       bool def_acl = False;
+       bool posix_open = False;
+       bool new_file_created = 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 pending_message_list *pml = NULL;
+       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;
+       const char *newname;
+       int granted_oplock;
+       uint64 oplock_waiter;
+       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",
+                         fname));
+
+               return print_fsp_open(req, conn, fname, req->vuid, fsp);
+       }
+
+       if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir,
+                                  &newname)) {
+               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 aARCH to this as this mode is only used if the file is
+                * created new. */
+               unx_mode = unix_mode(conn, new_dos_attributes | aARCH, 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",
+                 fname, new_dos_attributes, access_mask, share_access,
+                 create_disposition, create_options, unx_mode,
+                 oplock_request));
+
+       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 != NULL)
+           && ((pml = get_open_deferred_message(req->mid)) != NULL)) {
+               struct deferred_open_record *state =
+                       (struct deferred_open_record *)pml->private_data.data;
+
+               /* Remember the absolute time of the original
+                  request with this mid. We'll use it later to
+                  see if this has timed out. */
+
+               request_time = pml->request_time;
+
+               /* Remove the deferred open entry under lock. */
+               lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL,
+                                         NULL);
+               if (lck == NULL) {
+                       DEBUG(0, ("could not get share mode lock\n"));
+               } else {
+                       del_deferred_open_entry(lck, req->mid);
+                       TALLOC_FREE(lck);
+               }
+
+               /* Ensure we don't reprocess this message. */
+               remove_deferred_open_smb_message(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, fname);
+       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, fname, psbuf);
+               }
+       }
+
+       /* Setup dos_attributes to be set by ifs_createfile */
+       if (lp_store_dos_attributes(SNUM(conn))) {
+               createfile_attributes = (new_dos_attributes | aARCH) &
+                   ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED);
+       }
+
+       /* Ignore oplock requests if oplocks are disabled. */
+       if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break ||
+           IS_VETO_OPLOCK_PATH(conn, fname)) {
+               /* 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(fname,".+,;=[].")) {
+               /* 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:
+                       /* If file exists replace/overwrite. If file doesn't
+                        * exist create. */
+                       /**
+                        * @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);
+                       break;
+
+               case FILE_OVERWRITE_IF:
+                       /* If file exists replace/overwrite. If file doesn't
+                        * exist create. */
+                       flags2 |= (O_CREAT | O_TRUNC);
+                       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", 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",
+                                         fname));
+                               errno = ENOENT;
+                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       }
+                       flags2 |= O_TRUNC;
+                       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",
+                                         fname));
+                               if (S_ISDIR(psbuf->st_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, fname,
+                                          existing_dos_attributes,
+                                          new_dos_attributes, psbuf->st_mode,
+                                          unx_mode, &new_unx_mode)) {
+                       DEBUG(5, ("onefs_open_file_ntcreate: attributes "
+                                 "missmatch for file %s (%x %x) (0%o, 0%o)\n",
+                                 fname, existing_dos_attributes,
+                                 new_dos_attributes,
+                                 (unsigned int)psbuf->st_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",
+                  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);
+
+               /**
+                * XXX: TODO
+                * Apparently this is necessary because we ship with
+                * lp_acl_check_permissions = no.  It is set to no because our
+                * ifs_createfile does the access check correctly.  This check
+                * was added in the last merge, and the question is why is it
+                * necessary?  Check out Bug 25547 and Bug 14596.  The key is
+                * to figure out what case this is covering, and do some
+                * testing to see if it's actually necessary.  If it is, maybe
+                * it should go upstream in open.c.
+                */
+               if (!lp_acl_check_permissions(SNUM(conn)) &&
+                   (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",
+                         fname, !CAN_WRITE(conn) ? "share" : "file" ));
+               errno = EACCES;
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       DEBUG(10, ("fsp = %p\n", fsp));
+
+       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+       fsp->share_access = share_access;
+       fsp->fh->private_options = create_options;
+       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 = get_mtimespec(psbuf);
+               id = vfs_file_id_from_sbuf(conn, psbuf);
+
+               lck = get_share_mode_lock(talloc_tos(), id,
+                                         conn->connectpath,
+                                         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));
+
+       oplock_waiter = 1; //ifs_oplock_wait_record(mid);
+
+       if (oplock_waiter == 0) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* Do the open. */
+       status = onefs_open_file(fsp,
+                                conn,
+                                req,
+                                parent_dir,
+                                newname,
+                                fname,
+                                psbuf,
+                                flags|flags2,
+                                unx_mode,
+                                access_mask,
+                                open_access_mask,
+                                fsp->oplock_type,
+                                oplock_waiter,
+                                share_access,
+                                create_options,
+                                createfile_attributes,
+                                sd,
+                                &granted_oplock);
+
+       if (!NT_STATUS_IS_OK(status)) {
+
+               /* OneFS Oplock Handling */
+               if (errno == EINPROGRESS) {
+
+                       if (lck == NULL) {
+
+                               struct deferred_open_record state;
+                               struct timespec old_write_time;
+
+                               old_write_time = get_mtimespec(psbuf);
+
+                               DEBUG(3, ("Someone created file %s with an "
+                                         "oplock after we looked: Retrying\n",
+                                         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, psbuf);
+                               if (!(lck = get_share_mode_lock(talloc_tos(),
+                                         id, conn->connectpath, fname,
+                                         &old_write_time))) {
+                                       /*
+                                        * Emergency exit
+                                        */
+                                       DEBUG(0, ("onefs_open_file_ntcreate: "
+                                                 "Could not get share mode "
+                                                 "lock for %s\n", fname));
+                                       status = NT_STATUS_SHARING_VIOLATION;
+                                       goto cleanup_destroy;
+                               }
+
+                               state.delayed_for_oplocks = False;
+                               state.id = id;
+
+                               if (req != NULL) {
+                                       defer_open(lck, request_time,
+                                           timeval_zero(), req, &state);
+                               }
+                               goto cleanup_destroy;
+                       }
+                       /* Waiting for an oplock */
+                       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;
+
+                       /* Check if this can be done with the deny_dos and fcb
+                        * calls. */
+
+                       /* Try to find dup fsp if possible. */
+                       if (create_options &
+                           (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,
+                                                       fname,
+                                                       id,
+                                                       req->smbpid,
+                                                       req->vuid,
+                                                       access_mask,
+                                                       share_access,
+                                                       create_options);
+
+                               if (NT_STATUS_IS_OK(status)) {
+                                       TALLOC_FREE(lck);
+                                       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)) ||
+                           !can_access_file_data(conn,fname,psbuf,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;
+
+                               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:
+               //destroy_ifs_callback_record(oplock_waiter);
+        cleanup:
+               TALLOC_FREE(lck);
+               return status;
+       }
+
+       fsp->oplock_type = granted_oplock;
+
+       /* XXX uncomment for oplocks */
+       //ifs_set_oplock_callback(oplock_waiter, fsp);
+       //fsp->oplock_callback_id = oplock_waiter;
+
+       if (!file_existed) {
+               struct timespec old_write_time = get_mtimespec(psbuf);
+               /*
+                * 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->dev and fsp->inode are 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,
+                                         fname, &old_write_time);
+
+               if (lck == NULL) {
+                       DEBUG(0, ("onefs_open_file_ntcreate: Could not get "
+                                 "share mode lock for %s\n", 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);
+
+       /* 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);
+               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.
+        */
+
+       /* Record the options we were opened with. */
+       fsp->share_access = share_access;
+       fsp->fh->private_options = create_options;
+       /*
+        * 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 (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
+           info == FILE_WAS_SUPERSEDED) {
+               new_file_created = True;
+       }
+
+       set_share_mode(lck, fsp, conn->server_info->utok.uid, 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, True, 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(*psbuf)
+                 && (psbuf->st_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",
+                                         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",
+                                 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,
+                                    const char *fname,
+                                    uint32 access_mask,
+                                    uint32 share_access,
+                                    uint32 create_disposition,
+                                    uint32 create_options,
+                                    uint32 file_attributes,
+                                    struct security_descriptor *sd,
+                                    files_struct **result,
+                                    int *pinfo,
+                                    SMB_STRUCT_STAT *psbuf)
+{
+       files_struct *fsp = NULL;
+       struct share_mode_lock *lck = NULL;
+       NTSTATUS status;
+       struct timespec mtimespec;
+       int info = 0;
+       char *parent_dir;
+       const char *dirname;
+       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",
+                 fname, (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_name(fname)) {
+               DEBUG(2, ("onefs_open_directory: %s is a stream name!\n", fname));
+               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, fname));
+                       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(talloc_tos(), fname, &parent_dir,
+                                  &dirname)) {
+               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, aDIR, fname, 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,
+                                           fname,
+                                           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", fname, 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", fname ));
+                       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", fname ));
+                       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, fname, psbuf) == -1) {
+                       DEBUG(2, ("Could not stat directory '%s' just "
+                                 "created: %s\n",fname, strerror(errno)));
+                       return map_nt_error_from_unix(errno);
+               }
+
+               if (!S_ISDIR(psbuf->st_mode)) {
+                       DEBUG(0, ("Directory just '%s' created is not a "
+                                 "directory\n", fname));
+                       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 & ~psbuf->st_mode)) {
+                               SMB_VFS_CHMOD(conn, fname, (psbuf->st_mode |
+                                                 (mode & ~psbuf->st_mode)));
+                       }
+               }
+
+               /* Change the owner if required. */
+               if (lp_inherit_owner(SNUM(conn))) {
+                       change_dir_owner_to_parent(conn, parent_dir, fname,
+                                                  psbuf);
+               }
+
+               notify_fname(conn, NOTIFY_ACTION_ADDED,
+                            FILE_NOTIFY_CHANGE_DIR_NAME, fname);
+       }
+
+       /* Stat the fd for Samba bookkeeping. */
+       if(SMB_VFS_FSTAT(fsp, psbuf) != 0) {
+               fd_close(fsp);
+               file_free(req, fsp);
+               return map_nt_error_from_unix(errno);
+       }
+
+       /* Setup the files_struct for it. */
+       fsp->mode = psbuf->st_mode;
+       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+       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 = create_options;
+       /*
+        * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted,
+        */
+       fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES;
+       fsp->print_file = False;
+       fsp->modified = False;
+       fsp->oplock_type = NO_OPLOCK;
+       fsp->sent_oplock_break = NO_BREAK_SENT;
+       fsp->is_directory = True;
+       fsp->posix_open = posix_open;
+
+       string_set(&fsp->fsp_name,fname);
+
+       mtimespec = get_mtimespec(psbuf);
+
+       /*
+        * 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,
+                                 fname, &mtimespec);
+
+       if (lck == NULL) {
+               DEBUG(0, ("onefs_open_directory: Could not get share mode "
+                         "lock for %s\n", fname));
+               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, conn->server_info->utok.uid, 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, True, 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;
+}
+
+/*
+ * If a main file is opened for delete, all streams need to be checked for
+ * !FILE_SHARE_DELETE. Do this by opening with DELETE_ACCESS.
+ * If that works, delete them all by setting the delete on close and close.
+ */
+
+static NTSTATUS open_streams_for_delete(connection_struct *conn,
+                                       const char *fname)
+{
+       struct stream_struct *stream_info;
+       files_struct **streams;
+       int i;
+       unsigned int num_streams;
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status;
+
+       status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
+                                   &num_streams, &stream_info);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
+           || NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               DEBUG(10, ("no streams around\n"));
+               TALLOC_FREE(frame);
+               return NT_STATUS_OK;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
+                          nt_errstr(status)));
+               goto fail;
+       }
+
+       DEBUG(10, ("open_streams_for_delete found %d streams\n",
+                  num_streams));
+
+       if (num_streams == 0) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_OK;
+       }
+
+       streams = TALLOC_ARRAY(talloc_tos(), files_struct *, num_streams);
+       if (streams == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       for (i=0; i<num_streams; i++) {
+               char *streamname;
+
+               if (strequal(stream_info[i].name, "::$DATA")) {
+                       streams[i] = NULL;
+                       continue;
+               }
+
+               streamname = talloc_asprintf(talloc_tos(), "%s%s", fname,
+                                            stream_info[i].name);
+
+               if (streamname == NULL) {
+                       DEBUG(0, ("talloc_aprintf failed\n"));
+                       status = NT_STATUS_NO_MEMORY;
+                       goto fail;
+               }
+
+               status = onefs_create_file_unixpath
+                       (conn,                  /* conn */
+                        NULL,                  /* req */
+                        streamname,            /* fname */
+                        DELETE_ACCESS,         /* access_mask */
+                        FILE_SHARE_READ | FILE_SHARE_WRITE
+                        | FILE_SHARE_DELETE,   /* share_access */
+                        FILE_OPEN,             /* create_disposition*/
+                        NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE, /* create_options */
+                        FILE_ATTRIBUTE_NORMAL, /* file_attributes */
+                        0,                     /* oplock_request */
+                        0,                     /* allocation_size */
+                        NULL,                  /* sd */
+                        NULL,                  /* ea_list */
+                        &streams[i],           /* result */
+                        NULL,                  /* pinfo */
+                        NULL);                 /* psbuf */
+
+               TALLOC_FREE(streamname);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("Could not open stream %s: %s\n",
+                                  streamname, nt_errstr(status)));
+                       break;
+               }
+       }
+
+       /*
+        * don't touch the variable "status" beyond this point :-)
+        */
+
+       for (i -= 1 ; i >= 0; i--) {
+               if (streams[i] == NULL) {
+                       continue;
+               }
+
+               DEBUG(10, ("Closing stream # %d, %s\n", i,
+                          streams[i]->fsp_name));
+               close_file(NULL, streams[i], NORMAL_CLOSE);
+       }
+
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
+/*
+ * Wrapper around onefs_open_file_ntcreate and onefs_open_directory.
+ */
+static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
+                                          struct smb_request *req,
+                                          const char *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,
+                                          struct security_descriptor *sd,
+                                          struct ea_list *ea_list,
+                                          files_struct **result,
+                                          int *pinfo,
+                                          SMB_STRUCT_STAT *psbuf)
+{
+       SMB_STRUCT_STAT sbuf;
+       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 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,
+                 ea_list, sd, 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) {
+               oplock_request |= INTERNAL_OPEN_ONLY;
+       }
+
+       if (psbuf != NULL) {
+               sbuf = *psbuf;
+       }
+       else {
+               if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) {
+                       SET_STAT_INVALID(sbuf);
+               }
+       }
+
+       if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+           && (access_mask & DELETE_ACCESS)
+           && !is_ntfs_stream_name(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, fname);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto fail;
+               }
+       }
+
+       if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+           && is_ntfs_stream_name(fname)
+           && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) {
+               char *base;
+               uint32 base_create_disposition;
+
+               if (create_options & FILE_DIRECTORY_FILE) {
+                       status = NT_STATUS_NOT_A_DIRECTORY;
+                       goto fail;
+               }
+
+               status = split_ntfs_stream_name(talloc_tos(), fname,
+                                               &base, NULL);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("onefs_create_file_unixpath: "
+                                 "split_ntfs_stream_name failed: %s\n",
+                                 nt_errstr(status)));
+                       goto fail;
+               }
+
+               SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */
+
+               switch (create_disposition) {
+               case FILE_OPEN:
+                       base_create_disposition = FILE_OPEN;
+                       break;
+               default:
+                       base_create_disposition = FILE_OPEN_IF;
+                       break;
+               }
+
+               status = onefs_create_file_unixpath(
+                       conn,                           /* conn */
+                       NULL,                           /* req */
+                       base,                           /* fname */
+                       0,                              /* access_mask */
+                       (FILE_SHARE_READ |
+                           FILE_SHARE_WRITE |
+                           FILE_SHARE_DELETE),         /* share_access */
+                       base_create_disposition,        /* create_disposition*/
+                       0,                              /* create_options */
+                       0,                              /* file_attributes */
+                       NO_OPLOCK,                      /* oplock_request */
+                       0,                              /* allocation_size */
+                       NULL,                           /* sd */
+                       NULL,                           /* ea_list */
+                       &base_fsp,                      /* result */
+                       NULL,                           /* pinfo */
+                       NULL);                          /* psbuf */
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("onefs_create_file_unixpath for base %s "
+                                 "failed: %s\n", base, nt_errstr(status)));
+                       goto fail;
+               }
+               /*
+                * we don't need to low level fd: This might conflict with
+                * OneFS streams.
+                */
+               fd_close(base_fsp);
+       }
+
+       /* 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 */
+                       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 */
+                       &sbuf);                         /* psbuf */
+       } 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 */
+                       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 */
+                       &sbuf);                         /* psbuf */
+
+               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 */
+                               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 */
+                               &sbuf);                 /* psbuf */
+               }
+       }
+
+       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, fname, ea_list);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto fail;
+               }
+       }
+
+       if (!fsp->is_directory && S_ISDIR(sbuf.st_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 > sbuf.st_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)sbuf.st_size);
+               }
+       }
+
+       DEBUG(10, ("onefs_create_file_unixpath: info=%d\n", info));
+
+       *result = fsp;
+       if (pinfo != NULL) {
+               *pinfo = info;
+       }
+       if (psbuf != NULL) {
+               if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
+                       *psbuf = sbuf;
+               }
+               else {
+                       SMB_VFS_FSTAT(fsp, psbuf);
+               }
+       }
+       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;
+}
+
+/**
+ * SMB_VFS_CREATE_FILE interface to onefs.
+ */
+NTSTATUS onefs_create_file(vfs_handle_struct *handle,
+                          struct smb_request *req,
+                          uint16_t root_dir_fid,
+                          const char *fname,
+                          uint32_t create_file_flags,
+                          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,
+                          struct security_descriptor *sd,
+                          struct ea_list *ea_list,
+                          files_struct **result,
+                          int *pinfo,
+                          SMB_STRUCT_STAT *psbuf)
+{
+       connection_struct *conn = handle->conn;
+       struct case_semantics_state *case_state = NULL;
+       SMB_STRUCT_STAT sbuf;
+       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 "
+                 "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, "
+                 "create_file_flags = 0x%x, 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)root_dir_fid,
+                 ea_list, sd, create_file_flags, fname));
+
+       /* Get the file name if root_dir_fid was specified. */
+       if (root_dir_fid != 0) {
+               char *new_fname;
+
+               status = get_relative_fid_filename(conn, req, root_dir_fid,
+                                                  fname, &new_fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto fail;
+               }
+
+               fname = new_fname;
+       }
+
+       /* Resolve the file name if this was a DFS pathname. */
+       if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) {
+               char *resolved_fname;
+
+               status = resolve_dfspath(talloc_tos(), conn, true, fname,
+                                        &resolved_fname);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       /*
+                        * For PATH_NOT_COVERED we had
+                        * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+                        *                 ERRSRV, ERRbadpath);
+                        * Need to fix in callers
+                        */
+                       goto fail;
+               }
+               fname = resolved_fname;
+       }
+
+       /* Check if POSIX semantics are wanted. */
+       if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               case_state = set_posix_case_semantics(talloc_tos(), conn);
+       }
+
+       /* Convert dos path to unix path if it hasn't already been done. */
+       if (create_file_flags & CFF_DOS_PATH) {
+               char *converted_fname;
+
+               SET_STAT_INVALID(sbuf);
+
+               status = unix_convert(talloc_tos(), conn, fname, False,
+                                     &converted_fname, NULL, &sbuf);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto fail;
+               }
+               fname = converted_fname;
+       } else {
+               if (psbuf != NULL) {
+                       sbuf = *psbuf;
+               } else {
+                       if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) {
+                               SET_STAT_INVALID(sbuf);
+                       }
+               }
+
+       }
+
+       TALLOC_FREE(case_state);
+
+       /* All file access must go through check_name() */
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       status = onefs_create_file_unixpath(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               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 */
+               sd,                                     /* sd */
+               ea_list,                                /* ea_list */
+               &fsp,                                   /* result */
+               &info,                                  /* pinfo */
+               &sbuf);                                 /* psbuf */
+
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       DEBUG(10, ("onefs_create_file: info=%d\n", info));
+
+       *result = fsp;
+       if (pinfo != NULL) {
+               *pinfo = info;
+       }
+       if (psbuf != NULL) {
+               *psbuf = sbuf;
+       }
+       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;
+}