summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-02-06 21:05:34 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:17:47 -0500
commit7a5fa7f12ec439ef5a4af29aa86498f799b6b9a5 (patch)
tree611c3787938bb8eb77a127a18a4932890ae2fd03 /source3/smbd
parentc04068a42b230541559939004f33d72f1e76f075 (diff)
downloadsamba-7a5fa7f12ec439ef5a4af29aa86498f799b6b9a5.tar.gz
samba-7a5fa7f12ec439ef5a4af29aa86498f799b6b9a5.tar.bz2
samba-7a5fa7f12ec439ef5a4af29aa86498f799b6b9a5.zip
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)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/close.c111
-rw-r--r--source3/smbd/dir.c1
-rw-r--r--source3/smbd/fake_file.c4
-rw-r--r--source3/smbd/nttrans.c26
-rw-r--r--source3/smbd/open.c109
-rw-r--r--source3/smbd/oplock.c2
-rw-r--r--source3/smbd/reply.c54
-rw-r--r--source3/smbd/trans2.c290
8 files changed, 460 insertions, 137 deletions
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; i<lck->num_share_modes; i++) {
- if (is_valid_share_mode_entry(&lck->share_modes[i])) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if (is_valid_share_mode_entry(e)) {
+ if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+ continue;
+ }
delete_file = False;
break;
}
@@ -282,12 +285,10 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
fsp->fsp_name, strerror(errno) ));
status = map_nt_error_from_unix(errno);
- goto done;
}
- status = NT_STATUS_FILE_DELETED;
-
done:
+
/* unbecome user. */
pop_sec_ctx();
@@ -303,12 +304,13 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
delete on close is done on normal and shutdown close.
****************************************************************************/
-static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
+static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_type)
{
+ NTSTATUS status = NT_STATUS_OK;
+ NTSTATUS saved_status1 = NT_STATUS_OK;
+ NTSTATUS saved_status2 = NT_STATUS_OK;
+ NTSTATUS saved_status3 = NT_STATUS_OK;
connection_struct *conn = fsp->conn;
- int saved_errno = 0;
- int err = 0;
- int err1 = 0;
if (fsp->aio_write_behind) {
/*
@@ -317,8 +319,7 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
*/
int ret = wait_for_aio_completion(fsp);
if (ret) {
- saved_errno = ret;
- err1 = -1;
+ saved_status1 = map_nt_error_from_unix(ret);
}
} else {
cancel_aio_by_fsp(fsp);
@@ -329,15 +330,12 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
* error here, we must remember this.
*/
- if (close_filestruct(fsp) == -1) {
- saved_errno = errno;
- err1 = -1;
- }
+ saved_status2 = close_filestruct(fsp);
if (fsp->print_file) {
print_fsp_end(fsp, close_type);
file_free(fsp);
- return 0;
+ return NT_STATUS_OK;
}
/* If this is an old DOS or FCB open and we have multiple opens on
@@ -346,7 +344,7 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
if (fsp->fh->ref_count == 1) {
/* Should we return on error here... ? */
- close_remove_share_mode(fsp, close_type);
+ saved_status3 = close_remove_share_mode(fsp, close_type);
}
if(fsp->oplock_type) {
@@ -355,13 +353,7 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
locking_close_file(fsp);
- err = fd_close(conn, fsp);
-
- /* Only save errno if fd_close failed and we don't already
- have an errno saved from a flush call. */
- if ((err1 != -1) && (err == -1)) {
- saved_errno = errno;
- }
+ status = fd_close(conn, fsp);
/* check for magic scripts */
if (close_type == NORMAL_CLOSE) {
@@ -378,29 +370,34 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
set_filetime(conn, fsp->fsp_name, fsp->last_write_time);
}
+ if (NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_IS_OK(saved_status1)) {
+ status = saved_status1;
+ } else if (!NT_STATUS_IS_OK(saved_status2)) {
+ status = saved_status2;
+ } else if (!NT_STATUS_IS_OK(saved_status3)) {
+ status = saved_status3;
+ }
+ }
+
DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
conn->user,fsp->fsp_name,
conn->num_files_open,
- (err == -1 || err1 == -1) ? strerror(saved_errno) : ""));
+ nt_errstr(status) ));
file_free(fsp);
-
- if (err == -1 || err1 == -1) {
- errno = saved_errno;
- return saved_errno;
- } else {
- return 0;
- }
+ return status;
}
/****************************************************************************
Close a directory opened by an NT SMB call.
****************************************************************************/
-static int close_directory(files_struct *fsp, enum file_close_type close_type)
+static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_type)
{
struct share_mode_lock *lck = 0;
BOOL delete_dir = False;
+ NTSTATUS status = NT_STATUS_OK;
/*
* NT can set delete_on_close of the last open
@@ -411,7 +408,7 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
if (lck == NULL) {
DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name));
- return EINVAL;
+ return NT_STATUS_INVALID_PARAMETER;
}
if (!del_share_mode(lck, fsp)) {
@@ -441,9 +438,13 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
if (delete_dir) {
int i;
/* See if others still have the dir open. If this is the
- * case, then don't delete */
+ * case, then don't delete. If all opens are POSIX delete now. */
for (i=0; i<lck->num_share_modes; i++) {
- if (is_valid_share_mode_entry(&lck->share_modes[i])) {
+ struct share_mode_entry *e = &lck->share_modes[i];
+ if (is_valid_share_mode_entry(e)) {
+ if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+ continue;
+ }
delete_dir = False;
break;
}
@@ -469,7 +470,7 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
TALLOC_FREE(lck);
- ok = rmdir_internals(fsp->conn, fsp->fsp_name);
+ status = rmdir_internals(fsp->conn, fsp->fsp_name);
DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n",
fsp->fsp_name, ok ? "succeeded" : "failed" ));
@@ -482,7 +483,7 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
* now fail as the directory has been deleted.
*/
- if(ok) {
+ if(NT_STATUS_IS_OK(status)) {
remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
}
} else {
@@ -496,35 +497,35 @@ static int close_directory(files_struct *fsp, enum file_close_type close_type)
*/
close_filestruct(fsp);
file_free(fsp);
- return 0;
+ return status;
}
/****************************************************************************
Close a 'stat file' opened internally.
****************************************************************************/
-static int close_stat(files_struct *fsp)
+NTSTATUS close_stat(files_struct *fsp)
{
/*
* Do the code common to files and directories.
*/
close_filestruct(fsp);
file_free(fsp);
- return 0;
+ return NT_STATUS_OK;
}
/****************************************************************************
Close a files_struct.
****************************************************************************/
-int close_file(files_struct *fsp, enum file_close_type close_type)
+NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type)
{
- if(fsp->is_directory)
+ if(fsp->is_directory) {
return close_directory(fsp, close_type);
- else if (fsp->is_stat)
+ } else if (fsp->is_stat) {
return close_stat(fsp);
- else if (fsp->fake_file_handle != NULL)
+ } else if (fsp->fake_file_handle != NULL) {
return close_fake_file(fsp);
- else
- return close_normal_file(fsp, close_type);
+ }
+ return close_normal_file(fsp, close_type);
}
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;
}
@@ -4846,6 +4853,246 @@ 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,
+ 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;
}