summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-02-07 01:24:12 +0000
committerJeremy Allison <jra@samba.org>2007-02-07 01:24:12 +0000
commit8f06379b50cfbae62cacf8110fc8a2e47acc489c (patch)
treeb65ff1570e0ef7bc931072ef8e429d19ea49ab24
parent9e9ac60cd354898cd9660834255ad99751b759d6 (diff)
downloadsamba-8f06379b50cfbae62cacf8110fc8a2e47acc489c.tar.gz
samba-8f06379b50cfbae62cacf8110fc8a2e47acc489c.tar.xz
samba-8f06379b50cfbae62cacf8110fc8a2e47acc489c.zip
r21209: Add in the POSIX extensions.
Jeremy.
-rw-r--r--source/include/smb.h27
-rw-r--r--source/include/trans2.h43
-rw-r--r--source/libsmb/smb_share_modes.c1
-rw-r--r--source/locking/locking.c9
-rw-r--r--source/locking/posix.c14
-rw-r--r--source/param/loadparm.c12
-rw-r--r--source/rpc_server/srv_srvsvc_nt.c2
-rw-r--r--source/smbd/close.c111
-rw-r--r--source/smbd/dir.c1
-rw-r--r--source/smbd/fake_file.c4
-rw-r--r--source/smbd/nttrans.c26
-rw-r--r--source/smbd/open.c109
-rw-r--r--source/smbd/oplock.c2
-rw-r--r--source/smbd/reply.c54
-rw-r--r--source/smbd/trans2.c307
15 files changed, 562 insertions, 160 deletions
diff --git a/source/include/smb.h b/source/include/smb.h
index 5eb22d9107f..73f53583aab 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -478,6 +478,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;
@@ -698,6 +699,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;
@@ -714,6 +717,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.
@@ -731,10 +735,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. */
@@ -1532,19 +1537,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/source/include/trans2.h b/source/include/trans2.h
index 92c5a2e963f..44e85d8489a 100644
--- a/source/include/trans2.h
+++ b/source/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/source/libsmb/smb_share_modes.c b/source/libsmb/smb_share_modes.c
index b8c7a7e66b4..4c49ecb7bd9 100644
--- a/source/libsmb/smb_share_modes.c
+++ b/source/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/source/locking/locking.c b/source/locking/locking.c
index d2e8b7ef597..39cc991b5f2 100644
--- a/source/locking/locking.c
+++ b/source/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/source/locking/posix.c b/source/locking/posix.c
index 806018da816..62804eb8e34 100644
--- a/source/locking/posix.c
+++ b/source/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/source/param/loadparm.c b/source/param/loadparm.c
index 32caf06ff63..469976325c0 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -5584,17 +5584,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/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c
index 76ae7fcdc62..b7e63fcce13 100644
--- a/source/rpc_server/srv_srvsvc_nt.c
+++ b/source/rpc_server/srv_srvsvc_nt.c
@@ -1848,6 +1848,7 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
0,
+ FILE_ATTRIBUTE_DIRECTORY,
NULL, &fsp);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1965,6 +1966,7 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
0,
+ FILE_ATTRIBUTE_DIRECTORY,
NULL, &fsp);
if ( !NT_STATUS_IS_OK(nt_status) ) {
diff --git a/source/smbd/close.c b/source/smbd/close.c
index 07f81f988e3..7a1e97c2b6b 100644
--- a/source/smbd/close.c
+++ b/source/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; 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();
@@ -305,12 +306,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) {
/*
@@ -319,8 +321,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);
@@ -331,15 +332,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
@@ -348,7 +346,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) {
@@ -357,13 +355,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) {
@@ -380,29 +372,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
@@ -413,7 +410,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)) {
@@ -443,9 +440,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;
}
@@ -471,7 +472,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" ));
@@ -484,7 +485,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);
remove_pending_change_notify_requests_by_filename(fsp, NT_STATUS_DELETE_PENDING);
@@ -501,35 +502,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/source/smbd/dir.c b/source/smbd/dir.c
index 98356882aa4..9f0350fe6df 100644
--- a/source/smbd/dir.c
+++ b/source/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/source/smbd/fake_file.c b/source/smbd/fake_file.c
index 7c5eeae5c7d..208b3256673 100644
--- a/source/smbd/fake_file.c
+++ b/source/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/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 7afb2a95c16..2eddffb7f16 100644
--- a/source/smbd/nttrans.c
+++ b/source/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/source/smbd/open.c b/source/smbd/open.c
index 8f09d96036a..05023729474 100644
--- a/source/smbd/open.c
+++ b/source/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);
}
@@ -1112,6 +1111,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;
@@ -1150,10 +1150,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 "
@@ -1191,9 +1197,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 */
@@ -1288,7 +1296,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,
@@ -1353,7 +1361,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
@@ -1387,6 +1399,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);
@@ -1762,9 +1776,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);
+ }
}
}
@@ -1773,7 +1789,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.. */
@@ -1866,15 +1882,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;
@@ -1898,7 +1916,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);
@@ -1923,15 +1945,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. */
@@ -1953,6 +1977,7 @@ NTSTATUS open_directory(connection_struct *conn,
uint32 share_access,
uint32 create_disposition,
uint32 create_options,
+ uint32 file_attributes,
int *pinfo,
files_struct **result)
{
@@ -1964,12 +1989,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 ));
@@ -1996,7 +2022,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,
@@ -2013,7 +2043,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;
@@ -2071,6 +2104,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,
@@ -2135,7 +2170,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/source/smbd/oplock.c b/source/smbd/oplock.c
index 427fb7f2450..526b7ced9ec 100644
--- a/source/smbd/oplock.c
+++ b/source/smbd/oplock.c
@@ -826,6 +826,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);
}
/****************************************************************************
@@ -846,6 +847,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/source/smbd/reply.c b/source/smbd/reply.c
index 913f9a18a6c..315b338b0ba 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -3104,9 +3104,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);
@@ -3134,12 +3134,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,
@@ -3158,17 +3157,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);
@@ -3185,7 +3179,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;
@@ -3219,7 +3213,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",
@@ -3231,10 +3225,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);
@@ -3451,7 +3444,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);
@@ -3464,12 +3457,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);
@@ -3703,14 +3695,14 @@ 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;
ret = SMB_VFS_RMDIR(conn,directory);
if (ret == 0) {
- return True;
+ return NT_STATUS_OK;
}
if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
@@ -3784,10 +3776,10 @@ 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);
}
- return True;
+ return NT_STATUS_OK;
}
/****************************************************************************
@@ -3823,9 +3815,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);
@@ -4535,7 +4528,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) {
@@ -4620,10 +4612,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/source/smbd/trans2.c b/source/smbd/trans2.c
index e7f508c6033..1bc15357dec 100644
--- a/source/smbd/trans2.c
+++ b/source/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;
}
@@ -4840,6 +4847,263 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
}
/****************************************************************************
+ Create a directory with POSIX semantics.
+****************************************************************************/
+
+static NTSTATUS smb_posix_mkdir(connection_struct *conn,
+ char **ppdata,
+ int total_data,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ int *pdata_return_size)
+{
+ NTSTATUS status;
+ uint32 raw_unixmode;
+ uint32 mod_unixmode;
+ mode_t unixmode;
+ files_struct *fsp;
+ const char *pdata = *ppdata;
+
+ if (total_data < 10) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ raw_unixmode = IVAL(pdata,8);
+ status = unix_perms_from_wire(conn, psbuf, 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,
+ psbuf,
+ 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);
+ }
+
+ *pdata_return_size = 6;
+ /* Realloc the data size */
+ *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
+ if (*ppdata == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(pdata,0,NO_OPLOCK_RETURN);
+ SSVAL(pdata,2,0);
+ SSVAL(pdata,4,SMB_NO_INFO_LEVEL_RETURNED);
+
+ 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,
+ ppdata,
+ total_data,
+ fname,
+ psbuf,
+ pdata_return_size);
+ }
+
+ 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).
****************************************************************************/
@@ -4855,6 +5119,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);
@@ -5142,6 +5407,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,
@@ -5151,6 +5419,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);
}
@@ -5172,7 +5471,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;
}