fd support routines - attempt to do a dos_open.
****************************************************************************/
-static BOOL fd_open(struct connection_struct *conn,
+static NTSTATUS fd_open(struct connection_struct *conn,
const char *fname,
files_struct *fsp,
int flags,
mode_t mode)
{
- int sav;
+ NTSTATUS status = NT_STATUS_OK;
#ifdef O_NOFOLLOW
- if (!lp_symlinks(SNUM(conn))) {
+ /*
+ * Never follow symlinks on a POSIX client. The
+ * client should be doing this.
+ */
+
+ if (fsp->posix_open || !lp_symlinks(SNUM(conn))) {
flags |= O_NOFOLLOW;
}
#endif
fsp->fh->fd = SMB_VFS_OPEN(conn,fname,fsp,flags,mode);
- sav = errno;
+ if (fsp->fh->fd == -1) {
+ status = map_nt_error_from_unix(errno);
+ }
DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n",
fname, flags, (int)mode, fsp->fh->fd,
(fsp->fh->fd == -1) ? strerror(errno) : "" ));
- errno = sav;
- return fsp->fh->fd != -1;
+ return status;
}
/****************************************************************************
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);
}
uint32 access_mask, /* client requested access mask. */
uint32 open_access_mask) /* what we're actually using in the open. */
{
+ NTSTATUS status = NT_STATUS_OK;
int accmode = (flags & O_ACCMODE);
int local_flags = flags;
BOOL file_existed = VALID_STAT(*psbuf);
}
/* Actually do the open */
- if (!fd_open(conn, path, fsp, local_flags, unx_mode)) {
+ status = fd_open(conn, path, fsp, local_flags, unx_mode);
+ if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
"(flags=%d)\n",
- path,strerror(errno),local_flags,flags));
- return map_nt_error_from_unix(errno);
+ path,nt_errstr(status),local_flags,flags));
+ return status;
}
if ((local_flags & O_CREAT) && !file_existed) {
fsp);
}
- notify_action(conn, parent_dir, name, -1,
- NOTIFY_ACTION_ADDED);
+ notify_fname(conn, NOTIFY_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME, path);
}
} else {
/* For a non-io open, this stat failing means file not found. JRA */
if (ret == -1) {
- NTSTATUS status = map_nt_error_from_unix(errno);
+ status = map_nt_error_from_unix(errno);
fd_close(conn, fsp);
return status;
}
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = False;
fsp->is_stat = False;
- if (conn->aio_write_behind_list
- && is_in_path(path, conn->aio_write_behind_list,
- conn->case_sensitive)) {
- fsp->aio_write_behind = True;
- }
string_set(&fsp->fsp_name, path);
fsp->wcp = NULL; /* Write cache pointer. */
BOOL valid_entry = False;
BOOL delay_it = False;
BOOL have_level2 = False;
- BOOL ret;
+ NTSTATUS status;
char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
if (oplock_request & INTERNAL_OPEN_ONLY) {
SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
}
- ret = message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST,
- msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
- if (!ret) {
- DEBUG(3, ("Could not send oplock break message\n"));
+ status = messaging_send_buf(smbd_messaging_context(), exclusive->pid,
+ MSG_SMB_BREAK_REQUEST,
+ (uint8 *)msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not send oplock break message: %s\n",
+ nt_errstr(status)));
}
return True;
int flags2=0;
BOOL file_existed = VALID_STAT(*psbuf);
BOOL def_acl = False;
+ BOOL posix_open = False;
+ BOOL new_file_created = False;
SMB_DEV_T dev = 0;
SMB_INO_T inode = 0;
NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
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 "
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 */
/* 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,
}
#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
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);
return NT_STATUS_SHARING_VIOLATION;
}
+ /* First pass - send break only on batch oplocks. */
+ if (delay_for_oplocks(lck, fsp, 1, oplock_request)) {
+ schedule_defer_open(lck, request_time);
+ TALLOC_FREE(lck);
+ fd_close(conn, fsp);
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
status = open_mode_check(conn, fname, lck,
access_mask, share_access,
create_options, &file_existed);
return status;
}
+ if (delay_for_oplocks(lck, fsp, 2, oplock_request)) {
+ schedule_defer_open(lck, request_time);
+ TALLOC_FREE(lck);
+ fd_close(conn, fsp);
+ file_free(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
/*
* We exit this block with the share entry *locked*.....
*/
fsp->oplock_type = NO_OPLOCK;
}
}
- set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type);
- if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
- info == FILE_WAS_SUPERSEDED) {
+ if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) {
+ new_file_created = True;
+ }
- /* Handle strange delete on close create semantics. */
- if (create_options & FILE_DELETE_ON_CLOSE) {
- status = can_set_delete_on_close(fsp, True, new_dos_attributes);
+ set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type, new_file_created);
- if (!NT_STATUS_IS_OK(status)) {
- /* Remember to delete the mode we just added. */
- del_share_mode(lck, fsp);
- TALLOC_FREE(lck);
- fd_close(conn,fsp);
- file_free(fsp);
- return status;
- }
- /* Note that here we set the *inital* delete on close flag,
- not the regular one. The magic gets handled in close. */
- fsp->initial_delete_on_close = True;
+ /* Handle strange delete on close create semantics. */
+ if ((create_options & FILE_DELETE_ON_CLOSE) && can_set_initial_delete_on_close(lck)) {
+ status = can_set_delete_on_close(fsp, True, new_dos_attributes);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Remember to delete the mode we just added. */
+ del_share_mode(lck, fsp);
+ TALLOC_FREE(lck);
+ fd_close(conn,fsp);
+ file_free(fsp);
+ return status;
}
+ /* Note that here we set the *inital* delete on close flag,
+ not the regular one. The magic gets handled in close. */
+ fsp->initial_delete_on_close = True;
+ }
+ if (new_file_created) {
/* 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);
+ }
}
}
* 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.. */
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;
char *parent_dir;
const char *dirname;
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) {
+ if (SMB_VFS_MKDIR(conn, name, mode) != 0) {
return map_nt_error_from_unix(errno);
}
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. */
change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
}
- notify_action(conn, parent_dir, dirname, FILE_NOTIFY_CHANGE_DIR_NAME,
- NOTIFY_ACTION_ADDED);
+ notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME,
+ name);
return NT_STATUS_OK;
}
uint32 share_access,
uint32 create_disposition,
uint32 create_options,
+ uint32 file_attributes,
int *pinfo,
files_struct **result)
{
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 ));
/* 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,
* 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;
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,
return status;
}
- set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK);
+ set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK, True);
/* For directories the delete on close bit at open time seems
always to be honored on close... See test 19 in Samba4 BASE-DELETE. */
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);
smbd process.
****************************************************************************/
-void msg_file_was_renamed(int msg_type, struct process_id src,
- void *buf, size_t len, void *private_data)
+void msg_file_was_renamed(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
{
files_struct *fsp;
- char *frm = (char *)buf;
+ char *frm = (char *)data->data;
SMB_DEV_T dev;
SMB_INO_T inode;
const char *sharepath;
const char *newname;
size_t sp_len;
- if (buf == NULL || len < MSG_FILE_RENAMED_MIN_SIZE + 2) {
- DEBUG(0, ("msg_file_was_renamed: Got invalid msg len %d\n", (int)len));
+ if (data->data == NULL
+ || data->length < MSG_FILE_RENAMED_MIN_SIZE + 2) {
+ DEBUG(0, ("msg_file_was_renamed: Got invalid msg len %d\n",
+ data->length));
return;
}