From 7a5fa7f12ec439ef5a4af29aa86498f799b6b9a5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 6 Feb 2007 21:05:34 +0000 Subject: r21191: Add in the POSIX open/mkdir/unlink calls. 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. (This used to be commit 83dbbdff345fa9e427c9579183f4380004bf3dd7) --- source3/include/smb.h | 27 ++-- source3/include/trans2.h | 43 +++++- source3/libsmb/smb_share_modes.c | 1 + source3/locking/locking.c | 9 +- source3/locking/posix.c | 14 +- source3/param/loadparm.c | 12 +- source3/rpc_server/srv_srvsvc_nt.c | 2 + source3/smbd/close.c | 111 +++++++------- source3/smbd/dir.c | 1 + source3/smbd/fake_file.c | 4 +- source3/smbd/nttrans.c | 26 ++-- source3/smbd/open.c | 109 +++++++++----- source3/smbd/oplock.c | 2 + source3/smbd/reply.c | 54 +++---- source3/smbd/trans2.c | 290 ++++++++++++++++++++++++++++++++++++- 15 files changed, 545 insertions(+), 160 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index 71ff656385..7bc5c0a414 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -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) diff --git a/source3/include/trans2.h b/source3/include/trans2.h index 92c5a2e963..44e85d8489 100644 --- a/source3/include/trans2.h +++ b/source3/include/trans2.h @@ -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 diff --git a/source3/libsmb/smb_share_modes.c b/source3/libsmb/smb_share_modes.c index b8c7a7e66b..4c49ecb7bd 100644 --- a/source3/libsmb/smb_share_modes.c +++ b/source3/libsmb/smb_share_modes.c @@ -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; } /* diff --git a/source3/locking/locking.c b/source3/locking/locking.c index d2e8b7ef59..39cc991b5f 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -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, diff --git a/source3/locking/posix.c b/source3/locking/posix.c index 806018da81..62804eb8e3 100644 --- a/source3/locking/posix.c +++ b/source3/locking/posix.c @@ -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; } /**************************************************************************** diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index f7dd30475a..d7b23f615f 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -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; } diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index c0953f2723..005c57e50a 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -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)) { diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 714e0615de..05a45cc14f 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -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; inum_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; inum_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); } diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 98356882aa..9f0350fe6d 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -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); diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c index 7c5eeae5c7..208b325667 100644 --- a/source3/smbd/fake_file.c +++ b/source3/smbd/fake_file.c @@ -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; } diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 543f393c89..19710d1dcd 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -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)); } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 2415433fe9..c9e29cf0e5 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -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); diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 7b82a9ad9c..423d6b3a99 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -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); } /**************************************************************************** diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 655d78cd24..8bccd45f4b 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -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) { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 0394113408..d85ed9877d 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -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; } -- cgit