r21191: Add in the POSIX open/mkdir/unlink calls.
authorJeremy Allison <jra@samba.org>
Tue, 6 Feb 2007 21:05:34 +0000 (21:05 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:17:47 +0000 (12:17 -0500)
Move more error code returns to NTSTATUS.
Client test code to follow... See if this
passes the build-farm before I add it into
3.0.25.
Jeremy.

15 files changed:
source/include/smb.h
source/include/trans2.h
source/libsmb/smb_share_modes.c
source/locking/locking.c
source/locking/posix.c
source/param/loadparm.c
source/rpc_server/srv_srvsvc_nt.c
source/smbd/close.c
source/smbd/dir.c
source/smbd/fake_file.c
source/smbd/nttrans.c
source/smbd/open.c
source/smbd/oplock.c
source/smbd/reply.c
source/smbd/trans2.c

index 71ff656385f53819ffcd27229d58a8c1122cd1cd..7bc5c0a4144b603d9aee71ce94fb1d4576c38fb3 100644 (file)
@@ -515,6 +515,7 @@ typedef struct files_struct {
        BOOL aio_write_behind;
        BOOL lockdb_clean;
        BOOL initial_delete_on_close; /* Only set at NTCreateX if file was created. */
+       BOOL posix_open;
        char *fsp_name;
 
        struct vfs_fsp_data *vfs_extension;
@@ -736,6 +737,8 @@ struct pending_message_list {
        DATA_BLOB private_data;
 };
 
+#define SHARE_MODE_FLAG_POSIX_OPEN     0x1
+
 /* struct returned by get_share_modes */
 struct share_mode_entry {
        struct process_id pid;
@@ -752,6 +755,7 @@ struct share_mode_entry {
        SMB_INO_T inode;
        unsigned long share_file_id;
        uint32 uid;             /* uid of file opener. */
+       uint16 flags;           /* POSIX_OPEN only defined so far... */
 };
 
 /* oplock break message definition - linearization of share_mode_entry.
@@ -769,10 +773,11 @@ Offset  Data                      length.
 36     SMB_INO_T inode         8 bytes
 44     unsigned long file_id   4 bytes
 48     uint32 uid              4 bytes
-52
+52     uint16 flags            2 bytes
+54
 
 */
-#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 52
+#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 54
 
 struct share_mode_lock {
        const char *servicepath; /* canonicalized. */
@@ -1580,19 +1585,19 @@ extern int chain_size;
  * Note these must fit into 16-bits.
  */
 
-#define NO_OPLOCK 0
-#define EXCLUSIVE_OPLOCK 1
-#define BATCH_OPLOCK 2
-#define LEVEL_II_OPLOCK 4
+#define NO_OPLOCK                      0x0
+#define EXCLUSIVE_OPLOCK               0x1
+#define BATCH_OPLOCK                   0x2
+#define LEVEL_II_OPLOCK                0x4
 
 /* The following are Samba-private. */
-#define INTERNAL_OPEN_ONLY 8
-#define FAKE_LEVEL_II_OPLOCK 16        /* Client requested no_oplock, but we have to
+#define INTERNAL_OPEN_ONLY             0x8
+#define FAKE_LEVEL_II_OPLOCK           0x10    /* Client requested no_oplock, but we have to
                                 * inform potential level2 holders on
                                 * write. */
-#define DEFERRED_OPEN_ENTRY 32
-#define UNUSED_SHARE_MODE_ENTRY 64
-#define FORCE_OPLOCK_BREAK_TO_NONE 128
+#define DEFERRED_OPEN_ENTRY            0x20
+#define UNUSED_SHARE_MODE_ENTRY        0x40
+#define FORCE_OPLOCK_BREAK_TO_NONE     0x80
 
 /* None of the following should ever appear in fsp->oplock_request. */
 #define SAMBA_PRIVATE_OPLOCK_MASK (INTERNAL_OPEN_ONLY|DEFERRED_OPEN_ENTRY|UNUSED_SHARE_MODE_ENTRY|FORCE_OPLOCK_BREAK_TO_NONE)
index 92c5a2e963f9387bf32cfcc17ac305ff08149f6b..44e85d8489adcfc40c90566b96cd05552d2bb401 100644 (file)
@@ -446,6 +446,13 @@ Offset Size         Name
 /* Only valid for setfileinfo */
 #define SMB_SET_POSIX_LOCK            0x208
 
+/* The set info levels for POSIX path operations. */
+#define SMB_POSIX_PATH_OPEN           0x209
+#define SMB_POSIX_PATH_UNLINK         0x20A
+
+#define SMB_QUERY_FILE_UNIX_INFO2      0x20B   /* UNIX File Info2 */
+#define SMB_SET_FILE_UNIX_INFO2        0x20B
+
 /* Transact 2 Find First levels */
 #define SMB_FIND_FILE_UNIX             0x202
 
@@ -477,6 +484,7 @@ Offset Size         Name
 #define CIFS_UNIX_EXTATTR_CAP              0x8 /* for support of chattr
                                                (chflags) and lsattr */
 #define CIFS_UNIX_POSIX_PATHNAMES_CAP     0x10 /* Use POSIX pathnames on the wire. */
+#define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP       0x20 /* We can cope with POSIX open/mkdir/unlink etc. */
 
 
 #define SMB_QUERY_POSIX_FS_INFO     0x201
@@ -579,7 +587,7 @@ number of entries sent will be zero.
 
 #define SMB_POSIX_IGNORE_ACE_ENTRIES   0xFFFF
 
-/* Definition of SMB_SET_POSIX_LOCK */
+/* Definition of parameter block of SMB_SET_POSIX_LOCK */
 /*
   [2 bytes] lock_type - 0 = Read, 1 = Write, 2 = Unlock
   [2 bytes] lock_flags - 1 = Wait (only valid for setlock)
@@ -602,4 +610,37 @@ number of entries sent will be zero.
 #define POSIX_LOCK_TYPE_WRITE 1
 #define POSIX_LOCK_TYPE_UNLOCK 2
 
+/* SMB_POSIX_PATH_OPEN "open_mode" definitions. */
+#define SMB_O_RDONLY                     0x1
+#define SMB_O_WRONLY                     0x2
+#define SMB_O_RDWR                       0x4
+
+#define SMB_ACCMODE                      0x7
+
+#define SMB_O_CREAT                     0x10
+#define SMB_O_EXCL                      0x20
+#define SMB_O_TRUNC                     0x40
+#define SMB_O_APPEND                    0x80
+#define SMB_O_SYNC                     0x100
+#define SMB_O_DIRECTORY                        0x200
+#define SMB_O_NOFOLLOW                 0x400
+#define SMB_O_DIRECT                   0x800
+
+/* Definition of request parameter block for SMB_POSIX_PATH_OPEN */
+/*
+  [4 bytes] flags (as smb_ntcreate_Flags).
+  [4 bytes] open_mode
+  [4 bytes] mode_t             - same encoding as "Standard UNIX permissions" above.
+  [2 bytes] ret_info_level     - optimization. Info level to be returned.
+*/
+
+/* Definition of reply data block for SMB_POSIX_PATH_OPEN */
+
+#define SMB_NO_INFO_LEVEL_RETURNED 0xFFFF
+
+/*
+  [2 bytes] reply info level    - as requested or 0xFFFF if not available.
+  [n bytes] - info level reply  - if available.
+*/
+
 #endif
index b8c7a7e66b4bd4466838c669f459e6caebcfbf3f..4c49ecb7bd9489bf22bbb308be89b443c214b204 100644 (file)
@@ -154,6 +154,7 @@ static void create_share_mode_entry(struct share_mode_entry *out,
        out->dev = (SMB_DEV_T)in->dev;
        out->inode = (SMB_INO_T)in->ino;
        out->uid = (uint32)geteuid();
+       out->flags = 0;
 }
 
 /*
index d2e8b7ef5979370588d743d8b4621c19055f58e5..39cc991b5f297b6b997ffb60bbf4ed0369acf9fe 100644 (file)
@@ -81,7 +81,7 @@ BOOL is_locked(files_struct *fsp,
                enum brl_type lock_type)
 {
        int strict_locking = lp_strict_locking(fsp->conn->params);
-       enum brl_flavour lock_flav = lp_posix_cifsu_locktype();
+       enum brl_flavour lock_flav = lp_posix_cifsu_locktype(fsp);
        BOOL ret = True;
        
        if (count == 0) {
@@ -426,13 +426,14 @@ char *share_mode_str(int num, struct share_mode_entry *e)
        slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: %s "
                 "pid = %s, share_access = 0x%x, private_options = 0x%x, "
                 "access_mask = 0x%x, mid = 0x%x, type= 0x%x, file_id = %lu, "
-                "uid = %u, dev = 0x%x, inode = %.0f",
+                "uid = %u, flags = %u, dev = 0x%x, inode = %.0f",
                 num,
                 e->op_type == UNUSED_SHARE_MODE_ENTRY ? "UNUSED" : "",
                 procid_str_static(&e->pid),
                 e->share_access, e->private_options,
                 e->access_mask, e->op_mid, e->op_type, e->share_file_id,
-                (unsigned int)e->uid, (unsigned int)e->dev, (double)e->inode );
+                (unsigned int)e->uid, (unsigned int)e->flags,
+                (unsigned int)e->dev, (double)e->inode );
 
        return share_str;
 }
@@ -912,6 +913,7 @@ static void fill_share_mode_entry(struct share_mode_entry *e,
        e->inode = fsp->inode;
        e->share_file_id = fsp->fh->file_id;
        e->uid = (uint32)uid;
+       e->flags = fsp->posix_open ? SHARE_MODE_FLAG_POSIX_OPEN : 0;
 }
 
 static void fill_deferred_open_entry(struct share_mode_entry *e,
@@ -927,6 +929,7 @@ static void fill_deferred_open_entry(struct share_mode_entry *e,
        e->dev = dev;
        e->inode = ino;
        e->uid = (uint32)-1;
+       e->flags = 0;
 }
 
 static void add_share_mode_entry(struct share_mode_lock *lck,
index 806018da8161d13ab474c2c80e1d68127f3b92a6..62804eb8e34a6368221b7247606030814813cc09 100644 (file)
@@ -636,7 +636,7 @@ static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries)
  to delete all locks on this fsp before this function is called.
 ****************************************************************************/
 
-int fd_close_posix(struct connection_struct *conn, files_struct *fsp)
+NTSTATUS fd_close_posix(struct connection_struct *conn, files_struct *fsp)
 {
        int saved_errno = 0;
        int ret;
@@ -651,7 +651,7 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp)
                 */
                ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd);
                fsp->fh->fd = -1;
-               return ret;
+               return map_nt_error_from_unix(errno);
        }
 
        if (get_windows_lock_ref_count(fsp)) {
@@ -663,7 +663,7 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp)
 
                add_fd_to_close_entry(fsp);
                fsp->fh->fd = -1;
-               return 0;
+               return NT_STATUS_OK;
        }
 
        /*
@@ -701,14 +701,18 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp)
 
        ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd);
 
-       if (saved_errno != 0) {
+       if (ret == 0 && saved_errno != 0) {
                errno = saved_errno;
                ret = -1;
        } 
 
        fsp->fh->fd = -1;
 
-       return ret;
+       if (ret == -1) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
index f7dd30475adf271dc96c9f4e14ee4a72dd9a19d9..d7b23f615fbf7e87f1b07dedd69ba731daf8df97 100644 (file)
@@ -5589,17 +5589,23 @@ void lp_set_posix_pathnames(void)
  Global state for POSIX lock processing - CIFS unix extensions.
 ********************************************************************/
 
+BOOL posix_default_lock_was_set;
 static enum brl_flavour posix_cifsx_locktype; /* By default 0 == WINDOWS_LOCK */
 
-enum brl_flavour lp_posix_cifsu_locktype(void)
+enum brl_flavour lp_posix_cifsu_locktype(files_struct *fsp)
 {
-       return posix_cifsx_locktype;
+       if (posix_default_lock_was_set) {
+               return posix_cifsx_locktype;
+       } else {
+               return fsp->posix_open ? POSIX_LOCK : WINDOWS_LOCK;
+       }
 }
 
 /*******************************************************************
 ********************************************************************/
 
-void lp_set_posix_cifsx_locktype(enum brl_flavour val)
+void lp_set_posix_default_cifsx_readwrite_locktype(enum brl_flavour val)
 {
+       posix_default_lock_was_set = True;
        posix_cifsx_locktype = val;
 }
index c0953f2723aa4dbcc5915c531c267ba2daf75d07..005c57e50a48f82d389c2298d17a9e36497fbd05 100644 (file)
@@ -2081,6 +2081,7 @@ WERROR _srvsvc_NetGetFileSecurity(pipes_struct *p, struct srvsvc_NetGetFileSecur
                                        FILE_SHARE_READ|FILE_SHARE_WRITE,
                                        FILE_OPEN,
                                        0,
+                                       FILE_ATTRIBUTE_DIRECTORY,
                                        NULL, &fsp);
 
                if (!NT_STATUS_IS_OK(nt_status)) {
@@ -2187,6 +2188,7 @@ WERROR _srvsvc_NetSetFileSecurity(pipes_struct *p, struct srvsvc_NetSetFileSecur
                                                FILE_SHARE_READ|FILE_SHARE_WRITE,
                                                FILE_OPEN,
                                                0,
+                                               FILE_ATTRIBUTE_DIRECTORY,
                                                NULL, &fsp);
 
                if (!NT_STATUS_IS_OK(nt_status)) {
index 714e0615de690e61be68883ee074902d2b6afd85..05a45cc14fa85d91ddec6fd4f95f35c0f68c1e91 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    file closing
    Copyright (C) Andrew Tridgell 1992-1998
-   Copyright (C) Jeremy Allison 1992-2004.
+   Copyright (C) Jeremy Allison 1992-2007.
    Copyright (C) Volker Lendecke 2005
    
    This program is free software; you can redistribute it and/or modify
@@ -90,22 +90,21 @@ static void check_magic(files_struct *fsp,connection_struct *conn)
   Common code to close a file or a directory.
 ****************************************************************************/
 
-static int close_filestruct(files_struct *fsp)
+static NTSTATUS close_filestruct(files_struct *fsp)
 {   
+       NTSTATUS status = NT_STATUS_OK;
        connection_struct *conn = fsp->conn;
-       int ret = 0;
     
        if (fsp->fh->fd != -1) {
-               if(flush_write_cache(fsp, CLOSE_FLUSH) == -1)
-                       ret = -1;
-
+               if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) {
+                       status = map_nt_error_from_unix(errno);
+               }
                delete_write_cache(fsp);
        }
 
        conn->num_files_open--;
        SAFE_FREE(fsp->wbmpx_ptr);
-
-       return ret;
+       return status;
 }    
 
 /****************************************************************************
@@ -195,9 +194,13 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
        if (delete_file) {
                int i;
                /* See if others still have the file open. If this is the
-                * case, then don't delete */
+                * case, then don't delete. If all opens are POSIX delete now. */
                for (i=0; i<lck->num_share_modes; i++) {
-                       if (is_valid_share_mode_entry(&lck->share_modes[i])) {
+                       struct share_mode_entry *e = &lck->share_modes[i];
+                       if (is_valid_share_mode_entry(e)) {
+                               if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+                                       continue;
+                               }
                                delete_file = False;
                                break;
                        }
@@ -282,12 +285,10 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                         fsp->fsp_name, strerror(errno) ));
 
                status = map_nt_error_from_unix(errno);
-               goto done;
        }
 
-       status = NT_STATUS_FILE_DELETED;
-
  done:
+
        /* unbecome user. */
        pop_sec_ctx();
        
@@ -303,12 +304,13 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
  delete on close is done on normal and shutdown close.
 ****************************************************************************/
 
-static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
+static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_type)
 {
+       NTSTATUS status = NT_STATUS_OK;
+       NTSTATUS saved_status1 = NT_STATUS_OK;
+       NTSTATUS saved_status2 = NT_STATUS_OK;
+       NTSTATUS saved_status3 = NT_STATUS_OK;
        connection_struct *conn = fsp->conn;
-       int saved_errno = 0;
-       int err = 0;
-       int err1 = 0;
 
        if (fsp->aio_write_behind) {
                /*
@@ -317,8 +319,7 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
                 */
                int ret = wait_for_aio_completion(fsp);
                if (ret) {
-                       saved_errno = ret;
-                       err1 = -1;
+                       saved_status1 = map_nt_error_from_unix(ret);
                }
        } else {
                cancel_aio_by_fsp(fsp);
@@ -329,15 +330,12 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
         * error here, we must remember this.
         */
 
-       if (close_filestruct(fsp) == -1) {
-               saved_errno = errno;
-               err1 = -1;
-       }
+       saved_status2 = close_filestruct(fsp);
 
        if (fsp->print_file) {
                print_fsp_end(fsp, close_type);
                file_free(fsp);
-               return 0;
+               return NT_STATUS_OK;
        }
 
        /* If this is an old DOS or FCB open and we have multiple opens on
@@ -346,7 +344,7 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
 
        if (fsp->fh->ref_count == 1) {
                /* Should we return on error here... ? */
-               close_remove_share_mode(fsp, close_type);
+               saved_status3 = close_remove_share_mode(fsp, close_type);
        }
 
        if(fsp->oplock_type) {
@@ -355,13 +353,7 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
 
        locking_close_file(fsp);
 
-       err = fd_close(conn, fsp);
-
-       /* Only save errno if fd_close failed and we don't already
-          have an errno saved from a flush call. */
-       if ((err1 != -1) && (err == -1)) {
-               saved_errno = errno;
-       }
+       status = fd_close(conn, fsp);
 
        /* check for magic scripts */
        if (close_type == NORMAL_CLOSE) {
@@ -378,29 +370,34 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
                set_filetime(conn, fsp->fsp_name, fsp->last_write_time);
        }
 
+       if (NT_STATUS_IS_OK(status)) {
+               if (!NT_STATUS_IS_OK(saved_status1)) {
+                       status = saved_status1;
+               } else if (!NT_STATUS_IS_OK(saved_status2)) {
+                       status = saved_status2;
+               } else if (!NT_STATUS_IS_OK(saved_status3)) {
+                       status = saved_status3;
+               }
+       }
+
        DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
                conn->user,fsp->fsp_name,
                conn->num_files_open,
-               (err == -1 || err1 == -1) ? strerror(saved_errno) : ""));
+               nt_errstr(status) ));
 
        file_free(fsp);
-
-       if (err == -1 || err1 == -1) {
-               errno = saved_errno;
-               return saved_errno;
-       } else {
-               return 0;
-       }
+       return status;
 }
 
 /****************************************************************************
  Close a directory opened by an NT SMB call. 
 ****************************************************************************/
   
-static int close_directory(files_struct *fsp, enum file_close_type close_type)
+static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_type)
 {
        struct share_mode_lock *lck = 0;
        BOOL delete_dir = False;
+       NTSTATUS status = NT_STATUS_OK;
 
        /*
         * NT can set delete_on_close of the last open
@@ -411,7 +408,7 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
 
        if (lck == NULL) {
                DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name));
-               return EINVAL;
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
        if (!del_share_mode(lck, fsp)) {
@@ -441,9 +438,13 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
        if (delete_dir) {
                int i;
                /* See if others still have the dir open. If this is the
-                * case, then don't delete */
+                * case, then don't delete. If all opens are POSIX delete now. */
                for (i=0; i<lck->num_share_modes; i++) {
-                       if (is_valid_share_mode_entry(&lck->share_modes[i])) {
+                       struct share_mode_entry *e = &lck->share_modes[i];
+                       if (is_valid_share_mode_entry(e)) {
+                               if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+                                       continue;
+                               }
                                delete_dir = False;
                                break;
                        }
@@ -469,7 +470,7 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
 
                TALLOC_FREE(lck);
 
-               ok = rmdir_internals(fsp->conn, fsp->fsp_name);
+               status = rmdir_internals(fsp->conn, fsp->fsp_name);
 
                DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n",
                        fsp->fsp_name, ok ? "succeeded" : "failed" ));
@@ -482,7 +483,7 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
                 * now fail as the directory has been deleted.
                 */
 
-               if(ok) {
+               if(NT_STATUS_IS_OK(status)) {
                        remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
                }
        } else {
@@ -496,35 +497,35 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
         */
        close_filestruct(fsp);
        file_free(fsp);
-       return 0;
+       return status;
 }
 
 /****************************************************************************
  Close a 'stat file' opened internally.
 ****************************************************************************/
   
-static int close_stat(files_struct *fsp)
+NTSTATUS close_stat(files_struct *fsp)
 {
        /*
         * Do the code common to files and directories.
         */
        close_filestruct(fsp);
        file_free(fsp);
-       return 0;
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
  Close a files_struct.
 ****************************************************************************/
   
-int close_file(files_struct *fsp, enum file_close_type close_type)
+NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type)
 {
-       if(fsp->is_directory)
+       if(fsp->is_directory) {
                return close_directory(fsp, close_type);
-       else if (fsp->is_stat)
+       } else if (fsp->is_stat) {
                return close_stat(fsp);
-       else if (fsp->fake_file_handle != NULL)
+       } else if (fsp->fake_file_handle != NULL) {
                return close_fake_file(fsp);
-       else
-               return close_normal_file(fsp, close_type);
+       }
+       return close_normal_file(fsp, close_type);
 }
index 98356882aa42144b4efc8c21ef9f9b78dae56440..9f0350fe6dfa0bb6bd6f968466164e9569f4ec1e 100644 (file)
@@ -884,6 +884,7 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S
                        FILE_SHARE_READ|FILE_SHARE_WRITE,
                        FILE_OPEN,
                        0, /* no create options. */
+                       FILE_ATTRIBUTE_DIRECTORY,
                        NULL, &fsp);
        } else {
                status = open_file_stat(conn, name, pst, &fsp);
index 7c5eeae5c7d2d19f15d6c32dfeeb82ace7b1dee9..208b3256673bfafda859c951ec2f8f98301e4834 100644 (file)
@@ -160,8 +160,8 @@ void destroy_fake_file_handle(FAKE_FILE_HANDLE **fh)
        (*fh) = NULL;
 }
 
-int close_fake_file(files_struct *fsp)
+NTSTATUS close_fake_file(files_struct *fsp)
 {
        file_free(fsp);
-       return 0;
+       return NT_STATUS_OK;
 }
index 543f393c898b593ee3a4fa31e7b1f7c9affbce99..19710d1dcdd0e0d60591f87c7ea9bb38e0eeb7b9 100644 (file)
@@ -281,10 +281,10 @@ static BOOL saved_short_case_preserve;
  Save case semantics.
 ****************************************************************************/
 
-static void set_posix_case_semantics(connection_struct *conn, uint32 file_attributes)
+static uint32 set_posix_case_semantics(connection_struct *conn, uint32 file_attributes)
 {
        if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
-               return;
+               return file_attributes;
        }
 
        saved_case_sensitive = conn->case_sensitive;
@@ -295,6 +295,8 @@ static void set_posix_case_semantics(connection_struct *conn, uint32 file_attrib
        conn->case_sensitive = True;
        conn->case_preserve = True;
        conn->short_case_preserve = True;
+
+       return (file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
 }
 
 /****************************************************************************
@@ -455,6 +457,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
        uint32 flags = IVAL(inbuf,smb_ntcreate_Flags);
        uint32 access_mask = IVAL(inbuf,smb_ntcreate_DesiredAccess);
        uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes);
+       uint32 new_file_attributes;
        uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess);
        uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition);
        uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions);
@@ -625,7 +628,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
         * Check if POSIX semantics are wanted.
         */
                
-       set_posix_case_semantics(conn, file_attributes);
+       new_file_attributes = set_posix_case_semantics(conn, file_attributes);
                
        status = unix_convert(conn, fname, False, NULL, &sbuf);
        if (!NT_STATUS_IS_OK(status)) {
@@ -679,6 +682,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
                                        share_access,
                                        create_disposition,
                                        create_options,
+                                       new_file_attributes,
                                        &info, &fsp);
 
                restore_case_semantics(conn, file_attributes);
@@ -714,7 +718,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
                                        share_access,
                                        create_disposition,
                                        create_options,
-                                       file_attributes,
+                                       new_file_attributes,
                                        oplock_request,
                                        &info, &fsp);
                if (!NT_STATUS_IS_OK(status)) { 
@@ -756,6 +760,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
                                                        share_access,
                                                        create_disposition,
                                                        create_options,
+                                                       new_file_attributes,
                                                        &info, &fsp);
 
                                if(!NT_STATUS_IS_OK(status)) {
@@ -1096,6 +1101,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
        uint32 flags;
        uint32 access_mask;
        uint32 file_attributes;
+       uint32 new_file_attributes;
        uint32 share_access;
        uint32 create_disposition;
        uint32 create_options;
@@ -1252,7 +1258,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
         * Check if POSIX semantics are wanted.
         */
 
-       set_posix_case_semantics(conn, file_attributes);
+       new_file_attributes = set_posix_case_semantics(conn, file_attributes);
     
        RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
@@ -1324,6 +1330,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                                        share_access,
                                        create_disposition,
                                        create_options,
+                                       new_file_attributes,
                                        &info, &fsp);
                if(!NT_STATUS_IS_OK(status)) {
                        restore_case_semantics(conn, file_attributes);
@@ -1341,7 +1348,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                                        share_access,
                                        create_disposition,
                                        create_options,
-                                       file_attributes,
+                                       new_file_attributes,
                                        oplock_request,
                                        &info, &fsp);
 
@@ -1364,6 +1371,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                                                        share_access,
                                                        create_disposition,
                                                        create_options,
+                                                       new_file_attributes,
                                                        &info, &fsp);
                                if(!NT_STATUS_IS_OK(status)) {
                                        restore_case_semantics(conn, file_attributes);
@@ -1570,7 +1578,6 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
        uint32 fattr;
        int info;
        SMB_OFF_T ret=-1;
-       int close_ret;
        NTSTATUS status = NT_STATUS_OK;
 
        ZERO_STRUCT(sbuf1);
@@ -1670,7 +1677,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
        /* Ensure the modtime is set correctly on the destination file. */
        fsp_set_pending_modtime(fsp2, sbuf1.st_mtime);
 
-       close_ret = close_file(fsp2,NORMAL_CLOSE);
+       status = close_file(fsp2,NORMAL_CLOSE);
 
        /* Grrr. We have to do this as open_file_ntcreate adds aARCH when it
           creates the file. This isn't the correct thing to do in the copy
@@ -1682,8 +1689,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
                return NT_STATUS_DISK_FULL;
        }
 
-       if (close_ret != 0) {
-               status = map_nt_error_from_unix(close_ret);
+       if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
                        nt_errstr(status), oldname, newname));
        }
index 2415433fe9f24df1596e5e512afb7062c3734935..c9e29cf0e5a6dfcc5195aaa2c6dab42c9501da4a 100644 (file)
@@ -67,14 +67,13 @@ static BOOL fd_open(struct connection_struct *conn,
  Close the file associated with a fsp.
 ****************************************************************************/
 
-int fd_close(struct connection_struct *conn,
-            files_struct *fsp)
+NTSTATUS fd_close(struct connection_struct *conn, files_struct *fsp)
 {
        if (fsp->fh->fd == -1) {
-               return 0; /* What we used to call a stat open. */
+               return NT_STATUS_OK; /* What we used to call a stat open. */
        }
        if (fsp->fh->ref_count > 1) {
-               return 0; /* Shared handle. Only close last reference. */
+               return NT_STATUS_OK; /* Shared handle. Only close last reference. */
        }
        return fd_close_posix(conn, fsp);
 }
@@ -1118,6 +1117,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        int flags2=0;
        BOOL file_existed = VALID_STAT(*psbuf);
        BOOL def_acl = False;
+       BOOL posix_open = False;
        SMB_DEV_T dev = 0;
        SMB_INO_T inode = 0;
        NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
@@ -1156,10 +1156,16 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return NT_STATUS_NO_MEMORY;
        }
 
-       /* 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);
+       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, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x "
                   "access_mask=0x%x share_access=0x%x "
@@ -1197,9 +1203,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return status;
        } 
 
-       new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
-       if (file_existed) {
-               existing_dos_attributes = dos_mode(conn, fname, psbuf);
+       if (!posix_open) {
+               new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
+               if (file_existed) {
+                       existing_dos_attributes = dos_mode(conn, fname, psbuf);
+               }
        }
 
        /* ignore any oplock requests if oplocks are disabled */
@@ -1294,7 +1302,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        /* We only care about matching attributes on file exists and
         * overwrite. */
 
-       if (file_existed && ((create_disposition == FILE_OVERWRITE) ||
+       if (!posix_open && file_existed && ((create_disposition == FILE_OVERWRITE) ||
                             (create_disposition == FILE_OVERWRITE_IF))) {
                if (!open_match_attributes(conn, fname,
                                           existing_dos_attributes,
@@ -1359,7 +1367,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 #endif /* O_SYNC */
   
-       if (!CAN_WRITE(conn)) {
+       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
@@ -1393,6 +1405,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        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);
 
@@ -1769,9 +1783,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                /* Files should be initially set as archive */
                if (lp_map_archive(SNUM(conn)) ||
                    lp_store_dos_attributes(SNUM(conn))) {
-                       file_set_dosmode(conn, fname,
+                       if (!posix_open) {
+                               file_set_dosmode(conn, fname,
                                         new_dos_attributes | aARCH, NULL,
                                         parent_dir);
+                       }
                }
        }
 
@@ -1780,7 +1796,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         * selected.
         */
 
-       if (!file_existed && !def_acl) {
+       if (!posix_open && !file_existed && !def_acl) {
 
                int saved_errno = errno; /* We might get ENOSYS in the next
                                          * call.. */
@@ -1873,15 +1889,17 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
  Close the fchmod file fd - ensure no locks are lost.
 ****************************************************************************/
 
-int close_file_fchmod(files_struct *fsp)
+NTSTATUS close_file_fchmod(files_struct *fsp)
 {
-       int ret = fd_close(fsp->conn, fsp);
+       NTSTATUS status = fd_close(fsp->conn, fsp);
        file_free(fsp);
-       return ret;
+       return status;
 }
 
-static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
-                              SMB_STRUCT_STAT *psbuf)
+static NTSTATUS mkdir_internal(connection_struct *conn,
+                               const char *name,
+                               uint32 file_attributes,
+                               SMB_STRUCT_STAT *psbuf)
 {
        int ret= -1;
        mode_t mode;
@@ -1905,7 +1923,11 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                return NT_STATUS_NO_MEMORY;
        }
 
-       mode = unix_mode(conn, aDIR, name, parent_dir);
+       if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
+       } else {
+               mode = unix_mode(conn, aDIR, name, parent_dir);
+       }
 
        if ((ret=SMB_VFS_MKDIR(conn, name, mode)) != 0) {
                return map_nt_error_from_unix(errno);
@@ -1930,15 +1952,17 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                inherit_access_acl(conn, parent_dir, name, mode);
        }
 
-       /*
-        * 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, name,
-                             psbuf->st_mode | (mode & ~psbuf->st_mode));
+       if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
+               /*
+                * 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, name,
+                                     psbuf->st_mode | (mode & ~psbuf->st_mode));
+               }
        }
 
        /* Change the owner if required. */
@@ -1963,6 +1987,7 @@ NTSTATUS open_directory(connection_struct *conn,
                        uint32 share_access,
                        uint32 create_disposition,
                        uint32 create_options,
+                       uint32 file_attributes,
                        int *pinfo,
                        files_struct **result)
 {
@@ -1974,12 +1999,13 @@ NTSTATUS open_directory(connection_struct *conn,
 
        DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, "
                 "share_access = 0x%x create_options = 0x%x, "
-                "create_disposition = 0x%x\n",
+                "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)create_disposition,
+                (unsigned int)file_attributes));
 
        if (is_ntfs_stream_name(fname)) {
                DEBUG(0,("open_directory: %s is a stream name!\n", fname ));
@@ -2006,7 +2032,11 @@ NTSTATUS open_directory(connection_struct *conn,
                        /* If directory exists error. If directory doesn't
                         * exist create. */
 
-                       status = mkdir_internal(conn, fname, psbuf);
+                       status = mkdir_internal(conn,
+                                               fname,
+                                               file_attributes,
+                                               psbuf);
+
                        if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(2, ("open_directory: unable to create "
                                          "%s. Error was %s\n", fname,
@@ -2023,7 +2053,10 @@ NTSTATUS open_directory(connection_struct *conn,
                         * exist create.
                         */
 
-                       status = mkdir_internal(conn, fname, psbuf);
+                       status = mkdir_internal(conn,
+                                               fname,
+                                               file_attributes,
+                                               psbuf);
 
                        if (NT_STATUS_IS_OK(status)) {
                                info = FILE_WAS_CREATED;
@@ -2081,6 +2114,8 @@ NTSTATUS open_directory(connection_struct *conn,
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = True;
        fsp->is_stat = False;
+       fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False;
+
        string_set(&fsp->fsp_name,fname);
 
        lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode,
@@ -2145,7 +2180,11 @@ NTSTATUS create_directory(connection_struct *conn, const char *directory)
        status = open_directory(conn, directory, &sbuf,
                                FILE_READ_ATTRIBUTES, /* Just a stat open */
                                FILE_SHARE_NONE, /* Ignored for stat opens */
-                               FILE_CREATE, 0, NULL, &fsp);
+                               FILE_CREATE,
+                               0,
+                               FILE_ATTRIBUTE_DIRECTORY,
+                               NULL,
+                               &fsp);
 
        if (NT_STATUS_IS_OK(status)) {
                close_file(fsp, NORMAL_CLOSE);
index 7b82a9ad9c8cff30b7a5ecd400d1dd2fbffe6b4d..423d6b3a9991a5a9b0210b72d2830645cf394e8e 100644 (file)
@@ -832,6 +832,7 @@ void share_mode_entry_to_message(char *msg, struct share_mode_entry *e)
        SINO_T_VAL(msg,36,e->inode);
        SIVAL(msg,44,e->share_file_id);
        SIVAL(msg,48,e->uid);
+       SSVAL(msg,52,e->flags);
 }
 
 /****************************************************************************
@@ -852,6 +853,7 @@ void message_to_share_mode_entry(struct share_mode_entry *e, char *msg)
        e->inode = INO_T_VAL(msg,36);
        e->share_file_id = (unsigned long)IVAL(msg,44);
        e->uid = (uint32)IVAL(msg,48);
+       e->flags = (uint16)SVAL(msg,52);
 }
 
 /****************************************************************************
index 655d78cd246672e3e17a7f155b5993bb3b1d0a13..8bccd45f4bd44f7a132695be016388ec808c5dc2 100644 (file)
@@ -3108,9 +3108,9 @@ int reply_exit(connection_struct *conn,
 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 int dum_buffsize)
 {
+       NTSTATUS status = NT_STATUS_OK;
        int outsize = 0;
        time_t mtime;
-       int32 eclass = 0, err = 0;
        files_struct *fsp = NULL;
        START_PROFILE(SMBclose);
 
@@ -3138,12 +3138,11 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * Special case - close NT SMB directory handle.
                 */
                DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
-               close_file(fsp,NORMAL_CLOSE);
+               status = close_file(fsp,NORMAL_CLOSE);
        } else {
                /*
                 * Close ordinary file.
                 */
-               int close_err;
 
                DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
                         fsp->fh->fd, fsp->fnum,
@@ -3162,17 +3161,12 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * a disk full error. If not then it was probably an I/O error.
                 */
  
-               if((close_err = close_file(fsp,NORMAL_CLOSE)) != 0) {
-                       errno = close_err;
-                       END_PROFILE(SMBclose);
-                       return (UNIXERROR(ERRHRD,ERRgeneral));
-               }
+               status = close_file(fsp,NORMAL_CLOSE);
        }  
 
-       /* We have a cached error */
-       if(eclass || err) {
+       if(!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBclose);
-               return ERROR_DOS(eclass,err);
+               return ERROR_NT(status);
        }
 
        END_PROFILE(SMBclose);
@@ -3189,7 +3183,7 @@ int reply_writeclose(connection_struct *conn,
        size_t numtowrite;
        ssize_t nwritten = -1;
        int outsize = 0;
-       int close_err = 0;
+       NTSTATUS close_status = NT_STATUS_OK;
        SMB_OFF_T startpos;
        char *data;
        time_t mtime;
@@ -3223,7 +3217,7 @@ int reply_writeclose(connection_struct *conn,
        if (numtowrite) {
                DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
                        fsp->fsp_name ));
-               close_err = close_file(fsp,NORMAL_CLOSE);
+               close_status = close_file(fsp,NORMAL_CLOSE);
        }
 
        DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
@@ -3235,10 +3229,9 @@ int reply_writeclose(connection_struct *conn,
                return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
  
-       if(close_err != 0) {
-               errno = close_err;
+       if(!NT_STATUS_IS_OK(close_status)) {
                END_PROFILE(SMBwriteclose);
-               return(UNIXERROR(ERRHRD,ERRgeneral));
+               return ERROR_NT(close_status);
        }
  
        outsize = set_message(outbuf,1,0,True);
@@ -3455,7 +3448,7 @@ int reply_printclose(connection_struct *conn,
 {
        int outsize = set_message(outbuf,0,0,False);
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-       int close_err = 0;
+       NTSTATUS status;
        START_PROFILE(SMBsplclose);
 
        CHECK_FSP(fsp,conn);
@@ -3468,12 +3461,11 @@ int reply_printclose(connection_struct *conn,
        DEBUG(3,("printclose fd=%d fnum=%d\n",
                 fsp->fh->fd,fsp->fnum));
   
-       close_err = close_file(fsp,NORMAL_CLOSE);
+       status = close_file(fsp,NORMAL_CLOSE);
 
-       if(close_err != 0) {
-               errno = close_err;
+       if(!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBsplclose);
-               return(UNIXERROR(ERRHRD,ERRgeneral));
+               return ERROR_NT(status);
        }
 
        END_PROFILE(SMBsplclose);
@@ -3707,7 +3699,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
  The internals of the rmdir code - called elsewhere.
 ****************************************************************************/
 
-BOOL rmdir_internals(connection_struct *conn, const char *directory)
+NTSTATUS rmdir_internals(connection_struct *conn, const char *directory)
 {
        int ret;
        SMB_STRUCT_STAT st;
@@ -3717,7 +3709,7 @@ BOOL rmdir_internals(connection_struct *conn, const char *directory)
                notify_fname(conn, NOTIFY_ACTION_REMOVED,
                             FILE_NOTIFY_CHANGE_DIR_NAME,
                             directory);
-               return True;
+               return NT_STATUS_OK;
        }
 
        if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
@@ -3791,14 +3783,14 @@ BOOL rmdir_internals(connection_struct *conn, const char *directory)
        if (ret != 0) {
                DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
                         "%s\n", directory,strerror(errno)));
-               return False;
+               return map_nt_error_from_unix(errno);
        }
 
        notify_fname(conn, NOTIFY_ACTION_REMOVED,
                     FILE_NOTIFY_CHANGE_DIR_NAME,
                     directory);
 
-       return True;
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -3834,9 +3826,10 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        }
 
        dptr_closepath(directory,SVAL(inbuf,smb_pid));
-       if (!rmdir_internals(conn, directory)) {
+       status = rmdir_internals(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBrmdir);
-               return UNIXERROR(ERRDOS, ERRbadpath);
+               return ERROR_NT(status);
        }
  
        outsize = set_message(outbuf,0,0,False);
@@ -4585,7 +4578,6 @@ NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun,
        uint32 dosattrs;
        uint32 new_create_disposition;
        NTSTATUS status;
-       int close_err;
  
        pstrcpy(dest,dest1);
        if (target_is_directory) {
@@ -4670,10 +4662,10 @@ NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun,
         * Thus we don't look at the error return from the
         * close of fsp1.
         */
-       close_err = close_file(fsp2,NORMAL_CLOSE);
+       status = close_file(fsp2,NORMAL_CLOSE);
 
-       if (close_err != 0) {
-               return map_nt_error_from_unix(close_err);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        if (ret != (SMB_OFF_T)src_sbuf.st_size) {
index 039411340870cc67ec7dbc86eefbf08704addbce..d85ed9877dcb80261425dccbbdc7e40704c8cd11 100644 (file)
@@ -2529,7 +2529,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        SBIG_UINT(pdata,4,((SMB_BIG_UINT)(
                                        CIFS_UNIX_POSIX_ACLS_CAP|
                                        CIFS_UNIX_POSIX_PATHNAMES_CAP|
-                                       CIFS_UNIX_FCNTL_LOCKS_CAP)));
+                                       CIFS_UNIX_FCNTL_LOCKS_CAP|
+                                       CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
                        break;
 
                case SMB_QUERY_POSIX_FS_INFO:
@@ -2646,8 +2647,14 @@ cap_low = 0x%x, cap_high = 0x%x\n",
                                        mangle_change_to_posix();
                                }
 
-                               if (client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) {
-                                       lp_set_posix_cifsx_locktype(POSIX_LOCK);
+                               if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
+                                   !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
+                                       /* Client that knows how to do posix locks,
+                                        * but not posix open/mkdir operations. Set a
+                                        * default type for read/write checks. */
+
+                                       lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
+
                                }
                                break;
                        }
@@ -4845,6 +4852,246 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                tvs);
 }
 
+/****************************************************************************
+ Create a directory with POSIX semantics.
+****************************************************************************/
+
+static NTSTATUS smb_posix_mkdir(connection_struct *conn,
+                               const char *pdata,
+                               int total_data,
+                               const char *fname)
+{
+       NTSTATUS status;
+       SMB_STRUCT_STAT sbuf;
+       uint32 raw_unixmode;
+       uint32 mod_unixmode;
+       mode_t unixmode;
+       files_struct *fsp;
+
+       if (total_data < 10) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       ZERO_STRUCT(sbuf);
+
+       raw_unixmode = IVAL(pdata,8);
+       status = unix_perms_from_wire(conn, &sbuf, raw_unixmode, PERM_NEW_DIR, &unixmode);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+
+       status = open_directory(conn,
+                               fname,
+                               &sbuf,
+                               FILE_READ_ATTRIBUTES, /* Just a stat open */
+                               FILE_SHARE_NONE, /* Ignored for stat opens */
+                               FILE_CREATE,
+                               0,
+                               mod_unixmode,
+                               NULL,
+                               &fsp);
+
+        if (NT_STATUS_IS_OK(status)) {
+                close_file(fsp, NORMAL_CLOSE);
+        }
+       return status;
+}
+
+/****************************************************************************
+ Open/Create a file with POSIX semantics.
+****************************************************************************/
+
+static NTSTATUS smb_posix_open(connection_struct *conn,
+                               char **ppdata,
+                               int total_data,
+                               const char *fname,
+                               SMB_STRUCT_STAT *psbuf,
+                               int *pdata_return_size)
+{
+       BOOL extended_oplock_granted = False;
+       const char *pdata = *ppdata;
+       uint32 flags = 0;
+       uint32 wire_open_mode = 0;
+       uint32 raw_unixmode = 0;
+       uint32 mod_unixmode = 0;
+       uint32 create_disp = 0;
+       uint32 access_mask = 0;
+       uint32 create_options = 0;
+       NTSTATUS status = NT_STATUS_OK;
+       mode_t unixmode = (mode_t)0;
+       files_struct *fsp = NULL;
+       int oplock_request = 0;
+       int info = 0;
+
+       if (total_data < 14) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       flags = IVAL(pdata,0);
+       oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+       if (oplock_request) {
+               oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+       }
+
+       wire_open_mode = IVAL(pdata,4);
+
+       if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
+               return smb_posix_mkdir(conn, pdata, total_data, fname);
+       }
+
+       switch (wire_open_mode & SMB_ACCMODE) {
+               case SMB_O_RDONLY:
+                       access_mask = FILE_READ_DATA;
+                       break;
+               case SMB_O_WRONLY:
+                       access_mask = FILE_WRITE_DATA;
+                       break;
+               case SMB_O_RDWR:
+                       access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
+                       break;
+               default:
+                       DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
+                               (unsigned int)wire_open_mode ));
+                       return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       wire_open_mode &= ~SMB_ACCMODE;
+
+       if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
+               create_disp = FILE_CREATE;
+       } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
+               create_disp = FILE_OVERWRITE_IF;
+       } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
+               create_disp = FILE_OPEN_IF;
+       } else {
+               DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
+                       (unsigned int)wire_open_mode ));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       raw_unixmode = IVAL(pdata,8);
+       status = unix_perms_from_wire(conn,
+                               psbuf,
+                               raw_unixmode,
+                               VALID_STAT(*psbuf) ? PERM_EXISTING_FILE : PERM_NEW_FILE,
+                               &unixmode);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+
+       if (wire_open_mode & SMB_O_SYNC) {
+               create_options |= FILE_WRITE_THROUGH;
+       }
+       if (wire_open_mode & SMB_O_APPEND) {
+               access_mask |= FILE_APPEND_DATA;
+       }
+       if (wire_open_mode & SMB_O_DIRECT) {
+               mod_unixmode |= FILE_FLAG_NO_BUFFERING;
+       }
+
+       status = open_file_ntcreate(conn,
+                               fname,
+                               psbuf,
+                               access_mask,
+                               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                               create_disp,
+                               0,              /* no create options yet. */
+                               mod_unixmode,
+                               oplock_request,
+                               &info,
+                               &fsp);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+               extended_oplock_granted = True;
+       }
+
+       if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+               extended_oplock_granted = True;
+       }
+
+       *pdata_return_size = 6;
+       /* Realloc the data size */
+       *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
+       if (*ppdata == NULL) {
+               close_file(fsp,ERROR_CLOSE);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (extended_oplock_granted) {
+               if (flags & REQUEST_BATCH_OPLOCK) {
+                       SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
+               } else {
+                       SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
+               }
+       } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
+               SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
+       } else {
+               SSVAL(pdata,0,NO_OPLOCK_RETURN);
+       }
+
+       SSVAL(pdata,2,fsp->fnum);
+       SSVAL(pdata,4,SMB_NO_INFO_LEVEL_RETURNED);
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Delete a file with POSIX semantics.
+****************************************************************************/
+
+static NTSTATUS smb_posix_unlink(connection_struct *conn,
+                               const char *pdata,
+                               int total_data,
+                               const char *fname,
+                               SMB_STRUCT_STAT *psbuf)
+{
+       NTSTATUS status = NT_STATUS_OK;
+       files_struct *fsp = NULL;
+       int info = 0;
+
+       if (!VALID_STAT(*psbuf)) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       if (VALID_STAT_OF_DIR(*psbuf)) {
+               status = open_directory(conn,
+                                       fname,
+                                       psbuf,
+                                       DELETE_ACCESS,
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                                       FILE_OPEN,
+                                       FILE_DELETE_ON_CLOSE,
+                                       FILE_FLAG_POSIX_SEMANTICS|0777,
+                                       &info,                          
+                                       &fsp);
+       } else {
+               status = open_file_ntcreate(conn,
+                               fname,
+                               psbuf,
+                               DELETE_ACCESS,
+                               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                               FILE_OPEN,
+                               FILE_DELETE_ON_CLOSE,
+                               FILE_FLAG_POSIX_SEMANTICS|0777,
+                               INTERNAL_OPEN_ONLY,
+                               &info,
+                               &fsp);
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       return close_file(fsp, NORMAL_CLOSE);
+}
+
 /****************************************************************************
  Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
 ****************************************************************************/
@@ -4861,6 +5108,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
        pstring fname;
        files_struct *fsp = NULL;
        NTSTATUS status = NT_STATUS_OK;
+       int data_return_size = 0;
 
        if (!params) {
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
@@ -5148,6 +5396,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
 
                case SMB_SET_POSIX_LOCK:
                {
+                       if (tran_call == TRANSACT2_SETFILEINFO) {
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                       }
                        status = smb_set_posix_lock(conn,
                                                inbuf,
                                                length,
@@ -5157,6 +5408,37 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
                        break;
                }
 
+               case SMB_POSIX_PATH_OPEN:
+               {
+                       if (tran_call != TRANSACT2_SETPATHINFO) {
+                               /* We must have a pathname for this. */
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                       }
+
+                       status = smb_posix_open(conn,
+                                               ppdata,
+                                               total_data,
+                                               fname,
+                                               &sbuf,
+                                               &data_return_size);
+                       break;
+               }
+
+               case SMB_POSIX_PATH_UNLINK:
+               {
+                       if (tran_call != TRANSACT2_SETPATHINFO) {
+                               /* We must have a pathname for this. */
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                       }
+
+                       status = smb_posix_unlink(conn,
+                                               pdata,
+                                               total_data,
+                                               fname,
+                                               &sbuf);
+                       break;
+               }
+
                default:
                        return ERROR_NT(NT_STATUS_INVALID_LEVEL);
        }
@@ -5178,7 +5460,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
        }
 
        SSVAL(params,0,0);
-       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, data_return_size, max_data_bytes);
   
        return -1;
 }