Remove redundant parameter fd from SMB_VFS_FTRUNCATE().
[samba.git] / source3 / smbd / open.c
index 5cb8340e0e062e602a4965b254ef3bbbc940d968..cc62e020da22c000996247dde46dc009368a743c 100644 (file)
@@ -7,7 +7,7 @@
    
    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 2 of the License, or
+   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,
    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, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
-extern struct generic_mapping file_generic_mapping;
+extern const struct generic_mapping file_generic_mapping;
 extern struct current_user current_user;
 extern userdom_struct current_user_info;
-extern BOOL global_client_failed_oplock_break;
+extern bool global_client_failed_oplock_break;
 
 struct deferred_open_record {
-       BOOL delayed_for_oplocks;
+       bool delayed_for_oplocks;
        struct file_id id;
 };
 
@@ -71,7 +70,7 @@ static NTSTATUS fd_open(struct connection_struct *conn,
  Close the file associated with a fsp.
 ****************************************************************************/
 
-NTSTATUS fd_close(struct connection_struct *conn, files_struct *fsp)
+NTSTATUS fd_close(files_struct *fsp)
 {
        if (fsp->fh->fd == -1) {
                return NT_STATUS_OK; /* What we used to call a stat open. */
@@ -79,7 +78,7 @@ NTSTATUS fd_close(struct connection_struct *conn, files_struct *fsp)
        if (fsp->fh->ref_count > 1) {
                return NT_STATUS_OK; /* Shared handle. Only close last reference. */
        }
-       return fd_close_posix(conn, fsp);
+       return fd_close_posix(fsp);
 }
 
 /****************************************************************************
@@ -103,7 +102,7 @@ static void change_file_owner_to_parent(connection_struct *conn,
        }
 
        become_root();
-       ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, parent_st.st_uid, (gid_t)-1);
+       ret = SMB_VFS_FCHOWN(fsp, parent_st.st_uid, (gid_t)-1);
        unbecome_root();
        if (ret == -1) {
                DEBUG(0,("change_file_owner_to_parent: failed to fchown "
@@ -118,22 +117,26 @@ static void change_file_owner_to_parent(connection_struct *conn,
                  (unsigned int)parent_st.st_uid ));
 }
 
-static void change_dir_owner_to_parent(connection_struct *conn,
+static NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
                                       const char *inherit_from_dir,
                                       const char *fname,
                                       SMB_STRUCT_STAT *psbuf)
 {
-       pstring saved_dir;
+       char *saved_dir = NULL;
        SMB_STRUCT_STAT sbuf;
        SMB_STRUCT_STAT parent_st;
+       TALLOC_CTX *ctx = talloc_stackframe();
+       NTSTATUS status = NT_STATUS_OK;
        int ret;
 
        ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st);
        if (ret == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to stat parent "
                         "directory %s. Error was %s\n",
                         inherit_from_dir, strerror(errno) ));
-               return;
+               TALLOC_FREE(ctx);
+               return status;
        }
 
        /* We've already done an lstat into psbuf, and we know it's a
@@ -143,14 +146,19 @@ static void change_dir_owner_to_parent(connection_struct *conn,
           should work on any UNIX (thanks tridge :-). JRA.
        */
 
-       if (!vfs_GetWd(conn,saved_dir)) {
+       saved_dir = vfs_GetWd(ctx,conn);
+       if (!saved_dir) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to get "
-                        "current working directory\n"));
-               return;
+                        "current working directory. Error was %s\n",
+                        strerror(errno)));
+               TALLOC_FREE(ctx);
+               return status;
        }
 
        /* Chdir into the new path. */
        if (vfs_ChDir(conn, fname) == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to change "
                         "current working directory to %s. Error "
                         "was %s\n", fname, strerror(errno) ));
@@ -158,6 +166,7 @@ static void change_dir_owner_to_parent(connection_struct *conn,
        }
 
        if (SMB_VFS_STAT(conn,".",&sbuf) == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to stat "
                         "directory '.' (%s) Error was %s\n",
                         fname, strerror(errno)));
@@ -171,6 +180,7 @@ static void change_dir_owner_to_parent(connection_struct *conn,
                DEBUG(0,("change_dir_owner_to_parent: "
                         "device/inode/mode on directory %s changed. "
                         "Refusing to chown !\n", fname ));
+               status = NT_STATUS_ACCESS_DENIED;
                goto out;
        }
 
@@ -178,6 +188,7 @@ static void change_dir_owner_to_parent(connection_struct *conn,
        ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1);
        unbecome_root();
        if (ret == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(10,("change_dir_owner_to_parent: failed to chown "
                          "directory %s to parent directory uid %u. "
                          "Error was %s\n", fname,
@@ -191,7 +202,9 @@ static void change_dir_owner_to_parent(connection_struct *conn,
 
  out:
 
+       TALLOC_FREE(ctx);
        vfs_ChDir(conn,saved_dir);
+       return status;
 }
 
 /****************************************************************************
@@ -213,7 +226,7 @@ static NTSTATUS open_file(files_struct *fsp,
        NTSTATUS status = NT_STATUS_OK;
        int accmode = (flags & O_ACCMODE);
        int local_flags = flags;
-       BOOL file_existed = VALID_STAT(*psbuf);
+       bool file_existed = VALID_STAT(*psbuf);
 
        fsp->fh->fd = -1;
        errno = EPERM;
@@ -329,7 +342,7 @@ static NTSTATUS open_file(files_struct *fsp,
                if (fsp->fh->fd == -1) {
                        ret = SMB_VFS_STAT(conn, path, psbuf);
                } else {
-                       ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf);
+                       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 "
@@ -340,7 +353,7 @@ static NTSTATUS open_file(files_struct *fsp,
                /* 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(conn, fsp);
+                       fd_close(fsp);
                        return status;
                }
        }
@@ -352,13 +365,13 @@ static NTSTATUS open_file(files_struct *fsp,
         */
 
        if(S_ISDIR(psbuf->st_mode)) {
-               fd_close(conn, fsp);
+               fd_close(fsp);
                errno = EISDIR;
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
        fsp->mode = psbuf->st_mode;
-       fsp->file_id = file_id_sbuf(psbuf);
+       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;
@@ -374,6 +387,10 @@ static NTSTATUS open_file(files_struct *fsp,
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = False;
        fsp->is_stat = 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. */
@@ -392,7 +409,7 @@ static NTSTATUS open_file(files_struct *fsp,
  Return True if the filename is one of the special executable types.
 ********************************************************************/
 
-static BOOL is_executable(const char *fname)
+static bool is_executable(const char *fname)
 {
        if ((fname = strrchr_m(fname,'.'))) {
                if (strequal(fname,".com") ||
@@ -410,7 +427,7 @@ static BOOL is_executable(const char *fname)
  Returns True if conflict, False if not.
 ****************************************************************************/
 
-static BOOL share_conflict(struct share_mode_entry *entry,
+static bool share_conflict(struct share_mode_entry *entry,
                           uint32 access_mask,
                           uint32 share_access)
 {
@@ -501,9 +518,10 @@ static void validate_my_share_entries(int num,
 
        if (is_deferred_open_entry(share_entry) &&
            !open_was_deferred(share_entry->op_mid)) {
-               pstring str;
-               pstr_sprintf(str, "Got a deferred entry without a request: "
-                            "PANIC: %s\n", share_mode_str(num, share_entry));
+               char *str = talloc_asprintf(talloc_tos(),
+                       "Got a deferred entry without a request: "
+                       "PANIC: %s\n",
+                       share_mode_str(talloc_tos(), num, share_entry));
                smb_panic(str);
        }
 
@@ -515,7 +533,7 @@ static void validate_my_share_entries(int num,
                            share_entry->share_file_id);
        if (!fsp) {
                DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
-                        share_mode_str(num, share_entry) ));
+                        share_mode_str(talloc_tos(), num, share_entry) ));
                smb_panic("validate_my_share_entries: Cannot match a "
                          "share entry with an open file\n");
        }
@@ -540,11 +558,12 @@ static void validate_my_share_entries(int num,
 
  panic:
        {
-               pstring str;
+               char *str;
                DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
-                        share_mode_str(num, share_entry) ));
-               slprintf(str, sizeof(str)-1, "validate_my_share_entries: "
-                        "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
+                        share_mode_str(talloc_tos(), num, share_entry) ));
+               str = talloc_asprintf(talloc_tos(),
+                       "validate_my_share_entries: "
+                       "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
                         fsp->fsp_name, (unsigned int)fsp->oplock_type,
                         (unsigned int)share_entry->op_type );
                smb_panic(str);
@@ -552,7 +571,7 @@ static void validate_my_share_entries(int num,
 }
 #endif
 
-static BOOL is_stat_open(uint32 access_mask)
+static bool is_stat_open(uint32 access_mask)
 {
        return (access_mask &&
                ((access_mask & ~(SYNCHRONIZE_ACCESS| FILE_READ_ATTRIBUTES|
@@ -573,7 +592,7 @@ static NTSTATUS open_mode_check(connection_struct *conn,
                                uint32 access_mask,
                                uint32 share_access,
                                uint32 create_options,
-                               BOOL *file_existed)
+                               bool *file_existed)
 {
        int i;
 
@@ -627,7 +646,7 @@ static NTSTATUS open_mode_check(connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-static BOOL is_delete_request(files_struct *fsp) {
+static bool is_delete_request(files_struct *fsp) {
        return ((fsp->access_mask == DELETE_ACCESS) &&
                (fsp->oplock_type == NO_OPLOCK));
 }
@@ -642,7 +661,7 @@ static BOOL is_delete_request(files_struct *fsp) {
  * 3) Only level2 around: Grant level2 and do nothing else.
  */
 
-static BOOL delay_for_oplocks(struct share_mode_lock *lck,
+static bool delay_for_oplocks(struct share_mode_lock *lck,
                              files_struct *fsp,
                              uint16 mid,
                              int pass_number,
@@ -650,9 +669,9 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
 {
        int i;
        struct share_mode_entry *exclusive = NULL;
-       BOOL valid_entry = False;
-       BOOL delay_it = False;
-       BOOL have_level2 = False;
+       bool valid_entry = False;
+       bool delay_it = False;
+       bool have_level2 = False;
        NTSTATUS status;
        char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
 
@@ -753,7 +772,7 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
        return True;
 }
 
-static BOOL request_timed_out(struct timeval request_time,
+static bool request_timed_out(struct timeval request_time,
                              struct timeval timeout)
 {
        struct timeval now, end_time;
@@ -769,7 +788,7 @@ static BOOL request_timed_out(struct timeval request_time,
 static void defer_open(struct share_mode_lock *lck,
                       struct timeval request_time,
                       struct timeval timeout,
-                      uint16 mid,
+                      struct smb_request *req,
                       struct deferred_open_record *state)
 {
        int i;
@@ -783,9 +802,9 @@ static void defer_open(struct share_mode_lock *lck,
                        continue;
                }
 
-               if (procid_is_me(&e->pid) && (e->op_mid == mid)) {
+               if (procid_is_me(&e->pid) && (e->op_mid == req->mid)) {
                        DEBUG(0, ("Trying to defer an already deferred "
-                                 "request: mid=%d, exiting\n", mid));
+                                 "request: mid=%d, exiting\n", req->mid));
                        exit_server("attempt to defer a deferred request");
                }
        }
@@ -796,13 +815,13 @@ static void defer_open(struct share_mode_lock *lck,
                  "open entry for mid %u\n",
                  (unsigned int)request_time.tv_sec,
                  (unsigned int)request_time.tv_usec,
-                 (unsigned int)mid));
+                 (unsigned int)req->mid));
 
-       if (!push_deferred_smb_message(mid, request_time, timeout,
+       if (!push_deferred_smb_message(req, request_time, timeout,
                                       (char *)state, sizeof(*state))) {
                exit_server("push_deferred_smb_message failed");
        }
-       add_deferred_open(lck, mid, request_time, state->id);
+       add_deferred_open(lck, req->mid, request_time, state->id);
 
        /*
         * Push the MID of this packet on the signing queue.
@@ -811,7 +830,7 @@ static void defer_open(struct share_mode_lock *lck,
         * of incrementing the response sequence number.
         */
 
-       srv_defer_sign_response(mid);
+       srv_defer_sign_response(req->mid);
 }
 
 
@@ -819,7 +838,7 @@ static void defer_open(struct share_mode_lock *lck,
  On overwrite open ensure that the attributes match.
 ****************************************************************************/
 
-static BOOL open_match_attributes(connection_struct *conn,
+static bool open_match_attributes(connection_struct *conn,
                                  const char *path,
                                  uint32 old_dos_attr,
                                  uint32 new_dos_attr,
@@ -931,7 +950,7 @@ static files_struct *fcb_or_dos_open(connection_struct *conn,
  Open a file with a share mode - old openX method - map into NTCreate.
 ****************************************************************************/
 
-BOOL map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func,
+bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func,
                                 uint32 *paccess_mask,
                                 uint32 *pshare_mode,
                                 uint32 *pcreate_disposition,
@@ -1068,7 +1087,7 @@ BOOL map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func
 
 static void schedule_defer_open(struct share_mode_lock *lck,
                                struct timeval request_time,
-                               uint16 mid)
+                               struct smb_request *req)
 {
        struct deferred_open_record state;
 
@@ -1099,7 +1118,7 @@ static void schedule_defer_open(struct share_mode_lock *lck,
        state.id = lck->id;
 
        if (!request_timed_out(request_time, timeout)) {
-               defer_open(lck, request_time, timeout, mid, &state);
+               defer_open(lck, request_time, timeout, req, &state);
        }
 }
 
@@ -1123,10 +1142,10 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 {
        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;
+       bool file_existed = VALID_STAT(*psbuf);
+       bool def_acl = False;
+       bool posix_open = False;
+       bool new_file_created = False;
        struct file_id id;
        NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
        files_struct *fsp = NULL;
@@ -1160,7 +1179,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return print_fsp_open(conn, fname, result);
        }
 
-       if (!parent_dirname_talloc(tmp_talloc_ctx(), fname, &parent_dir,
+       if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir,
                                   &newname)) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1386,7 +1405,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 #endif /* O_SYNC */
   
-       if (posix_open & (access_mask & FILE_APPEND_DATA)) {
+       if (posix_open && (access_mask & FILE_APPEND_DATA)) {
                flags2 |= O_APPEND;
        }
 
@@ -1417,7 +1436,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return status;
        }
 
-       fsp->file_id = file_id_sbuf(psbuf);
+       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
@@ -1433,7 +1452,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 
        if (file_existed) {
-               id = file_id_sbuf(psbuf);
+               id = vfs_file_id_from_sbuf(conn, psbuf);
 
                lck = get_share_mode_lock(NULL, id,
                                          conn->connectpath,
@@ -1449,7 +1468,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                if ((req != NULL)
                    && delay_for_oplocks(lck, fsp, req->mid, 1,
                                         oplock_request)) {
-                       schedule_defer_open(lck, request_time, req->mid);
+                       schedule_defer_open(lck, request_time, req);
                        TALLOC_FREE(lck);
                        file_free(fsp);
                        return NT_STATUS_SHARING_VIOLATION;
@@ -1469,8 +1488,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        if ((req != NULL)
                             && delay_for_oplocks(lck, fsp, req->mid, 2,
                                                  oplock_request)) {
-                               schedule_defer_open(lck, request_time,
-                                                   req->mid);
+                               schedule_defer_open(lck, request_time, req);
                                TALLOC_FREE(lck);
                                file_free(fsp);
                                return NT_STATUS_SHARING_VIOLATION;
@@ -1486,7 +1504,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                if (!NT_STATUS_IS_OK(status)) {
                        uint32 can_access_mask;
-                       BOOL can_access = True;
+                       bool can_access = True;
 
                        SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
 
@@ -1588,7 +1606,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                                    && !request_timed_out(request_time,
                                                          timeout)) {
                                        defer_open(lck, request_time, timeout,
-                                                  req->mid, &state);
+                                                  req, &state);
                                }
                        }
 
@@ -1670,7 +1688,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                if (lck == NULL) {
                        DEBUG(0, ("open_file_ntcreate: Could not get share "
                                  "mode lock for %s\n", fname));
-                       fd_close(conn, fsp);
+                       fd_close(fsp);
                        file_free(fsp);
                        return NT_STATUS_SHARING_VIOLATION;
                }
@@ -1679,9 +1697,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                if ((req != NULL)
                    && delay_for_oplocks(lck, fsp, req->mid, 1,
                                         oplock_request)) {
-                       schedule_defer_open(lck, request_time, req->mid);
+                       schedule_defer_open(lck, request_time, req);
                        TALLOC_FREE(lck);
-                       fd_close(conn, fsp);
+                       fd_close(fsp);
                        file_free(fsp);
                        return NT_STATUS_SHARING_VIOLATION;
                }
@@ -1698,10 +1716,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        if ((req != NULL)
                            && delay_for_oplocks(lck, fsp, req->mid, 2,
                                                 oplock_request)) {
-                               schedule_defer_open(lck, request_time,
-                                                   req->mid);
+                               schedule_defer_open(lck, request_time, req);
                                TALLOC_FREE(lck);
-                               fd_close(conn, fsp);
+                               fd_close(fsp);
                                file_free(fsp);
                                return NT_STATUS_SHARING_VIOLATION;
                        }
@@ -1710,7 +1727,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                if (!NT_STATUS_IS_OK(status)) {
                        struct deferred_open_record state;
 
-                       fd_close(conn, fsp);
+                       fd_close(fsp);
                        file_free(fsp);
 
                        state.delayed_for_oplocks = False;
@@ -1725,7 +1742,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                        if (req != NULL) {
                                defer_open(lck, request_time, timeval_zero(),
-                                          req->mid, &state);
+                                          req, &state);
                        }
                        TALLOC_FREE(lck);
                        return status;
@@ -1751,7 +1768,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        if(ret_flock == -1 ){
 
                TALLOC_FREE(lck);
-               fd_close(conn, fsp);
+               fd_close(fsp);
                file_free(fsp);
                
                return NT_STATUS_SHARING_VIOLATION;
@@ -1772,11 +1789,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                 * We are modifing the file after open - update the stat
                 * struct..
                 */
-               if ((SMB_VFS_FTRUNCATE(fsp,fsp->fh->fd,0) == -1) ||
-                   (SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf)==-1)) {
+               if ((SMB_VFS_FTRUNCATE(fsp, 0) == -1) ||
+                   (SMB_VFS_FSTAT(fsp, psbuf)==-1)) {
                        status = map_nt_error_from_unix(errno);
                        TALLOC_FREE(lck);
-                       fd_close(conn,fsp);
+                       fd_close(fsp);
                        file_free(fsp);
                        return status;
                }
@@ -1833,7 +1850,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        /* Remember to delete the mode we just added. */
                        del_share_mode(lck, fsp);
                        TALLOC_FREE(lck);
-                       fd_close(conn,fsp);
+                       fd_close(fsp);
                        file_free(fsp);
                        return status;
                }
@@ -1847,9 +1864,15 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                if (lp_map_archive(SNUM(conn)) ||
                    lp_store_dos_attributes(SNUM(conn))) {
                        if (!posix_open) {
-                               file_set_dosmode(conn, fname,
-                                        new_dos_attributes | aARCH, NULL,
-                                        parent_dir);
+                               SMB_STRUCT_STAT tmp_sbuf;
+                               SET_STAT_INVALID(tmp_sbuf);
+                               if (file_set_dosmode(
+                                           conn, fname,
+                                           new_dos_attributes | aARCH,
+                                           &tmp_sbuf, parent_dir,
+                                           true) == 0) {
+                                       unx_mode = tmp_sbuf.st_mode;
+                               }
                        }
                }
        }
@@ -1892,7 +1915,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
 
                if ((ret == -1) &&
-                   (SMB_VFS_FCHMOD(fsp, fsp->fh->fd, new_unx_mode) == -1))
+                   (SMB_VFS_FCHMOD(fsp, new_unx_mode) == -1))
                        DEBUG(5, ("open_file_ntcreate: failed to reset "
                                  "attributes of file %s to 0%o\n",
                                  fname, (unsigned int)new_unx_mode));
@@ -1956,7 +1979,7 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
 
 NTSTATUS close_file_fchmod(files_struct *fsp)
 {
-       NTSTATUS status = fd_close(fsp->conn, fsp);
+       NTSTATUS status = fd_close(fsp);
        file_free(fsp);
        return status;
 }
@@ -1970,6 +1993,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
        char *parent_dir;
        const char *dirname;
        NTSTATUS status;
+       bool posix_open = false;
 
        if(!CAN_WRITE(conn)) {
                DEBUG(5,("mkdir_internal: failing create on read-only share "
@@ -1982,12 +2006,13 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return status;
        }
 
-       if (!parent_dirname_talloc(tmp_talloc_ctx(), name, &parent_dir,
+       if (!parent_dirname_talloc(talloc_tos(), name, &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);
        } else {
                mode = unix_mode(conn, aDIR, name, parent_dir);
@@ -2012,6 +2037,15 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       if (lp_store_dos_attributes(SNUM(conn))) {
+               if (!posix_open) {
+                       file_set_dosmode(conn, name,
+                                file_attributes | aDIR, NULL,
+                                parent_dir,
+                                true);
+               }
+       }
+
        if (lp_inherit_perms(SNUM(conn))) {
                inherit_access_acl(conn, parent_dir, name, mode);
        }
@@ -2057,7 +2091,7 @@ NTSTATUS open_directory(connection_struct *conn,
                        files_struct **result)
 {
        files_struct *fsp = NULL;
-       BOOL dir_existed = VALID_STAT(*psbuf) ? True : False;
+       bool dir_existed = VALID_STAT(*psbuf) ? True : False;
        struct share_mode_lock *lck = NULL;
        NTSTATUS status;
        int info = 0;
@@ -2073,7 +2107,7 @@ NTSTATUS open_directory(connection_struct *conn,
                 (unsigned int)file_attributes));
 
        if (is_ntfs_stream_name(fname)) {
-               DEBUG(0,("open_directory: %s is a stream name!\n", fname ));
+               DEBUG(2, ("open_directory: %s is a stream name!\n", fname));
                return NT_STATUS_NOT_A_DIRECTORY;
        }
 
@@ -2161,7 +2195,7 @@ NTSTATUS open_directory(connection_struct *conn,
         */
        
        fsp->mode = psbuf->st_mode;
-       fsp->file_id = file_id_sbuf(psbuf);
+       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;
@@ -2233,7 +2267,7 @@ NTSTATUS open_directory(connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-NTSTATUS create_directory(connection_struct *conn, const char *directory)
+NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, const char *directory)
 {
        NTSTATUS status;
        SMB_STRUCT_STAT sbuf;
@@ -2241,7 +2275,7 @@ NTSTATUS create_directory(connection_struct *conn, const char *directory)
 
        SET_STAT_INVALID(sbuf);
        
-       status = open_directory(conn, NULL, directory, &sbuf,
+       status = open_directory(conn, req, directory, &sbuf,
                                FILE_READ_ATTRIBUTES, /* Just a stat open */
                                FILE_SHARE_NONE, /* Ignored for stat opens */
                                FILE_CREATE,
@@ -2289,7 +2323,7 @@ NTSTATUS open_file_stat(connection_struct *conn, struct smb_request *req,
         */
        
        fsp->mode = psbuf->st_mode;
-       fsp->file_id = file_id_sbuf(psbuf);
+       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;
@@ -2342,7 +2376,7 @@ void msg_file_was_renamed(struct messaging_context *msg,
 
        DEBUG(10,("msg_file_was_renamed: Got rename message for sharepath %s, new name %s, "
                "file_id %s\n",
-                 sharepath, newname, file_id_static_string(&id)));
+                 sharepath, newname, file_id_string_tos(&id)));
 
        for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
                if (memcmp(fsp->conn->connectpath, sharepath, sp_len) == 0) {
@@ -2364,3 +2398,535 @@ void msg_file_was_renamed(struct messaging_context *msg,
                }
         }
 }
+
+struct case_semantics_state {
+       connection_struct *conn;
+       bool case_sensitive;
+       bool case_preserve;
+       bool short_case_preserve;
+};
+
+/****************************************************************************
+ Restore case semantics.
+****************************************************************************/
+static int restore_case_semantics(struct case_semantics_state *state)
+{
+       state->conn->case_sensitive = state->case_sensitive;
+       state->conn->case_preserve = state->case_preserve;
+       state->conn->short_case_preserve = state->short_case_preserve;
+       return 0;
+}
+
+/****************************************************************************
+ Save case semantics.
+****************************************************************************/
+static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx,
+                                                            connection_struct *conn)
+{
+       struct case_semantics_state *result;
+
+       if (!(result = talloc(mem_ctx, struct case_semantics_state))) {
+               DEBUG(0, ("talloc failed\n"));
+               return NULL;
+       }
+
+       result->conn = conn;
+       result->case_sensitive = conn->case_sensitive;
+       result->case_preserve = conn->case_preserve;
+       result->short_case_preserve = conn->short_case_preserve;
+
+       /* Set to POSIX. */
+       conn->case_sensitive = True;
+       conn->case_preserve = True;
+       conn->short_case_preserve = True;
+
+       talloc_set_destructor(result, restore_case_semantics);
+
+       return result;
+}
+
+/*
+ * Wrapper around open_file_ntcreate and open_directory
+ */
+
+NTSTATUS 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,
+                             SMB_BIG_UINT 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 *fsp = NULL;
+       NTSTATUS status;
+
+       DEBUG(10,("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 (req == NULL) {
+               oplock_request |= INTERNAL_OPEN_ONLY;
+       }
+
+       if (psbuf != NULL) {
+               sbuf = *psbuf;
+       }
+       else {
+               SET_STAT_INVALID(sbuf);
+       }
+
+       /* This is the correct thing to do (check every time) but can_delete
+        * is expensive (it may have to read the parent directory
+        * permissions). So for now we're not doing it unless we have a strong
+        * hint the client is really going to delete this file. If the client
+        * is forcing FILE_CREATE let the filesystem take care of the
+        * permissions. */
+
+       /* Setting FILE_SHARE_DELETE is the hint. */
+
+       if (lp_acl_check_permissions(SNUM(conn))
+           && (create_disposition != FILE_CREATE)
+           && (share_access & FILE_SHARE_DELETE)
+           && (access_mask & DELETE_ACCESS)
+           && (((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY)
+                && !lp_delete_readonly(SNUM(conn)))
+               || !can_delete_file_in_directory(conn, fname))) {
+               status = NT_STATUS_ACCESS_DENIED;
+               goto fail;
+       }
+
+#if 0
+       /* We need to support SeSecurityPrivilege for this. */
+       if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) &&
+           !user_has_privileges(current_user.nt_user_token,
+                                &se_security)) {
+               status = NT_STATUS_PRIVILEGE_NOT_HELD;
+               goto fail;
+       }
+#endif
+
+       /*
+        * If it's a request for a directory open, deal with it separately.
+        */
+
+       if (create_options & FILE_DIRECTORY_FILE) {
+
+               /* Can't open a temp directory. IFS kit test. */
+               if (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.
+                */
+
+               oplock_request = 0;
+               status = open_directory(
+                       conn, req, fname, &sbuf, access_mask, share_access,
+                       create_disposition, create_options, file_attributes,
+                       &info, &fsp);
+       } else {
+
+               /*
+                * Ordinary file case.
+                */
+
+               status = open_file_ntcreate(
+                       conn, req, fname, &sbuf, access_mask, share_access,
+                       create_disposition, create_options, file_attributes,
+                       oplock_request, &info, &fsp);
+
+               if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
+
+                       /*
+                        * 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;
+                       }
+
+                       oplock_request = 0;
+                       status = open_directory(
+                               conn, req, fname, &sbuf, access_mask,
+                               share_access, create_disposition,
+                               create_options, file_attributes,
+                               &info, &fsp);
+               }
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       /*
+        * According to the MS documentation, the only time the security
+        * descriptor is applied to the opened file is iff we *created* the
+        * file; an existing file stays the same.
+        *
+        * Also, it seems (from observation) that you can open the file with
+        * any access mask but you can still write the sd. We need to override
+        * the granted access before we call set_sd
+        * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>.
+        */
+
+       if ((sd != NULL) && (info == FILE_WAS_CREATED)
+           && lp_nt_acl_support(SNUM(conn))) {
+
+               uint32_t sec_info_sent = ALL_SECURITY_INFORMATION;
+               uint32_t saved_access_mask = fsp->access_mask;
+
+               if (sd->owner_sid == NULL) {
+                       sec_info_sent &= ~OWNER_SECURITY_INFORMATION;
+               }
+               if (sd->group_sid == NULL) {
+                       sec_info_sent &= ~GROUP_SECURITY_INFORMATION;
+               }
+               if (sd->sacl == NULL) {
+                       sec_info_sent &= ~SACL_SECURITY_INFORMATION;
+               }
+               if (sd->dacl == NULL) {
+                       sec_info_sent &= ~DACL_SECURITY_INFORMATION;
+               }
+
+               fsp->access_mask = FILE_GENERIC_ALL;
+
+               status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd);
+
+               fsp->access_mask = saved_access_mask;
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto fail;
+               }
+       }
+
+       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, (SMB_BIG_UINT)sbuf.st_size);
+               }
+       }
+
+       DEBUG(10, ("create_file: 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, ("create_file: %s\n", nt_errstr(status)));
+
+       if (fsp != NULL) {
+               close_file(fsp, ERROR_CLOSE);
+               fsp = NULL;
+       }
+       return status;
+}
+
+NTSTATUS create_file(connection_struct *conn,
+                    struct smb_request *req,
+                    uint16_t root_dir_fid,
+                    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,
+                    SMB_BIG_UINT allocation_size,
+                    struct security_descriptor *sd,
+                    struct ea_list *ea_list,
+
+                    files_struct **result,
+                    int *pinfo,
+                    SMB_STRUCT_STAT *psbuf)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct case_semantics_state *case_state = NULL;
+       SMB_STRUCT_STAT sbuf;
+       int info = FILE_WAS_OPENED;
+       files_struct *fsp = NULL;
+       NTSTATUS status;
+
+       DEBUG(10,("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, "
+                 "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, fname));
+
+       /*
+        * Get the file name.
+        */
+
+       if (root_dir_fid != 0) {
+               /*
+                * This filename is relative to a directory fid.
+                */
+               char *parent_fname = NULL;
+               files_struct *dir_fsp = file_fsp(root_dir_fid);
+
+               if (dir_fsp == NULL) {
+                       status = NT_STATUS_INVALID_HANDLE;
+                       goto fail;
+               }
+
+               if (!dir_fsp->is_directory) {
+
+                       /*
+                        * Check to see if this is a mac fork of some kind.
+                        */
+
+                       if (is_ntfs_stream_name(fname)) {
+                               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                               goto fail;
+                       }
+
+                       /*
+                         we need to handle the case when we get a
+                         relative open relative to a file and the
+                         pathname is blank - this is a reopen!
+                         (hint from demyn plantenberg)
+                       */
+
+                       status = NT_STATUS_INVALID_HANDLE;
+                       goto fail;
+               }
+
+               if (ISDOT(dir_fsp->fsp_name)) {
+                       /*
+                        * We're at the toplevel dir, the final file name
+                        * must not contain ./, as this is filtered out
+                        * normally by srvstr_get_path and unix_convert
+                        * explicitly rejects paths containing ./.
+                        */
+                       parent_fname = talloc_strdup(talloc_tos(), "");
+                       if (parent_fname == NULL) {
+                               status = NT_STATUS_NO_MEMORY;
+                               goto fail;
+                       }
+               } else {
+                       size_t dir_name_len = strlen(dir_fsp->fsp_name);
+
+                       /*
+                        * Copy in the base directory name.
+                        */
+
+                       parent_fname = TALLOC_ARRAY(talloc_tos(), char,
+                                                   dir_name_len+2);
+                       if (parent_fname == NULL) {
+                               status = NT_STATUS_NO_MEMORY;
+                               goto fail;
+                       }
+                       memcpy(parent_fname, dir_fsp->fsp_name,
+                              dir_name_len+1);
+
+                       /*
+                        * Ensure it ends in a '/'.
+                        * We used TALLOC_SIZE +2 to add space for the '/'.
+                        */
+
+                       if(dir_name_len
+                          && (parent_fname[dir_name_len-1] != '\\')
+                          && (parent_fname[dir_name_len-1] != '/')) {
+                               parent_fname[dir_name_len] = '/';
+                               parent_fname[dir_name_len+1] = '\0';
+                       }
+               }
+
+               fname = talloc_asprintf(talloc_tos(), "%s%s", parent_fname,
+                                       fname);
+               if (fname == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto fail;
+               }
+       } else {
+               /*
+                * Check to see if this is a mac fork of some kind.
+                */
+
+               if (is_ntfs_stream_name(fname)) {
+                       enum FAKE_FILE_TYPE fake_file_type;
+
+                       fake_file_type = is_fake_file(fname);
+
+                       if (fake_file_type == FAKE_FILE_TYPE_NONE) {
+                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                       }
+
+                       /*
+                        * Here we go! support for changing the disk quotas
+                        * --metze
+                        *
+                        * We need to fake up to open this MAGIC QUOTA file
+                        * and return a valid FID.
+                        *
+                        * w2k close this file directly after openening xp
+                        * also tries a QUERY_FILE_INFO on the file and then
+                        * close it
+                        */
+                       status = open_fake_file(conn, fake_file_type, fname,
+                                               access_mask, &fsp);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+
+                       goto done;
+               }
+       }
+
+       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);
+               file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+       }
+
+       {
+               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;
+       }
+
+       /* All file access must go through check_name() */
+
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+       status = create_file_unixpath(
+               conn, req, fname, access_mask, share_access,
+               create_disposition, create_options, file_attributes,
+               oplock_request, allocation_size, sd, ea_list,
+               &fsp, &info, &sbuf);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               goto fail;
+       }
+
+ done:
+       DEBUG(10, ("create_file: info=%d\n", info));
+
+       *result = fsp;
+       if (pinfo != NULL) {
+               *pinfo = info;
+       }
+       if (psbuf != NULL) {
+               *psbuf = sbuf;
+       }
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+
+ fail:
+       DEBUG(10, ("create_file: %s\n", nt_errstr(status)));
+
+       if (fsp != NULL) {
+               close_file(fsp, ERROR_CLOSE);
+               fsp = NULL;
+       }
+       TALLOC_FREE(frame);
+       return status;
+}