summaryrefslogtreecommitdiff
path: root/source3/smbd/open.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2005-07-08 04:51:27 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:58:18 -0500
commitaf8a691db11a5072865f8b03fd1cbd3aab5cb6d7 (patch)
tree0779dd2d2c6d9ea3eae0f094803f6ba3b3c56f24 /source3/smbd/open.c
parent22268d79265d79b8d86d1152a7bfe2ebc8988905 (diff)
downloadsamba-af8a691db11a5072865f8b03fd1cbd3aab5cb6d7.tar.gz
samba-af8a691db11a5072865f8b03fd1cbd3aab5cb6d7.tar.bz2
samba-af8a691db11a5072865f8b03fd1cbd3aab5cb6d7.zip
r8219: Merge the new open code from HEAD to 3.0. Haven't yet run the torture
tests on this as it's very late NY time (just wanted to get this work into the tree). I'll test this over the weekend.... Jerry - in looking at the difference between the two trees there seem to be some printing/ntprinting.c and registry changes we might want to examine to try keep in sync. Jeremy. (This used to be commit c7fe18761e2c753afbffd3a78abff46472a9b8eb)
Diffstat (limited to 'source3/smbd/open.c')
-rw-r--r--source3/smbd/open.c1906
1 files changed, 1127 insertions, 779 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 9da53a5057..810913c025 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -3,6 +3,7 @@
file opening and share modes
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Jeremy Allison 2001-2004
+ Copyright (C) Volker Lendecke 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,13 +37,16 @@ struct dev_inode_bundle {
fd support routines - attempt to do a dos_open.
****************************************************************************/
-static int fd_open(struct connection_struct *conn, const char *fname,
- int flags, mode_t mode)
+static int fd_open(struct connection_struct *conn,
+ const char *fname,
+ int flags,
+ mode_t mode)
{
int fd;
#ifdef O_NOFOLLOW
- if (!lp_symlinks(SNUM(conn)))
+ if (!lp_symlinks(SNUM(conn))) {
flags |= O_NOFOLLOW;
+ }
#endif
fd = SMB_VFS_OPEN(conn,fname,flags,mode);
@@ -57,10 +61,15 @@ static int fd_open(struct connection_struct *conn, const char *fname,
Close the file associated with a fsp.
****************************************************************************/
-int fd_close(struct connection_struct *conn, files_struct *fsp)
+int fd_close(struct connection_struct *conn,
+ files_struct *fsp)
{
- if (fsp->fd == -1)
- return 0; /* what we used to call a stat open. */
+ if (fsp->fh->fd == -1) {
+ return 0; /* What we used to call a stat open. */
+ }
+ if (fsp->fh->ref_count > 1) {
+ return 0; /* Shared handle. Only close last reference. */
+ }
return fd_close_posix(conn, fsp);
}
@@ -86,7 +95,10 @@ static void check_for_pipe(const char *fname)
Do this by fd if possible.
****************************************************************************/
-void change_owner_to_parent(connection_struct *conn, files_struct *fsp, const char *fname, SMB_STRUCT_STAT *psbuf)
+void change_owner_to_parent(connection_struct *conn,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
{
const char *parent_path = parent_dirname(fname);
SMB_STRUCT_STAT parent_st;
@@ -94,56 +106,67 @@ void change_owner_to_parent(connection_struct *conn, files_struct *fsp, const ch
ret = SMB_VFS_STAT(conn, parent_path, &parent_st);
if (ret == -1) {
- DEBUG(0,("change_owner_to_parent: failed to stat parent directory %s. Error was %s\n",
- parent_path, strerror(errno) ));
+ DEBUG(0,("change_owner_to_parent: failed to stat parent "
+ "directory %s. Error was %s\n",
+ parent_path, strerror(errno) ));
return;
}
- if (fsp && fsp->fd != -1) {
+ if (fsp && fsp->fh->fd != -1) {
become_root();
- ret = SMB_VFS_FCHOWN(fsp, fsp->fd, parent_st.st_uid, (gid_t)-1);
+ ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, parent_st.st_uid, (gid_t)-1);
unbecome_root();
if (ret == -1) {
- DEBUG(0,("change_owner_to_parent: failed to fchown file %s to parent directory uid %u. \
-Error was %s\n",
- fname, (unsigned int)parent_st.st_uid, strerror(errno) ));
+ DEBUG(0,("change_owner_to_parent: failed to fchown "
+ "file %s to parent directory uid %u. Error "
+ "was %s\n", fname,
+ (unsigned int)parent_st.st_uid,
+ strerror(errno) ));
}
- DEBUG(10,("change_owner_to_parent: changed new file %s to parent directory uid %u.\n",
- fname, (unsigned int)parent_st.st_uid ));
+ DEBUG(10,("change_owner_to_parent: changed new file %s to "
+ "parent directory uid %u.\n", fname,
+ (unsigned int)parent_st.st_uid ));
} else {
- /* We've already done an lstat into psbuf, and we know it's a directory. If
- we can cd into the directory and the dev/ino are the same then we can safely
- chown without races as we're locking the directory in place by being in it.
- This should work on any UNIX (thanks tridge :-). JRA.
+ /* We've already done an lstat into psbuf, and we know it's a
+ directory. If we can cd into the directory and the dev/ino
+ are the same then we can safely chown without races as
+ we're locking the directory in place by being in it. This
+ should work on any UNIX (thanks tridge :-). JRA.
*/
pstring saved_dir;
SMB_STRUCT_STAT sbuf;
if (!vfs_GetWd(conn,saved_dir)) {
- DEBUG(0,("change_owner_to_parent: failed to get current working directory\n"));
+ DEBUG(0,("change_owner_to_parent: failed to get "
+ "current working directory\n"));
return;
}
/* Chdir into the new path. */
if (vfs_ChDir(conn, fname) == -1) {
- DEBUG(0,("change_owner_to_parent: failed to change current working directory to %s. \
-Error was %s\n", fname, strerror(errno) ));
+ DEBUG(0,("change_owner_to_parent: failed to change "
+ "current working directory to %s. Error "
+ "was %s\n", fname, strerror(errno) ));
goto out;
}
if (SMB_VFS_STAT(conn,".",&sbuf) == -1) {
- DEBUG(0,("change_owner_to_parent: failed to stat directory '.' (%s) \
-Error was %s\n", fname, strerror(errno)));
+ DEBUG(0,("change_owner_to_parent: failed to stat "
+ "directory '.' (%s) Error was %s\n",
+ fname, strerror(errno)));
goto out;
}
/* Ensure we're pointing at the same place. */
- if (sbuf.st_dev != psbuf->st_dev || sbuf.st_ino != psbuf->st_ino || sbuf.st_mode != psbuf->st_mode ) {
- DEBUG(0,("change_owner_to_parent: device/inode/mode on directory %s changed. Refusing to chown !\n",
- fname ));
+ if (sbuf.st_dev != psbuf->st_dev ||
+ sbuf.st_ino != psbuf->st_ino ||
+ sbuf.st_mode != psbuf->st_mode ) {
+ DEBUG(0,("change_owner_to_parent: "
+ "device/inode/mode on directory %s changed. "
+ "Refusing to chown !\n", fname ));
goto out;
}
@@ -151,14 +174,16 @@ Error was %s\n", fname, strerror(errno)));
ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1);
unbecome_root();
if (ret == -1) {
- DEBUG(10,("change_owner_to_parent: failed to chown directory %s to parent directory uid %u. \
-Error was %s\n",
- fname, (unsigned int)parent_st.st_uid, strerror(errno) ));
+ DEBUG(10,("change_owner_to_parent: failed to chown "
+ "directory %s to parent directory uid %u. "
+ "Error was %s\n", fname,
+ (unsigned int)parent_st.st_uid, strerror(errno) ));
goto out;
}
- DEBUG(10,("change_owner_to_parent: changed ownership of new directory %s to parent directory uid %u.\n",
- fname, (unsigned int)parent_st.st_uid ));
+ DEBUG(10,("change_owner_to_parent: changed ownership of new "
+ "directory %s to parent directory uid %u.\n",
+ fname, (unsigned int)parent_st.st_uid ));
out:
@@ -170,13 +195,19 @@ Error was %s\n",
Open a file.
****************************************************************************/
-static BOOL open_file(files_struct *fsp,connection_struct *conn,
- const char *fname,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode, uint32 desired_access)
+static BOOL open_file(files_struct *fsp,
+ connection_struct *conn,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ int flags,
+ mode_t unx_mode,
+ uint32 access_mask)
{
int accmode = (flags & O_ACCMODE);
int local_flags = flags;
+ BOOL file_existed = VALID_STAT(*psbuf);
- fsp->fd = -1;
+ fsp->fh->fd = -1;
fsp->oplock_type = NO_OPLOCK;
errno = EPERM;
@@ -199,9 +230,9 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
check_for_pipe(fname);
return False;
} else if(flags & O_CREAT) {
- /* We don't want to write - but we must make sure that O_CREAT
- doesn't create the file if we have write access into the
- directory.
+ /* We don't want to write - but we must make sure that
+ O_CREAT doesn't create the file if we have write
+ access into the directory.
*/
flags &= ~O_CREAT;
local_flags &= ~O_CREAT;
@@ -221,12 +252,14 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
*/
if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
- DEBUG(10,("open_file: truncate requested on read-only open for file %s\n",fname ));
+ DEBUG(10,("open_file: truncate requested on read-only open "
+ "for file %s\n",fname ));
local_flags = (flags & ~O_ACCMODE)|O_RDWR;
}
- if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
- (local_flags & O_CREAT) || ((local_flags & O_TRUNC) == O_TRUNC) ) {
+ if ((access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
+ (local_flags & O_CREAT) ||
+ ((local_flags & O_TRUNC) == O_TRUNC) ) {
/*
* We can't actually truncate here as the file may be locked.
@@ -242,42 +275,50 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
* open flags. JRA.
*/
- if (VALID_STAT(*psbuf) && S_ISFIFO(psbuf->st_mode))
+ if (file_existed && S_ISFIFO(psbuf->st_mode)) {
local_flags |= O_NONBLOCK;
+ }
#endif
/* Don't create files with Microsoft wildcard characters. */
- if ((local_flags & O_CREAT) && !VALID_STAT(*psbuf) && ms_has_wild(fname)) {
- set_saved_error_triple(ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID);
+ if ((local_flags & O_CREAT) && !file_existed &&
+ ms_has_wild(fname)) {
+ set_saved_error_triple(ERRDOS, ERRinvalidname,
+ NT_STATUS_OBJECT_NAME_INVALID);
return False;
}
/* Actually do the open */
- fsp->fd = fd_open(conn, fname, local_flags, mode);
- if (fsp->fd == -1) {
- DEBUG(3,("Error opening file %s (%s) (local_flags=%d) (flags=%d)\n",
+ fsp->fh->fd = fd_open(conn, fname, local_flags, unx_mode);
+ if (fsp->fh->fd == -1) {
+ DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
+ "(flags=%d)\n",
fname,strerror(errno),local_flags,flags));
check_for_pipe(fname);
return False;
}
/* Inherit the ACL if the file was created. */
- if ((local_flags & O_CREAT) && !VALID_STAT(*psbuf))
- inherit_access_acl(conn, fname, mode);
+ if ((local_flags & O_CREAT) && !file_existed) {
+ inherit_access_acl(conn, fname, unx_mode);
+ }
- } else
- fsp->fd = -1; /* What we used to call a stat open. */
+ } else {
+ fsp->fh->fd = -1; /* What we used to call a stat open. */
+ }
- if (!VALID_STAT(*psbuf)) {
+ if (!file_existed) {
int ret;
- if (fsp->fd == -1)
+ if (fsp->fh->fd == -1) {
ret = SMB_VFS_STAT(conn, fname, psbuf);
- else {
- ret = SMB_VFS_FSTAT(fsp,fsp->fd,psbuf);
+ } else {
+ ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf);
/* If we have an fd, this stat should succeed. */
- if (ret == -1)
- DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) ));
+ if (ret == -1) {
+ DEBUG(0,("Error doing fstat on open file %s "
+ "(%s)\n", fname,strerror(errno) ));
+ }
}
/* For a non-io open, this stat failing means file not found. JRA */
@@ -305,18 +346,20 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
fsp->vuid = current_user.vuid;
fsp->file_pid = global_smbpid;
fsp->can_lock = True;
- fsp->can_read = ((flags & O_WRONLY)==0);
- fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
- fsp->share_mode = 0;
- fsp->desired_access = desired_access;
+ fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
+ if (!CAN_WRITE(conn)) {
+ fsp->can_write = False;
+ } else {
+ fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False;
+ }
fsp->print_file = False;
fsp->modified = False;
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = False;
fsp->is_stat = False;
- fsp->directory_delete_on_close = False;
- if (conn->aio_write_behind_list && is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) {
+ if (conn->aio_write_behind_list &&
+ is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) {
fsp->aio_write_behind = True;
}
@@ -349,293 +392,119 @@ static BOOL is_executable(const char *fname)
return False;
}
-enum {AFAIL,AREAD,AWRITE,AALL};
-
-/*******************************************************************
- Reproduce the share mode access table.
- This is horrendoously complex, and really can't be justified on any
- rational grounds except that this is _exactly_ what NT does. See
- the DENY1 and DENY2 tests in smbtorture for a comprehensive set of
- test routines.
-********************************************************************/
-
-static int access_table(int new_deny,int old_deny,int old_mode,
- BOOL same_pid, BOOL isexe)
-{
- if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
-
- if (same_pid) {
- if (isexe && old_mode == DOS_OPEN_RDONLY &&
- old_deny == DENY_DOS && new_deny == DENY_READ) {
- return AFAIL;
- }
- if (!isexe && old_mode == DOS_OPEN_RDONLY &&
- old_deny == DENY_DOS && new_deny == DENY_DOS) {
- return AREAD;
- }
- if (new_deny == DENY_FCB && old_deny == DENY_DOS) {
- if (isexe) return AFAIL;
- if (old_mode == DOS_OPEN_RDONLY) return AFAIL;
- return AALL;
- }
- if (old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS) {
- if (new_deny == DENY_FCB || new_deny == DENY_READ) {
- if (isexe) return AREAD;
- return AFAIL;
- }
- }
- if (old_deny == DENY_FCB) {
- if (new_deny == DENY_DOS || new_deny == DENY_FCB) return AALL;
- return AFAIL;
- }
- }
-
- if (old_deny == DENY_DOS || new_deny == DENY_DOS ||
- old_deny == DENY_FCB || new_deny == DENY_FCB) {
- if (isexe) {
- if (old_deny == DENY_FCB || new_deny == DENY_FCB) {
- return AFAIL;
- }
- if (old_deny == DENY_DOS) {
- if (new_deny == DENY_READ &&
- (old_mode == DOS_OPEN_RDONLY ||
- old_mode == DOS_OPEN_RDWR)) {
- return AFAIL;
- }
- if (new_deny == DENY_WRITE &&
- (old_mode == DOS_OPEN_WRONLY ||
- old_mode == DOS_OPEN_RDWR)) {
- return AFAIL;
- }
- return AALL;
- }
- if (old_deny == DENY_NONE) return AALL;
- if (old_deny == DENY_READ) return AWRITE;
- if (old_deny == DENY_WRITE) return AREAD;
- }
- /* it isn't a exe, dll, sym or com file */
- if (old_deny == new_deny && same_pid)
- return(AALL);
-
- if (old_deny == DENY_READ || new_deny == DENY_READ) return AFAIL;
- if (old_mode == DOS_OPEN_RDONLY) return(AREAD);
-
- return(AFAIL);
- }
-
- switch (new_deny)
- {
- case DENY_WRITE:
- if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_RDONLY) return(AREAD);
- if (old_deny==DENY_READ && old_mode==DOS_OPEN_RDONLY) return(AWRITE);
- if (old_deny==DENY_NONE && old_mode==DOS_OPEN_RDONLY) return(AALL);
- return(AFAIL);
- case DENY_READ:
- if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_WRONLY) return(AREAD);
- if (old_deny==DENY_READ && old_mode==DOS_OPEN_WRONLY) return(AWRITE);
- if (old_deny==DENY_NONE && old_mode==DOS_OPEN_WRONLY) return(AALL);
- return(AFAIL);
- case DENY_NONE:
- if (old_deny==DENY_WRITE) return(AREAD);
- if (old_deny==DENY_READ) return(AWRITE);
- if (old_deny==DENY_NONE) return(AALL);
- return(AFAIL);
- }
- return(AFAIL);
-}
-
/****************************************************************************
Check if we can open a file with a share mode.
+ Returns True if conflict, False if not.
****************************************************************************/
-static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, uint32 desired_access,
- const char *fname, BOOL fcbopen, int *flags)
+static BOOL share_conflict(share_mode_entry *entry,
+ uint32 access_mask,
+ uint32 share_access)
{
- int deny_mode = GET_DENY_MODE(share_mode);
- int old_open_mode = GET_OPEN_MODE(share->share_mode);
- int old_deny_mode = GET_DENY_MODE(share->share_mode);
- BOOL non_io_open_request;
- BOOL non_io_open_existing;
-
- /*
- * share modes = false means don't bother to check for
- * DENY mode conflict. This is a *really* bad idea :-). JRA.
- */
-
- if(!lp_share_modes(SNUM(conn)))
- return True;
-
- if (desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) {
- non_io_open_request = False;
- } else {
- non_io_open_request = True;
- }
-
- if (share->desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) {
- non_io_open_existing = False;
- } else {
- non_io_open_existing = True;
- }
-
- /*
- * Don't allow any opens once the delete on close flag has been
- * set.
- */
-
- if (GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) {
- DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n",
- fname ));
- /* Use errno to map to correct error. */
- set_saved_error_triple(SMB_SUCCESS, 0, NT_STATUS_OK);
+ DEBUG(10,("share_conflict: entry->access_mask = 0x%x, "
+ "entry->share_access = 0x%x, "
+ "entry->private_options = 0x%x\n",
+ (unsigned int)entry->access_mask,
+ (unsigned int)entry->share_access,
+ (unsigned int)entry->private_options));
+
+ DEBUG(10,("share_conflict: access_mask = 0x%x, share_access = 0x%x\n",
+ (unsigned int)access_mask, (unsigned int)share_access));
+
+ if ((entry->access_mask & (FILE_WRITE_DATA|
+ FILE_APPEND_DATA|
+ FILE_READ_DATA|
+ FILE_EXECUTE|
+ DELETE_ACCESS)) == 0) {
+ DEBUG(10,("share_conflict: No conflict due to "
+ "entry->access_mask = 0x%x\n",
+ (unsigned int)entry->access_mask ));
return False;
}
- /* this is a nasty hack, but necessary until we rewrite our open
- handling to use a NTCreateX call as the basic call.
- NT may open a file with neither read nor write access, and in
- this case it expects the open not to conflict with any
- existing deny modes. This happens (for example) during a
- "xcopy /o" where the second file descriptor is used for
- ACL sets
- (tridge)
- */
-
- /*
- * This is a bit wierd - the test for desired access not having the
- * critical bits seems seems odd. Firstly, if both opens have no
- * critical bits then always ignore. Then check the "allow delete"
- * then check for either. This probably isn't quite right yet but
- * gets us much closer. JRA.
- */
-
- /*
- * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE
- * and the existing desired_acces then share modes don't conflict.
- */
-
- if (non_io_open_request && non_io_open_existing) {
-
- /*
- * Wrinkle discovered by smbtorture....
- * If both are non-io open and requester is asking for delete and current open has delete access
- * but neither open has allowed file share delete then deny.... this is very strange and
- * seems to be the only case in which non-io opens conflict. JRA.
- */
-
- if ((desired_access & DELETE_ACCESS) && (share->desired_access & DELETE_ACCESS) &&
- (!GET_ALLOW_SHARE_DELETE(share->share_mode) || !GET_ALLOW_SHARE_DELETE(share_mode))) {
- DEBUG(5,("check_share_mode: Failing open on file %s as delete access requests conflict.\n",
- fname ));
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
- return False;
- }
-
- DEBUG(5,("check_share_mode: Allowing open on file %s as both desired access (0x%x) \
-and existing desired access (0x%x) are non-data opens\n",
- fname, (unsigned int)desired_access, (unsigned int)share->desired_access ));
- return True;
- } else if (non_io_open_request || non_io_open_existing) {
- /*
- * If either are non-io opens then share modes don't conflict.
- */
- DEBUG(5,("check_share_mode: One non-io open. Allowing open on file %s as desired access (0x%x) doesn't conflict with\
-existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access ));
- return True;
- }
-
- /*
- * If delete access was requested and the existing share mode doesn't have
- * ALLOW_SHARE_DELETE then deny.
- */
-
- if ((desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) {
- DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n",
- fname ));
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
+ if ((access_mask & (FILE_WRITE_DATA|
+ FILE_APPEND_DATA|
+ FILE_READ_DATA|
+ FILE_EXECUTE|
+ DELETE_ACCESS)) == 0) {
+ DEBUG(10,("share_conflict: No conflict due to "
+ "access_mask = 0x%x\n",
+ (unsigned int)access_mask ));
return False;
}
- /*
- * The inverse of the above.
- * If delete access was granted and the new share mode doesn't have
- * ALLOW_SHARE_DELETE then deny.
- */
-
- if ((share->desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share_mode)) {
- DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n",
- fname ));
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
- return False;
- }
-
-#if 0
- /* Bluarc test may need this ... needs further investigation. */
- if (deny_mode == DENY_ALL || old_deny_mode == DENY_ALL) {
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
- return False;
+#if 1 /* JRA TEST - Superdebug. */
+#define CHECK_MASK(num, am, right, sa, share) \
+ DEBUG(10,("share_conflict: [%d] am (0x%x) & right (0x%x) = 0x%x\n", \
+ (unsigned int)(num), (unsigned int)(am), \
+ (unsigned int)(right), (unsigned int)(am)&(right) )); \
+ DEBUG(10,("share_conflict: [%d] sa (0x%x) & share (0x%x) = 0x%x\n", \
+ (unsigned int)(num), (unsigned int)(sa), \
+ (unsigned int)(share), (unsigned int)(sa)&(share) )); \
+ if (((am) & (right)) && !((sa) & (share))) { \
+ DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
+sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
+ (unsigned int)(share) )); \
+ set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); \
+ return True; \
+ }
+#else
+#define CHECK_MASK(num, am, right, sa, share) \
+ if (((am) & (right)) && !((sa) & (share))) { \
+ DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
+sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
+ (unsigned int)(share) )); \
+ set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); \
+ return True; \
}
#endif
- /*
- * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE
- * then share modes don't conflict. Likewise with existing desired access.
- */
-
- if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
- !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) {
- DEBUG(5,("check_share_mode: Allowing open on file %s as desired access (0x%x) doesn't conflict with \
-existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access ));
- return True;
- }
-
- {
- int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
- (share->pid == sys_getpid()),is_executable(fname));
-
- if ((access_allowed == AFAIL) ||
- (!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) ||
- (access_allowed == AREAD && *flags != O_RDONLY) ||
- (access_allowed == AWRITE && *flags != O_WRONLY)) {
-
- DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n",
- deny_mode,old_deny_mode,old_open_mode,
- (int)share->pid,fname, fcbopen, *flags, access_allowed));
-
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
- return False;
- }
-
- if (access_allowed == AREAD)
- *flags = O_RDONLY;
-
- if (access_allowed == AWRITE)
- *flags = O_WRONLY;
+ CHECK_MASK(1, entry->access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,
+ share_access, FILE_SHARE_WRITE);
+ CHECK_MASK(2, access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,
+ entry->share_access, FILE_SHARE_WRITE);
+
+ CHECK_MASK(3, entry->access_mask, FILE_READ_DATA | FILE_EXECUTE,
+ share_access, FILE_SHARE_READ);
+ CHECK_MASK(4, access_mask, FILE_READ_DATA | FILE_EXECUTE,
+ entry->share_access, FILE_SHARE_READ);
- }
+ CHECK_MASK(5, entry->access_mask, DELETE_ACCESS,
+ share_access, FILE_SHARE_DELETE);
+ CHECK_MASK(6, access_mask, DELETE_ACCESS,
+ entry->share_access, FILE_SHARE_DELETE);
- return True;
+ DEBUG(10,("share_conflict: No conflict.\n"));
+ return False;
}
-
#if defined(DEVELOPER)
-static void validate_my_share_entries(int num, share_mode_entry *share_entry)
+static void validate_my_share_entries(int num,
+ share_mode_entry *share_entry)
{
files_struct *fsp;
- if (share_entry->pid != sys_getpid())
+ if (share_entry->pid != sys_getpid()) {
return;
+ }
- fsp = file_find_dif(share_entry->dev, share_entry->inode, share_entry->share_file_id);
+ fsp = file_find_dif(share_entry->dev, share_entry->inode,
+ share_entry->share_file_id);
if (!fsp) {
- DEBUG(0,("validate_my_share_entries: PANIC : %s\n", share_mode_str(num, share_entry) ));
- smb_panic("validate_my_share_entries: Cannot match a share entry with an open file\n");
+ DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
+ share_mode_str(num, share_entry) ));
+ smb_panic("validate_my_share_entries: Cannot match a "
+ "share entry with an open file\n");
}
if (((uint16)fsp->oplock_type) != share_entry->op_type) {
pstring str;
- DEBUG(0,("validate_my_share_entries: PANIC : %s\n", share_mode_str(num, share_entry) ));
- slprintf(str, sizeof(str)-1, "validate_my_share_entries: file %s, oplock_type = 0x%x, op_type = 0x%x\n",
- fsp->fsp_name, (unsigned int)fsp->oplock_type, (unsigned int)share_entry->op_type );
+ DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
+ share_mode_str(num, share_entry) ));
+ slprintf(str, sizeof(str)-1, "validate_my_share_entries: "
+ "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
+ fsp->fsp_name, (unsigned int)fsp->oplock_type,
+ (unsigned int)share_entry->op_type );
smb_panic(str);
}
}
@@ -655,42 +524,75 @@ static void free_broken_entry_list(struct share_mode_entry_list *broken_entry_li
}
}
+static BOOL cause_oplock_break(int request, int existing, uint32 access_mask)
+{
+ if ((access_mask == DELETE_ACCESS) &&
+ (request == NO_OPLOCK)) {
+ /* This is a delete request */
+ return (BATCH_OPLOCK_TYPE(existing) != 0);
+ }
+
+ if (EXCLUSIVE_OPLOCK_TYPE(existing) && (request != NO_OPLOCK)) {
+ return True;
+ }
+
+ if ((existing != NO_OPLOCK) && (request == NO_OPLOCK)) {
+ return True;
+ }
+
+ return False;
+}
+
/****************************************************************************
Deal with open deny mode and oplock break processing.
Invarient: Share mode must be locked on entry and exit.
Returns -1 on error, or number of share modes on success (may be zero).
****************************************************************************/
-static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T dev,
+static int open_mode_check(connection_struct *conn,
+ const char *fname,
+ SMB_DEV_T dev,
SMB_INO_T inode,
- uint32 desired_access,
- int share_mode, int *p_flags, int *p_oplock_request,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_options,
+ int *p_flags,
+ int *p_oplock_request,
BOOL *p_all_current_opens_are_level_II)
{
int i;
int num_share_modes;
int oplock_contention_count = 0;
share_mode_entry *old_shares = NULL;
- BOOL fcbopen = False;
BOOL broke_oplock;
+ BOOL delete_on_close;
- if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB)
- fcbopen = True;
-
- num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ num_share_modes = get_share_modes(dev, inode, &old_shares, &delete_on_close);
if(num_share_modes == 0) {
SAFE_FREE(old_shares);
return 0;
}
- if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) &&
- ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) {
- /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */
+ if (access_mask &&
+ ((access_mask & ~(SYNCHRONIZE_ACCESS| FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES))==0) &&
+ ((access_mask & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES)) != 0)) {
+ /* Stat open that doesn't trigger oplock breaks or share mode
+ * checks... ! JRA. */
SAFE_FREE(old_shares);
return num_share_modes;
}
+ /* A delete on close prohibits everything */
+
+ if (delete_on_close) {
+ SAFE_FREE(old_shares);
+ errno = EACCES;
+ return -1;
+ }
+
/*
* Check if the share modes will give us access.
*/
@@ -703,132 +605,152 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T
*p_all_current_opens_are_level_II = True;
for(i = 0; i < num_share_modes; i++) {
- BOOL cause_oplock_break = False;
share_mode_entry *share_entry = &old_shares[i];
+ BOOL opb_ret;
#if defined(DEVELOPER)
validate_my_share_entries(i, share_entry);
#endif
/*
- * By observation of NetBench, oplocks are broken *before* share
- * modes are checked. This allows a file to be closed by the client
- * if the share mode would deny access and the client has an oplock.
- * Check if someone has an oplock on this file. If so we must break
- * it before continuing.
+ * By observation of NetBench, oplocks are broken
+ * *before* share modes are checked. This allows a
+ * file to be closed by the client if the share mode
+ * would deny access and the client has an oplock.
+ * Check if someone has an oplock on this file. If so
+ * we must break it before continuing.
*/
-
- /* Was this a delete this file request ? */
- if (!*p_oplock_request && desired_access == DELETE_ACCESS &&
- !BATCH_OPLOCK_TYPE(share_entry->op_type)) {
- /* Don't break the oplock in this case. */
- cause_oplock_break = False;
- } else if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) ||
- (!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) {
- cause_oplock_break = True;
+
+ if (!cause_oplock_break(*p_oplock_request,
+ share_entry->op_type,
+ access_mask)) {
+ if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ *p_all_current_opens_are_level_II = False;
+ }
+ continue;
}
- if(cause_oplock_break) {
- BOOL opb_ret;
+ /* This is an oplock break */
- DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \
-dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsigned int)dev, (double)inode));
+ DEBUG(5,("open_mode_check: oplock_request = %d, "
+ "breaking oplock (%x) on file %s, "
+ "dev = %x, inode = %.0f\n",
+ *p_oplock_request, share_entry->op_type,
+ fname, (unsigned int)dev, (double)inode));
- /* Ensure the reply for the open uses the correct sequence number. */
- /* This isn't a real deferred packet as it's response will also increment
- * the sequence.
- */
- srv_defer_sign_response(get_current_mid());
+ /* Ensure the reply for the open uses the correct
+ * sequence number. */
+ /* This isn't a real deferred packet as it's response
+ * will also increment the sequence.
+ */
+ srv_defer_sign_response(get_current_mid());
- /* Oplock break - unlock to request it. */
- unlock_share_entry(conn, dev, inode);
-
- opb_ret = request_oplock_break(share_entry);
+ /* Oplock break - unlock to request it. */
+ unlock_share_entry(conn, dev, inode);
- /* Now relock. */
- lock_share_entry(conn, dev, inode);
+ opb_ret = request_oplock_break(share_entry);
- if(opb_ret == False) {
- DEBUG(0,("open_mode_check: FAILED when breaking oplock (%x) on file %s, \
-dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
- SAFE_FREE(old_shares);
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
- return -1;
- }
+ /* Now relock. */
+ lock_share_entry(conn, dev, inode);
- broken_entry = SMB_MALLOC_P(struct share_mode_entry_list);
- if (!broken_entry) {
- smb_panic("open_mode_check: malloc fail.\n");
- }
- broken_entry->entry = *share_entry;
- DLIST_ADD(broken_entry_list, broken_entry);
- broke_oplock = True;
+ if (!opb_ret) {
+ DEBUG(0,("open_mode_check: FAILED when breaking "
+ "oplock (%x) on file %s, dev = %x, "
+ "inode = %.0f\n",
+ old_shares[i].op_type, fname,
+ (unsigned int)dev, (double)inode));
+ SAFE_FREE(old_shares);
+ set_saved_error_triple(ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
+ return -1;
+ }
- } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
- *p_all_current_opens_are_level_II = False;
+ broken_entry = SMB_MALLOC_P(struct share_mode_entry_list);
+ if (!broken_entry) {
+ smb_panic("open_mode_check: malloc fail.\n");
}
+ broken_entry->entry = *share_entry;
+ DLIST_ADD(broken_entry_list, broken_entry);
+ broke_oplock = True;
+
} /* end for */
if (broke_oplock) {
/* Update the current open table. */
SAFE_FREE(old_shares);
- num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ num_share_modes = get_share_modes(dev, inode,
+ &old_shares,
+ &delete_on_close);
}
- /* Now we check the share modes, after any oplock breaks. */
- for(i = 0; i < num_share_modes; i++) {
- share_mode_entry *share_entry = &old_shares[i];
+ if (lp_share_modes(SNUM(conn))) {
+ /* Now we check the share modes, after any oplock breaks. */
+ for(i = 0; i < num_share_modes; i++) {
+ share_mode_entry *share_entry = &old_shares[i];
- /* someone else has a share lock on it, check to see if we can too */
- if (!check_share_mode(conn, share_entry, share_mode, desired_access,
- fname, fcbopen, p_flags)) {
- SAFE_FREE(old_shares);
- free_broken_entry_list(broken_entry_list);
- errno = EACCES;
- return -1;
- }
+ /* someone else has a share lock on it, check to see
+ * if we can too */
+ if (share_conflict(share_entry, access_mask,
+ share_access)) {
+ SAFE_FREE(old_shares);
+ free_broken_entry_list(broken_entry_list);
+ errno = EACCES;
+ return -1;
+ }
+ }
}
- for(broken_entry = broken_entry_list; broken_entry; broken_entry = broken_entry->next) {
+ for(broken_entry = broken_entry_list; broken_entry;
+ broken_entry = broken_entry->next) {
oplock_contention_count++;
/* Paranoia check that this is no longer an exlusive entry. */
for(i = 0; i < num_share_modes; i++) {
share_mode_entry *share_entry = &old_shares[i];
- if (share_modes_identical(&broken_entry->entry, share_entry) &&
- EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) {
+ if (!(share_modes_identical(&broken_entry->entry,
+ share_entry) &&
+ EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type))) {
+ continue;
+ }
- /*
- * This should not happen. The target left this oplock
- * as exlusive.... The process *must* be dead....
- */
+ /*
+ * This should not happen. The target left this oplock
+ * as exlusive.... The process *must* be dead....
+ */
- DEBUG(0,("open_mode_check: exlusive oplock left by process %d \
-after break ! For file %s, dev = %x, inode = %.0f. Deleting it to continue...\n",
- (int)broken_entry->entry.pid, fname, (unsigned int)dev, (double)inode));
+ DEBUG(0,("open_mode_check: exlusive oplock left by "
+ "process %d after break ! For file %s, "
+ "dev = %x, inode = %.0f. Deleting it to "
+ "continue...\n",
+ (int)broken_entry->entry.pid, fname,
+ (unsigned int)dev, (double)inode));
- if (process_exists(broken_entry->entry.pid)) {
- DEBUG(0,("open_mode_check: Existent process %lu left active oplock.\n",
- (unsigned long)broken_entry->entry.pid ));
- }
+ if (process_exists(broken_entry->entry.pid)) {
+ DEBUG(0,("open_mode_check: Existent process "
+ "%lu left active oplock.\n",
+ (unsigned long)broken_entry->entry.pid ));
+ }
- if (del_share_entry(dev, inode, &broken_entry->entry, NULL) == -1) {
- free_broken_entry_list(broken_entry_list);
- errno = EACCES;
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
- return -1;
- }
+ if (del_share_entry(dev, inode, &broken_entry->entry,
+ NULL, &delete_on_close) == -1) {
+ free_broken_entry_list(broken_entry_list);
+ errno = EACCES;
+ set_saved_error_triple(ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
+ return -1;
+ }
- /*
- * We must reload the share modes after deleting the
- * other process's entry.
- */
+ /*
+ * We must reload the share modes after deleting the
+ * other process's entry.
+ */
- SAFE_FREE(old_shares);
- num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
- break;
- }
+ SAFE_FREE(old_shares);
+ num_share_modes = get_share_modes(dev, inode,
+ &old_shares,
+ &delete_on_close);
+ break;
} /* end for paranoia... */
} /* end for broken_entry */
free_broken_entry_list(broken_entry_list);
@@ -853,7 +775,9 @@ after break ! For file %s, dev = %x, inode = %.0f. Deleting it to continue...\n"
Delete the record for a handled deferred open entry.
****************************************************************************/
-static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode)
+static void delete_defered_open_entry_record(connection_struct *conn,
+ SMB_DEV_T dev,
+ SMB_INO_T inode)
{
uint16 mid = get_current_mid();
pid_t mypid = sys_getpid();
@@ -868,7 +792,7 @@ static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T
for (i = 0; i < num_de_entries; i++) {
deferred_open_entry *entry = &de_array[i];
if (entry->pid == mypid && entry->mid == mid && entry->dev == dev &&
- entry->inode == inode) {
+ entry->inode == inode) {
/* Remove the deferred open entry from the array. */
delete_deferred_open_entry(entry);
@@ -883,8 +807,11 @@ static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T
Handle the 1 second delay in returning a SHARING_VIOLATION error.
****************************************************************************/
-void defer_open_sharing_error(connection_struct *conn, struct timeval *ptv,
- char *fname, SMB_DEV_T dev, SMB_INO_T inode)
+static void defer_open_sharing_error(connection_struct *conn,
+ struct timeval *ptv,
+ const char *fname,
+ SMB_DEV_T dev,
+ SMB_INO_T inode)
{
uint16 mid = get_current_mid();
pid_t mypid = sys_getpid();
@@ -906,10 +833,12 @@ void defer_open_sharing_error(connection_struct *conn, struct timeval *ptv,
/*
* Check if a 1 second timeout has expired.
*/
- if (usec_time_diff(ptv, &entry->time) > SHARING_VIOLATION_USEC_WAIT) {
- DEBUG(10,("defer_open_sharing_error: Deleting deferred open entry for mid %u, \
-file %s\n",
- (unsigned int)mid, fname ));
+ if (usec_time_diff(ptv, &entry->time) >
+ SHARING_VIOLATION_USEC_WAIT) {
+ DEBUG(10,("defer_open_sharing_error: Deleting "
+ "deferred open entry for mid %u, "
+ "file %s\n",
+ (unsigned int)mid, fname ));
/* Expired, return a real error. */
/* Remove the deferred open entry from the array. */
@@ -919,24 +848,30 @@ file %s\n",
return;
}
/*
- * If the timeout hasn't expired yet and we still have a sharing violation,
- * just leave the entry in the deferred open array alone. We do need to
- * reschedule this open call though (with the original created time).
+ * If the timeout hasn't expired yet and we still have
+ * a sharing violation, just leave the entry in the
+ * deferred open array alone. We do need to reschedule
+ * this open call though (with the original created
+ * time).
*/
- DEBUG(10,("defer_open_sharing_error: time [%u.%06u] updating \
-deferred open entry for mid %u, file %s\n",
- (unsigned int)entry->time.tv_sec,
- (unsigned int)entry->time.tv_usec,
- (unsigned int)mid, fname ));
-
- push_sharing_violation_open_smb_message(&entry->time, (char *)&dib, sizeof(dib));
+ DEBUG(10,("defer_open_sharing_error: time [%u.%06u] "
+ "updating deferred open entry for mid %u, file %s\n",
+ (unsigned int)entry->time.tv_sec,
+ (unsigned int)entry->time.tv_usec,
+ (unsigned int)mid, fname ));
+
+ push_sharing_violation_open_smb_message(&entry->time,
+ (char *)&dib,
+ sizeof(dib));
SAFE_FREE(de_array);
return;
}
}
- DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred open entry for mid %u, file %s\n",
- (unsigned int)ptv->tv_sec, (unsigned int)ptv->tv_usec, (unsigned int)mid, fname ));
+ DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred "
+ "open entry for mid %u, file %s\n",
+ (unsigned int)ptv->tv_sec, (unsigned int)ptv->tv_usec,
+ (unsigned int)mid, fname ));
if (!push_sharing_violation_open_smb_message(ptv, (char *)&dib, sizeof(dib))) {
SAFE_FREE(de_array);
@@ -963,80 +898,302 @@ deferred open entry for mid %u, file %s\n",
This requires a patch to Linux.
****************************************************************************/
-static void kernel_flock(files_struct *fsp, int deny_mode)
+static void kernel_flock(files_struct *fsp, uint32 share_mode)
{
#if HAVE_KERNEL_SHARE_MODES
int kernel_mode = 0;
- if (deny_mode == DENY_READ) kernel_mode = LOCK_MAND|LOCK_WRITE;
- else if (deny_mode == DENY_WRITE) kernel_mode = LOCK_MAND|LOCK_READ;
- else if (deny_mode == DENY_ALL) kernel_mode = LOCK_MAND;
- if (kernel_mode) flock(fsp->fd, kernel_mode);
+ if (share_mode == FILE_SHARE_WRITE) {
+ kernel_mode = LOCK_MAND|LOCK_WRITE;
+ } else if (share_mode == FILE_SHARE_READ) {
+ kernel_mode = LOCK_MAND|LOCK_READ;
+ } else if (share_mode == FILE_SHARE_NONE) {
+ kernel_mode = LOCK_MAND;
+ }
+ if (kernel_mode) {
+ flock(fsp->fh->fd, kernel_mode);
+ }
#endif
- ;;
+ ;
}
+/****************************************************************************
+ On overwrite open ensure that the attributes match.
+****************************************************************************/
-static BOOL open_match_attributes(connection_struct *conn, const char *path, uint32 old_dos_mode, uint32 new_dos_mode,
- mode_t existing_mode, mode_t new_mode, mode_t *returned_mode)
+static BOOL open_match_attributes(connection_struct *conn,
+ const char *path,
+ uint32 old_dos_attr,
+ uint32 new_dos_attr,
+ mode_t existing_unx_mode,
+ mode_t new_unx_mode,
+ mode_t *returned_unx_mode)
{
- uint32 noarch_old_dos_mode, noarch_new_dos_mode;
+ uint32 noarch_old_dos_attr, noarch_new_dos_attr;
- noarch_old_dos_mode = (old_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE);
- noarch_new_dos_mode = (new_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE);
+ noarch_old_dos_attr = (old_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
+ noarch_new_dos_attr = (new_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
- if((noarch_old_dos_mode == 0 && noarch_new_dos_mode != 0) ||
- (noarch_old_dos_mode != 0 && ((noarch_old_dos_mode & noarch_new_dos_mode) == noarch_old_dos_mode)))
- *returned_mode = new_mode;
- else
- *returned_mode = (mode_t)0;
+ if((noarch_old_dos_attr == 0 && noarch_new_dos_attr != 0) ||
+ (noarch_old_dos_attr != 0 && ((noarch_old_dos_attr & noarch_new_dos_attr) == noarch_old_dos_attr))) {
+ *returned_unx_mode = new_unx_mode;
+ } else {
+ *returned_unx_mode = (mode_t)0;
+ }
- DEBUG(10,("open_match_attributes: file %s old_dos_mode = 0x%x, existing_mode = 0%o, new_dos_mode = 0x%x returned_mode = 0%o\n",
- path,
- old_dos_mode, (unsigned int)existing_mode, new_dos_mode, (unsigned int)*returned_mode ));
+ DEBUG(10,("open_match_attributes: file %s old_dos_attr = 0x%x, "
+ "existing_unx_mode = 0%o, new_dos_attr = 0x%x "
+ "returned_unx_mode = 0%o\n",
+ path,
+ (unsigned int)old_dos_attr,
+ (unsigned int)existing_unx_mode,
+ (unsigned int)new_dos_attr,
+ (unsigned int)*returned_unx_mode ));
/* If we're mapping SYSTEM and HIDDEN ensure they match. */
if (lp_map_system(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
- if ((old_dos_mode & FILE_ATTRIBUTE_SYSTEM) && !(new_dos_mode & FILE_ATTRIBUTE_SYSTEM))
+ if ((old_dos_attr & FILE_ATTRIBUTE_SYSTEM) &&
+ !(new_dos_attr & FILE_ATTRIBUTE_SYSTEM)) {
return False;
+ }
}
if (lp_map_hidden(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
- if ((old_dos_mode & FILE_ATTRIBUTE_HIDDEN) && !(new_dos_mode & FILE_ATTRIBUTE_HIDDEN))
+ if ((old_dos_attr & FILE_ATTRIBUTE_HIDDEN) &&
+ !(new_dos_attr & FILE_ATTRIBUTE_HIDDEN)) {
return False;
+ }
}
return True;
}
/****************************************************************************
- Open a file with a share mode.
+ Special FCB or DOS processing in the case of a sharing violation.
+ Try and find a duplicated file handle.
****************************************************************************/
-files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf,
- int share_mode,int ofun, uint32 new_dos_mode, int oplock_request,
- int *Access,int *action)
+static files_struct *fcb_or_dos_open(connection_struct *conn,
+ const char *fname, SMB_DEV_T dev,
+ SMB_INO_T inode,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_options)
{
- return open_file_shared1(conn, fname, psbuf, 0, share_mode, ofun, new_dos_mode,
- oplock_request, Access, action);
+ files_struct *fsp;
+ files_struct *dup_fsp;
+
+ DEBUG(5,("fcb_or_dos_open: attempting old open semantics for "
+ "file %s.\n", fname ));
+
+ for(fsp = file_find_di_first(dev, inode); fsp;
+ fsp = file_find_di_next(fsp)) {
+
+ DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, "
+ "vuid = %u, file_pid = %u, private_options = 0x%x "
+ "access_mask = 0x%x\n", fsp->fsp_name,
+ fsp->fh->fd, (unsigned int)fsp->vuid,
+ (unsigned int)fsp->file_pid,
+ (unsigned int)fsp->fh->private_options,
+ (unsigned int)fsp->access_mask ));
+
+ if (fsp->fh->fd != -1 &&
+ fsp->vuid == current_user.vuid &&
+ fsp->file_pid == global_smbpid &&
+ (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
+ (fsp->access_mask & FILE_WRITE_DATA) &&
+ strequal(fsp->fsp_name, fname)) {
+ DEBUG(10,("fcb_or_dos_open: file match\n"));
+ break;
+ }
+ }
+
+ if (!fsp) {
+ return NULL;
+ }
+
+ /* quite an insane set of semantics ... */
+ if (is_executable(fname) &&
+ (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
+ DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n"));
+ return NULL;
+ }
+
+ /* We need to duplicate this fsp. */
+ dup_fsp = dup_file_fsp(fsp, access_mask, share_access, create_options);
+ if (!dup_fsp) {
+ return NULL;
+ }
+
+ return dup_fsp;
+}
+
+/****************************************************************************
+ Open a file with a share mode - old openX method - map into NTCreate.
+****************************************************************************/
+
+BOOL map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func,
+ uint32 *paccess_mask,
+ uint32 *pshare_mode,
+ uint32 *pcreate_disposition,
+ uint32 *pcreate_options)
+{
+ uint32 access_mask;
+ uint32 share_mode;
+ uint32 create_disposition;
+ uint32 create_options = 0;
+
+ DEBUG(10,("map_open_params_to_ntcreate: fname = %s, deny_mode = 0x%x, "
+ "open_func = 0x%x\n",
+ fname, (unsigned int)deny_mode, (unsigned int)open_func ));
+
+ /* Create the NT compatible access_mask. */
+ switch (GET_OPENX_MODE(deny_mode)) {
+ case DOS_OPEN_RDONLY:
+ access_mask = FILE_GENERIC_READ;
+ break;
+ case DOS_OPEN_WRONLY:
+ access_mask = FILE_GENERIC_WRITE;
+ break;
+ case DOS_OPEN_EXEC: /* This used to be FILE_READ_DATA... */
+ case DOS_OPEN_RDWR:
+ case DOS_OPEN_FCB:
+ access_mask = FILE_GENERIC_READ|FILE_GENERIC_WRITE;
+ break;
+ default:
+ DEBUG(10,("map_open_params_to_ntcreate: bad open mode = 0x%x\n",
+ (unsigned int)GET_OPENX_MODE(deny_mode)));
+ return False;
+ }
+
+ /* Create the NT compatible create_disposition. */
+ switch (open_func) {
+ case OPENX_FILE_EXISTS_FAIL|OPENX_FILE_CREATE_IF_NOT_EXIST:
+ create_disposition = FILE_CREATE;
+ break;
+
+ case OPENX_FILE_EXISTS_OPEN:
+ create_disposition = FILE_OPEN;
+ break;
+
+ case OPENX_FILE_EXISTS_OPEN|OPENX_FILE_CREATE_IF_NOT_EXIST:
+ create_disposition = FILE_OPEN_IF;
+ break;
+
+ case OPENX_FILE_EXISTS_TRUNCATE:
+ create_disposition = FILE_OVERWRITE;
+ break;
+
+ case OPENX_FILE_EXISTS_TRUNCATE|OPENX_FILE_CREATE_IF_NOT_EXIST:
+ create_disposition = FILE_OVERWRITE_IF;
+ break;
+
+ default:
+ /* From samba4 - to be confirmed. */
+ if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_EXEC) {
+ create_disposition = FILE_CREATE;
+ break;
+ }
+ DEBUG(10,("map_open_params_to_ntcreate: bad "
+ "open_func 0x%x\n", (unsigned int)open_func));
+ return False;
+ }
+
+ /* Create the NT compatible share modes. */
+ switch (GET_DENY_MODE(deny_mode)) {
+ case DENY_ALL:
+ share_mode = FILE_SHARE_NONE;
+ break;
+
+ case DENY_WRITE:
+ share_mode = FILE_SHARE_READ;
+ break;
+
+ case DENY_READ:
+ share_mode = FILE_SHARE_WRITE;
+ break;
+
+ case DENY_NONE:
+ share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+ break;
+
+ case DENY_DOS:
+ create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
+ if (is_executable(fname)) {
+ share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+ } else {
+ if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_RDONLY) {
+ share_mode = FILE_SHARE_READ;
+ } else {
+ share_mode = FILE_SHARE_NONE;
+ }
+ }
+ break;
+
+ case DENY_FCB:
+ create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
+ share_mode = FILE_SHARE_NONE;
+ break;
+
+ default:
+ DEBUG(10,("map_open_params_to_ntcreate: bad deny_mode 0x%x\n",
+ (unsigned int)GET_DENY_MODE(deny_mode) ));
+ return False;
+ }
+
+ DEBUG(10,("map_open_params_to_ntcreate: file %s, access_mask = 0x%x, "
+ "share_mode = 0x%x, create_disposition = 0x%x, "
+ "create_options = 0x%x\n",
+ fname,
+ (unsigned int)access_mask,
+ (unsigned int)share_mode,
+ (unsigned int)create_disposition,
+ (unsigned int)create_options ));
+
+ if (paccess_mask) {
+ *paccess_mask = access_mask;
+ }
+ if (pshare_mode) {
+ *pshare_mode = share_mode;
+ }
+ if (pcreate_disposition) {
+ *pcreate_disposition = create_disposition;
+ }
+ if (pcreate_options) {
+ *pcreate_options = create_options;
+ }
+
+ return True;
+
}
+/* Map generic permissions to file object specific permissions */
+
+struct generic_mapping file_generic_mapping = {
+ FILE_GENERIC_READ,
+ FILE_GENERIC_WRITE,
+ FILE_GENERIC_EXECUTE,
+ FILE_GENERIC_ALL
+};
+
/****************************************************************************
Open a file with a share mode.
****************************************************************************/
-files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf,
- uint32 desired_access,
- int share_mode,int ofun, uint32 new_dos_mode,
- int oplock_request,
- int *Access,int *paction)
+files_struct *open_file_ntcreate(connection_struct *conn,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */
+ uint32 share_access, /* share constants (FILE_SHARE_READ etc). */
+ uint32 create_disposition, /* FILE_OPEN_IF etc. */
+ uint32 create_options, /* options such as delete on close. */
+ uint32 new_dos_attributes, /* attributes used for new file. */
+ int oplock_request, /* internal Samba oplock codes. */
+ /* Information (FILE_EXISTS etc.) */
+ int *pinfo)
{
int flags=0;
int flags2=0;
- int deny_mode = GET_DENY_MODE(share_mode);
- BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode);
- BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode);
BOOL file_existed = VALID_STAT(*psbuf);
- BOOL fcbopen = False;
BOOL def_acl = False;
- BOOL add_share_mode = True;
BOOL internal_only_open = False;
SMB_DEV_T dev = 0;
SMB_INO_T inode = 0;
@@ -1044,15 +1201,40 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
BOOL all_current_opens_are_level_II = False;
BOOL fsp_open = False;
files_struct *fsp = NULL;
- int open_mode=0;
- uint16 port = 0;
- mode_t new_mode = (mode_t)0;
- int action;
- uint32 existing_dos_mode = 0;
+ mode_t new_unx_mode = (mode_t)0;
+ mode_t unx_mode = (mode_t)0;
+ int info;
+ uint32 existing_dos_attributes = 0;
struct pending_message_list *pml = NULL;
+ uint16 port = 0;
uint16 mid = get_current_mid();
- /* We add aARCH to this as this mode is only used if the file is created new. */
- mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname, True);
+
+ if (conn->printer) {
+ /*
+ * Printers are handled completely differently.
+ * Most of the passed parameters are ignored.
+ */
+
+ if (pinfo) {
+ *pinfo = FILE_WAS_CREATED;
+ }
+
+ DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname));
+
+ return print_fsp_open(conn, fname);
+ }
+
+ /* 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, True);
+
+ DEBUG(10, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x "
+ "access_mask=0x%x share_access=0x%x "
+ "create_disposition = 0x%x create_options=0x%x "
+ "unix mode=0%o oplock_request=%d\n",
+ fname, new_dos_attributes, access_mask, share_access,
+ create_disposition, create_options, unx_mode,
+ oplock_request));
if (oplock_request == INTERNAL_OPEN_ONLY) {
internal_only_open = True;
@@ -1065,52 +1247,42 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
memcpy(&dib, pml->private_data.data, sizeof(dib));
/* There could be a race condition where the dev/inode pair
- has changed since we deferred the message. If so, just
- remove the deferred open entry and return sharing violation. */
-
- /* If the timeout value is non-zero, we need to just
- return sharing violation. Don't retry the open
- as we were not notified of a close and we don't want to
- trigger another spurious oplock break. */
-
- if (!file_existed || dib.dev != psbuf->st_dev || dib.inode != psbuf->st_ino ||
- pml->msg_time.tv_sec || pml->msg_time.tv_usec) {
+ has changed since we deferred the message. If so, just
+ remove the deferred open entry and return sharing
+ violation. */
+
+ /* If the timeout value is non-zero, we need to just return
+ sharing violation. Don't retry the open as we were not
+ notified of a close and we don't want to trigger another
+ spurious oplock break. */
+
+ if (!file_existed || dib.dev != psbuf->st_dev ||
+ dib.inode != psbuf->st_ino || pml->msg_time.tv_sec ||
+ pml->msg_time.tv_usec) {
/* Ensure we don't reprocess this message. */
remove_sharing_violation_open_smb_message(mid);
/* Now remove the deferred open entry under lock. */
lock_share_entry(conn, dib.dev, dib.inode);
- delete_defered_open_entry_record(conn, dib.dev, dib.inode);
+ delete_defered_open_entry_record(conn, dib.dev,
+ dib.inode);
unlock_share_entry(conn, dib.dev, dib.inode);
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
+ set_saved_error_triple(ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
return NULL;
}
/* Ensure we don't reprocess this message. */
remove_sharing_violation_open_smb_message(mid);
-
- }
-
- if (conn->printer) {
- /* printers are handled completely differently. Most of the passed parameters are
- ignored */
- if (Access)
- *Access = DOS_OPEN_WRONLY;
- if (paction)
- *paction = FILE_WAS_CREATED;
- return print_fsp_open(conn, fname);
}
- DEBUG(10,("open_file_shared: fname = %s, dos_attrs = %x, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
- fname, new_dos_mode, share_mode, ofun, (int)mode, oplock_request ));
-
if (!check_name(fname,conn)) {
return NULL;
}
- new_dos_mode &= SAMBA_ATTRIBUTES_MASK;
+ new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
if (file_existed) {
- existing_dos_mode = dos_mode(conn, fname, psbuf);
+ existing_dos_attributes = dos_mode(conn, fname, psbuf);
}
/* ignore any oplock requests if oplocks are disabled */
@@ -1119,114 +1291,173 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
}
/* this is for OS/2 long file names - say we don't support them */
- if (strstr(fname,".+,;=[].")) {
- /* OS/2 Workplace shell fix may be main code stream in a later release. */
- set_saved_error_triple(ERRDOS, ERRcannotopen, NT_STATUS_OBJECT_NAME_NOT_FOUND);
- DEBUG(5,("open_file_shared: OS/2 long filenames are not supported.\n"));
+ if (!lp_posix_pathnames() && strstr(fname,".+,;=[].")) {
+ /* OS/2 Workplace shell fix may be main code stream in a later
+ * release. */
+ set_saved_error_triple(ERRDOS, ERRcannotopen,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not "
+ "supported.\n"));
return NULL;
}
- if ((GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) && file_existed) {
- DEBUG(5,("open_file_shared: create new requested for file %s and file already exists.\n",
- fname ));
- if (S_ISDIR(psbuf->st_mode)) {
- errno = EISDIR;
- } else {
- errno = EEXIST;
- }
- return NULL;
- }
-
- if (CAN_WRITE(conn) && (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST))
- flags2 |= O_CREAT;
+ switch( create_disposition ) {
+ /*
+ * Currently we're using FILE_SUPERSEDE as the same as
+ * FILE_OVERWRITE_IF but they really are
+ * different. FILE_SUPERSEDE deletes an existing file
+ * (requiring delete access) then recreates it.
+ */
+ case FILE_SUPERSEDE:
+ /* If file exists replace/overwrite. If file doesn't
+ * exist create. */
+ flags2 |= (O_CREAT | O_TRUNC);
+ break;
- if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE))
- flags2 |= O_TRUNC;
+ case FILE_OVERWRITE_IF:
+ /* If file exists replace/overwrite. If file doesn't
+ * exist create. */
+ flags2 |= (O_CREAT | O_TRUNC);
+ break;
- /* We only care about matching attributes on file exists and truncate. */
- if (file_existed && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) {
- if (!open_match_attributes(conn, fname, existing_dos_mode, new_dos_mode,
- psbuf->st_mode, mode, &new_mode)) {
- DEBUG(5,("open_file_shared: attributes missmatch for file %s (%x %x) (0%o, 0%o)\n",
- fname, existing_dos_mode, new_dos_mode,
- (int)psbuf->st_mode, (int)mode ));
+ case FILE_OPEN:
+ /* If file exists open. If file doesn't exist error. */
+ if (!file_existed) {
+ DEBUG(5,("open_file_ntcreate: FILE_OPEN "
+ "requested for file %s and file "
+ "doesn't exist.\n", fname ));
+ set_saved_error_triple(ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ errno = ENOENT;
+ return NULL;
+ }
+ break;
+
+ case FILE_OVERWRITE:
+ /* If file exists overwrite. If file doesn't exist
+ * error. */
+ if (!file_existed) {
+ DEBUG(5,("open_file_ntcreate: FILE_OVERWRITE "
+ "requested for file %s and file "
+ "doesn't exist.\n", fname ));
+ set_saved_error_triple(ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ errno = ENOENT;
+ return NULL;
+ }
+ flags2 |= O_TRUNC;
+ break;
+
+ case FILE_CREATE:
+ /* If file exists error. If file doesn't exist
+ * create. */
+ if (file_existed) {
+ DEBUG(5,("open_file_ntcreate: FILE_CREATE "
+ "requested for file %s and file "
+ "already exists.\n", fname ));
+ if (S_ISDIR(psbuf->st_mode)) {
+ errno = EISDIR;
+ } else {
+ errno = EEXIST;
+ }
+ return NULL;
+ }
+ flags2 |= (O_CREAT|O_EXCL);
+ break;
+
+ case FILE_OPEN_IF:
+ /* If file exists open. If file doesn't exist
+ * create. */
+ flags2 |= O_CREAT;
+ break;
+
+ default:
+ set_saved_error_triple(ERRDOS, ERRinvalidparam,
+ NT_STATUS_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ /* We only care about matching attributes on file exists and
+ * overwrite. */
+
+ if (file_existed && ((create_disposition == FILE_OVERWRITE) ||
+ (create_disposition == FILE_OVERWRITE_IF))) {
+ if (!open_match_attributes(conn, fname,
+ existing_dos_attributes,
+ new_dos_attributes, psbuf->st_mode,
+ unx_mode, &new_unx_mode)) {
+ DEBUG(5,("open_file_ntcreate: attributes missmatch "
+ "for file %s (%x %x) (0%o, 0%o)\n",
+ fname, existing_dos_attributes,
+ new_dos_attributes,
+ (unsigned int)psbuf->st_mode,
+ (unsigned int)unx_mode ));
errno = EACCES;
return NULL;
}
}
- if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL)
- flags2 |= O_EXCL;
+ /* This is a nasty hack - must fix... JRA. */
+ if (access_mask == MAXIMUM_ALLOWED_ACCESS) {
+ access_mask = FILE_GENERIC_ALL;
+ }
- /* note that we ignore the append flag as
- append does not mean the same thing under dos and unix */
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
- switch (GET_OPEN_MODE(share_mode)) {
- case DOS_OPEN_EXEC:
- case DOS_OPEN_RDONLY:
- flags = O_RDONLY;
- if (desired_access == 0)
- desired_access = FILE_READ_DATA;
- break;
- case DOS_OPEN_WRONLY:
- flags = O_WRONLY;
- if (desired_access == 0)
- desired_access = FILE_WRITE_DATA;
- break;
- case DOS_OPEN_FCB:
- fcbopen = True;
- flags = O_RDWR;
- if (desired_access == 0)
- desired_access = FILE_READ_DATA|FILE_WRITE_DATA;
- break;
- case DOS_OPEN_RDWR:
- flags = O_RDWR;
- if (desired_access == 0)
- desired_access = FILE_READ_DATA|FILE_WRITE_DATA;
- break;
- default:
- /* Force DOS error. */
- set_saved_error_triple(ERRDOS, ERRinvalidparam, NT_STATUS_INVALID);
- return NULL;
+ se_map_generic(&access_mask, &file_generic_mapping);
+
+ DEBUG(10, ("open_file_ntcreate: fname=%s, after mapping "
+ "access_mask=0x%x\n", fname, access_mask ));
+
+ /*
+ * Note that we ignore the append flag as append does not
+ * mean the same thing under DOS and Unix.
+ */
+
+ if (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
+ flags = O_RDWR;
+ } else {
+ flags = O_RDONLY;
}
+ /*
+ * Currently we only look at FILE_WRITE_THROUGH for create options.
+ */
+
#if defined(O_SYNC)
- if (GET_FILE_SYNC_OPENMODE(share_mode)) {
+ if (create_options & FILE_WRITE_THROUGH) {
flags2 |= O_SYNC;
}
#endif /* O_SYNC */
- if (flags != O_RDONLY && file_existed &&
- (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_mode))) {
- if (!fcbopen) {
- DEBUG(5,("open_file_shared: read/write access requested for file %s on read only %s\n",
- fname, !CAN_WRITE(conn) ? "share" : "file" ));
- errno = EACCES;
- return NULL;
- }
- flags = O_RDONLY;
+ if (!CAN_WRITE(conn)) {
+ /*
+ * We should really return a permission denied error if either
+ * O_CREAT or O_TRUNC are set, but for compatibility with
+ * older versions of Samba we just AND them out.
+ */
+ flags2 &= ~(O_CREAT|O_TRUNC);
}
- if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) {
- DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname));
- errno = EINVAL;
- return NULL;
- }
+ /*
+ * Ensure we can't write on a read-only share or file.
+ */
- if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) &&
- ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) {
- /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */
- deny_mode = DENY_NONE;
- if (file_existed) {
- oplock_request = 0;
- add_share_mode = False;
- flags2 &= ~O_CREAT;
- }
+ if (flags != O_RDONLY && file_existed &&
+ (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) {
+ DEBUG(5,("open_file_ntcreate: write access requested for "
+ "file %s on read only %s\n",
+ fname, !CAN_WRITE(conn) ? "share" : "file" ));
+ set_saved_error_triple(ERRDOS, ERRnoaccess,
+ NT_STATUS_ACCESS_DENIED);
+ errno = EACCES;
+ return NULL;
}
fsp = file_new(conn);
- if(!fsp)
+ if(!fsp) {
return NULL;
+ }
if (file_existed) {
@@ -1235,47 +1466,86 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
lock_share_entry(conn, dev, inode);
- num_share_modes = open_mode_check(conn, fname, dev, inode,
- desired_access,
- share_mode,
- &flags, &oplock_request, &all_current_opens_are_level_II);
+ num_share_modes = open_mode_check(conn, fname, dev, inode,
+ access_mask, share_access,
+ create_options,
+ &flags, &oplock_request,
+ &all_current_opens_are_level_II);
if(num_share_modes == -1) {
+ if (!internal_only_open) {
+ NTSTATUS status;
+ get_saved_error_triple(NULL, NULL, &status);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) {
+ /* Check if this can be done with the
+ * deny_dos and fcb calls. */
+ if (create_options &
+ (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
+ files_struct *fsp_dup;
+ fsp_dup = fcb_or_dos_open(conn, fname, dev,
+ inode, access_mask,
+ share_access,
+ create_options);
+
+ if (fsp_dup) {
+ unlock_share_entry(conn, dev, inode);
+ file_free(fsp);
+ if (pinfo) {
+ *pinfo = FILE_WAS_OPENED;
+ }
+ conn->num_files_open++;
+ return fsp_dup;
+ }
+ }
+ }
+ }
+
/*
- * This next line is a subtlety we need for MS-Access. If a file open will
- * fail due to share permissions and also for security (access)
- * reasons, we need to return the access failed error, not the
- * share error. This means we must attempt to open the file anyway
- * in order to get the UNIX access error - even if we're going to
- * fail the open for share reasons. This is bad, as we're burning
- * another fd if there are existing locks but there's nothing else
- * we can do. We also ensure we're not going to create or tuncate
- * the file as we only want an access decision at this stage. JRA.
+ * This next line is a subtlety we need for
+ * MS-Access. If a file open will fail due to share
+ * permissions and also for security (access) reasons,
+ * we need to return the access failed error, not the
+ * share error. This means we must attempt to open the
+ * file anyway in order to get the UNIX access error -
+ * even if we're going to fail the open for share
+ * reasons. This is bad, as we're burning another fd
+ * if there are existing locks but there's nothing
+ * else we can do. We also ensure we're not going to
+ * create or tuncate the file as we only want an
+ * access decision at this stage. JRA.
*/
errno = 0;
fsp_open = open_file(fsp,conn,fname,psbuf,
- flags|(flags2&~(O_TRUNC|O_CREAT)),mode,desired_access);
+ flags|(flags2&~(O_TRUNC|O_CREAT)),
+ unx_mode,access_mask);
- DEBUG(4,("open_file_shared : share_mode deny - calling open_file with \
-flags=0x%X flags2=0x%X mode=0%o returned %d\n",
- flags,(flags2&~(O_TRUNC|O_CREAT)),(int)mode,(int)fsp_open ));
+ DEBUG(4,("open_file_ntcreate : share_mode deny - "
+ "calling open_file with flags=0x%X "
+ "flags2=0x%X mode=0%o returned %d\n",
+ flags, (flags2&~(O_TRUNC|O_CREAT)),
+ (unsigned int)unx_mode, (int)fsp_open ));
if (!fsp_open && errno) {
/* Default error. */
- set_saved_error_triple(ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED);
+ set_saved_error_triple(ERRDOS, ERRnoaccess,
+ NT_STATUS_ACCESS_DENIED);
}
/*
- * If we're returning a share violation, ensure we cope with
- * the braindead 1 second delay.
+ * If we're returning a share violation, ensure we
+ * cope with the braindead 1 second delay.
*/
if (!internal_only_open) {
NTSTATUS status;
get_saved_error_triple(NULL, NULL, &status);
if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) {
- /* The fsp->open_time here represents the current time of day. */
- defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode);
+ /* The fsp->open_time here represents
+ * the current time of day. */
+ defer_open_sharing_error(conn,
+ &fsp->open_time,
+ fname, dev, inode);
}
}
@@ -1286,7 +1556,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
* We have detected a sharing violation here
* so return the correct error code
*/
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
+ set_saved_error_triple(ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
}
file_free(fsp);
return NULL;
@@ -1302,35 +1573,39 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
*/
if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) &&
- (def_acl = directory_has_default_acl(conn, parent_dirname(fname))))
- mode = 0777;
+ (def_acl = directory_has_default_acl(conn, parent_dirname(fname)))) {
+ unx_mode = 0777;
+ }
DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
- flags,flags2,(int)mode));
+ (unsigned int)flags,(unsigned int)flags2,(unsigned int)unx_mode));
/*
* open_file strips any O_TRUNC flags itself.
*/
- fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,mode,desired_access);
+ fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode,access_mask);
- if (!fsp_open && (flags == O_RDWR) && (errno != ENOENT) && fcbopen) {
- if((fsp_open = open_file(fsp,conn,fname,psbuf,O_RDONLY,mode,desired_access)) == True)
+ if (!fsp_open && (flags == O_RDWR) && (errno != ENOENT)) {
+ if((fsp_open = open_file(fsp,conn,fname,psbuf,
+ O_RDONLY,unx_mode,access_mask)) == True) {
flags = O_RDONLY;
+ }
}
if (!fsp_open) {
- if(file_existed)
+ if(file_existed) {
unlock_share_entry(conn, dev, inode);
+ }
file_free(fsp);
return NULL;
}
/*
- * Deal with the race condition where two smbd's detect the file doesn't
- * exist and do the create at the same time. One of them will win and
- * set a share mode, the other (ie. this one) should check if the
- * requested share mode for this create is allowed.
+ * Deal with the race condition where two smbd's detect the file
+ * doesn't exist and do the create at the same time. One of them will
+ * win and set a share mode, the other (ie. this one) should check if
+ * the requested share mode for this create is allowed.
*/
if (!file_existed) {
@@ -1347,22 +1622,47 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
lock_share_entry_fsp(fsp);
- num_share_modes = open_mode_check(conn, fname, dev, inode,
- desired_access,
- share_mode,
- &flags, &oplock_request, &all_current_opens_are_level_II);
+ num_share_modes = open_mode_check(conn, fname, dev, inode,
+ access_mask, share_access,
+ create_options,
+ &flags, &oplock_request,
+ &all_current_opens_are_level_II);
if(num_share_modes == -1) {
- /*
- * If we're returning a share violation, ensure we cope with
- * the braindead 1 second delay.
- */
-
NTSTATUS status;
get_saved_error_triple(NULL, NULL, &status);
if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) {
- /* The fsp->open_time here represents the current time of day. */
- defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode);
+ /* Check if this can be done with the deny_dos
+ * and fcb calls. */
+ if (create_options &
+ (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
+ files_struct *fsp_dup;
+ fsp_dup = fcb_or_dos_open(conn, fname, dev, inode,
+ access_mask, share_access,
+ create_options);
+ if (fsp_dup) {
+ unlock_share_entry(conn, dev, inode);
+ fd_close(conn, fsp);
+ file_free(fsp);
+ if (pinfo) {
+ *pinfo = FILE_WAS_OPENED;
+ }
+ conn->num_files_open++;
+ return fsp_dup;
+ }
+ }
+
+ /*
+ * If we're returning a share violation,
+ * ensure we cope with the braindead 1 second
+ * delay.
+ */
+
+ /* The fsp->open_time here represents the
+ * current time of day. */
+ defer_open_sharing_error(conn, &fsp->open_time,
+ fname, dev, inode);
}
unlock_share_entry_fsp(fsp);
@@ -1372,7 +1672,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
* We have detected a sharing violation here, so
* return the correct code.
*/
- set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION);
+ set_saved_error_triple(ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
return NULL;
}
@@ -1381,8 +1682,9 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
* exist. Ensure we return the correct value for action.
*/
- if (num_share_modes > 0)
+ if (num_share_modes > 0) {
file_existed = True;
+ }
/*
* We exit this block with the share entry *locked*.....
@@ -1395,7 +1697,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
mode and we have already checked our more authoritative
locking database for permission to set this deny mode. If
the kernel refuses the operations then the kernel is wrong */
- kernel_flock(fsp, deny_mode);
+
+ kernel_flock(fsp, share_access);
/*
* At this point onwards, we can guarentee that the share entry
@@ -1409,9 +1712,11 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
if (flags2&O_TRUNC) {
/*
- * We are modifing the file after open - update the stat struct..
+ * We are modifing the file after open - update the stat
+ * struct..
*/
- if ((SMB_VFS_FTRUNCATE(fsp,fsp->fd,0) == -1) || (SMB_VFS_FSTAT(fsp,fsp->fd,psbuf)==-1)) {
+ if ((SMB_VFS_FTRUNCATE(fsp,fsp->fh->fd,0) == -1) ||
+ (SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf)==-1)) {
unlock_share_entry_fsp(fsp);
fd_close(conn,fsp);
file_free(fsp);
@@ -1419,44 +1724,28 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
}
}
- switch (flags) {
- case O_RDONLY:
- open_mode = DOS_OPEN_RDONLY;
- break;
- case O_RDWR:
- open_mode = DOS_OPEN_RDWR;
- break;
- case O_WRONLY:
- open_mode = DOS_OPEN_WRONLY;
- break;
- }
+ /* Record the options we were opened with. */
+ fsp->share_access = share_access;
+ fsp->fh->private_options = create_options;
+ fsp->access_mask = access_mask;
- fsp->share_mode = SET_DENY_MODE(deny_mode) |
- SET_OPEN_MODE(open_mode) |
- SET_ALLOW_SHARE_DELETE(allow_share_delete);
-
- DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode ));
-
- if (Access) {
- (*Access) = (SET_DENY_MODE(deny_mode) | SET_OPEN_MODE(open_mode));
- }
-
- action = 0;
-
- if (file_existed && !(flags2 & O_TRUNC))
- action = FILE_WAS_OPENED;
- if (file_existed && (flags2 & O_TRUNC))
- action = FILE_WAS_OVERWRITTEN;
- if (!file_existed) {
- action = FILE_WAS_CREATED;
+ if (file_existed) {
+ if (!(flags2 & O_TRUNC)) {
+ info = FILE_WAS_OPENED;
+ } else {
+ info = FILE_WAS_OVERWRITTEN;
+ }
+ } else {
+ info = FILE_WAS_CREATED;
/* Change the owner if required. */
if (lp_inherit_owner(SNUM(conn))) {
- change_owner_to_parent(conn, fsp, fsp->fsp_name, psbuf);
+ change_owner_to_parent(conn, fsp, fsp->fsp_name,
+ psbuf);
}
}
- if (paction) {
- *paction = action;
+ if (pinfo) {
+ *pinfo = info;
}
/*
@@ -1465,7 +1754,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
*/
if(oplock_request && (num_share_modes == 0) &&
- !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp, oplock_request) ) {
+ !IS_VETO_OPLOCK_PATH(conn,fname) &&
+ set_file_oplock(fsp, oplock_request) ) {
port = global_oplock_port;
} else if (oplock_request && all_current_opens_are_level_II) {
port = global_oplock_port;
@@ -1476,26 +1766,25 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
oplock_request = 0;
}
- if (add_share_mode) {
- set_share_mode(fsp, port, oplock_request);
- }
+ set_share_mode(fsp, port, oplock_request);
- if (delete_on_close) {
- uint32 dosmode = existing_dos_mode;
+ if (create_options & FILE_DELETE_ON_CLOSE) {
+ uint32 dosattr= existing_dos_attributes;
NTSTATUS result;
- if (action == FILE_WAS_OVERWRITTEN || action == FILE_WAS_CREATED) {
- dosmode = new_dos_mode;
+ if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
+ info == FILE_WAS_SUPERSEDED) {
+ dosattr = new_dos_attributes;
}
- result = set_delete_on_close_internal(fsp, delete_on_close, dosmode);
- if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) {
+ result = can_set_delete_on_close(fsp, True, dosattr);
+
+ if (!NT_STATUS_IS_OK(result)) {
uint8 u_e_c;
uint32 u_e_code;
+ BOOL dummy_del_on_close;
/* Remember to delete the mode we just added. */
- if (add_share_mode) {
- del_share_mode(fsp, NULL);
- }
+ del_share_mode(fsp, NULL, &dummy_del_on_close);
unlock_share_entry_fsp(fsp);
fd_close(conn,fsp);
file_free(fsp);
@@ -1503,12 +1792,17 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
set_saved_error_triple(u_e_c, u_e_code, result);
return NULL;
}
+ set_delete_on_close(fsp, True);
}
- if (action == FILE_WAS_OVERWRITTEN || action == FILE_WAS_CREATED) {
+ if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
+ info == FILE_WAS_SUPERSEDED) {
/* Files should be initially set as archive */
- if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
- file_set_dosmode(conn, fname, new_dos_mode | aARCH, NULL, True);
+ if (lp_map_archive(SNUM(conn)) ||
+ lp_store_dos_attributes(SNUM(conn))) {
+ file_set_dosmode(conn, fname,
+ new_dos_attributes | aARCH, NULL,
+ True);
}
}
@@ -1519,36 +1813,45 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
if (!file_existed && !def_acl) {
- int saved_errno = errno; /* We might get ENOSYS in the next call.. */
+ int saved_errno = errno; /* We might get ENOSYS in the next
+ * call.. */
- if (SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, mode) == -1 && errno == ENOSYS)
+ if (SMB_VFS_FCHMOD_ACL(fsp, fsp->fh->fd, unx_mode) == -1
+ && errno == ENOSYS) {
errno = saved_errno; /* Ignore ENOSYS */
+ }
- } else if (new_mode) {
+ } else if (new_unx_mode) {
int ret = -1;
/* Attributes need changing. File already existed. */
{
- int saved_errno = errno; /* We might get ENOSYS in the next call.. */
- ret = SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, new_mode);
+ int saved_errno = errno; /* We might get ENOSYS in the
+ * next call.. */
+ ret = SMB_VFS_FCHMOD_ACL(fsp, fsp->fh->fd,
+ new_unx_mode);
if (ret == -1 && errno == ENOSYS) {
errno = saved_errno; /* Ignore ENOSYS */
} else {
- DEBUG(5, ("open_file_shared: failed to reset attributes of file %s to 0%o\n",
- fname, (int)new_mode));
+ DEBUG(5, ("open_file_shared: failed to reset "
+ "attributes of file %s to 0%o\n",
+ fname, (unsigned int)new_unx_mode));
ret = 0; /* Don't do the fchmod below. */
}
}
- if ((ret == -1) && (SMB_VFS_FCHMOD(fsp, fsp->fd, new_mode) == -1))
- DEBUG(5, ("open_file_shared: failed to reset attributes of file %s to 0%o\n",
- fname, (int)new_mode));
+ if ((ret == -1) &&
+ (SMB_VFS_FCHMOD(fsp, fsp->fh->fd, new_unx_mode) == -1))
+ DEBUG(5, ("open_file_shared: failed to reset "
+ "attributes of file %s to 0%o\n",
+ fname, (unsigned int)new_unx_mode));
}
- /* If this is a successful open, we must remove any deferred open records. */
+ /* If this is a successful open, we must remove any deferred open
+ * records. */
delete_defered_open_entry_record(conn, fsp->dev, fsp->inode);
unlock_share_entry_fsp(fsp);
@@ -1561,17 +1864,20 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
Open a file for for write to ensure that we can fchmod it.
****************************************************************************/
-files_struct *open_file_fchmod(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+files_struct *open_file_fchmod(connection_struct *conn, const char *fname,
+ SMB_STRUCT_STAT *psbuf)
{
files_struct *fsp = NULL;
BOOL fsp_open;
- if (!VALID_STAT(*psbuf))
+ if (!VALID_STAT(*psbuf)) {
return NULL;
+ }
fsp = file_new(conn);
- if(!fsp)
+ if(!fsp) {
return NULL;
+ }
/* note! we must use a non-zero desired access or we don't get
a real file descriptor. Oh what a twisted web we weave. */
@@ -1606,96 +1912,135 @@ int close_file_fchmod(files_struct *fsp)
Open a directory from an NT SMB call.
****************************************************************************/
-files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
- uint32 desired_access, int share_mode, int smb_ofun, int *action)
+files_struct *open_directory(connection_struct *conn,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 access_mask,
+ uint32 share_access,
+ uint32 create_disposition,
+ uint32 create_options,
+ int *pinfo)
{
- BOOL got_stat = False;
- files_struct *fsp = file_new(conn);
- BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode);
-
- if(!fsp)
+ files_struct *fsp = NULL;
+ BOOL dir_existed = VALID_STAT(*psbuf) ? True : False;
+ BOOL create_dir = False;
+ int info = 0;
+
+ DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, "
+ "share_access = 0x%x create_options = 0x%x, "
+ "create_disposition = 0x%x\n",
+ fname,
+ (unsigned int)access_mask,
+ (unsigned int)share_access,
+ (unsigned int)create_options,
+ (unsigned int)create_disposition));
+
+ if (is_ntfs_stream_name(fname)) {
+ DEBUG(0,("open_directory: %s is a stream name!\n", fname ));
+ /* NB. Is the DOS error ERRbadpath or ERRbaddirectory ? */
+ set_saved_error_triple(ERRDOS, ERRbadpath,
+ NT_STATUS_NOT_A_DIRECTORY);
return NULL;
+ }
- if (VALID_STAT(*psbuf))
- got_stat = True;
-
- if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) {
- file_free(fsp);
- errno = EEXIST; /* Setup so correct error is returned to client. */
+ if (dir_existed && !S_ISDIR(psbuf->st_mode)) {
+ DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
+ /* NB. Is the DOS error ERRbadpath or ERRbaddirectory ? */
+ set_saved_error_triple(ERRDOS, ERRbadpath,
+ NT_STATUS_NOT_A_DIRECTORY);
return NULL;
}
- if (GET_FILE_CREATE_DISPOSITION(smb_ofun) == FILE_CREATE_IF_NOT_EXIST) {
-
- if (got_stat) {
-
- if(!S_ISDIR(psbuf->st_mode)) {
- DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
- file_free(fsp);
- errno = EACCES;
+ switch( create_disposition ) {
+ case FILE_OPEN:
+ /* If directory exists open. If directory doesn't
+ * exist error. */
+ if (!dir_existed) {
+ DEBUG(5,("open_directory: FILE_OPEN requested "
+ "for directory %s and it doesn't "
+ "exist.\n", fname ));
+ set_saved_error_triple(ERRDOS, ERRbadfile,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND);
return NULL;
}
- *action = FILE_WAS_OPENED;
-
- } else {
-
- /*
- * Try and create the directory.
- */
-
- /* We know bad_path is false as it's caught earlier. */
-
- NTSTATUS status = mkdir_internal(conn, fname, False);
+ info = FILE_WAS_OPENED;
+ break;
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,("open_directory: unable to create %s. Error was %s\n",
- fname, strerror(errno) ));
- file_free(fsp);
- /* Ensure we return the correct NT status to the client. */
- set_saved_error_triple(0, 0, status);
+ case FILE_CREATE:
+ /* If directory exists error. If directory doesn't
+ * exist create. */
+ if (dir_existed) {
+ DEBUG(5,("open_directory: FILE_CREATE "
+ "requested for directory %s and it "
+ "already exists.\n", fname ));
+ set_saved_error_triple(ERRDOS, ERRfilexists,
+ NT_STATUS_OBJECT_NAME_COLLISION);
return NULL;
}
+ create_dir = True;
+ info = FILE_WAS_CREATED;
+ break;
- /* Ensure we're checking for a symlink here.... */
- /* We don't want to get caught by a symlink racer. */
-
- if(SMB_VFS_LSTAT(conn,fname, psbuf) != 0) {
- file_free(fsp);
- return NULL;
+ case FILE_OPEN_IF:
+ /* If directory exists open. If directory doesn't
+ * exist create. */
+ if (!dir_existed) {
+ create_dir = True;
+ info = FILE_WAS_CREATED;
+ } else {
+ info = FILE_WAS_OPENED;
}
+ break;
- if(!S_ISDIR(psbuf->st_mode)) {
- DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
- file_free(fsp);
- return NULL;
- }
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE:
+ case FILE_OVERWRITE_IF:
+ default:
+ DEBUG(5,("open_directory: invalid create_disposition "
+ "0x%x for directory %s\n",
+ (unsigned int)create_disposition, fname));
+ file_free(fsp);
+ set_saved_error_triple(ERRDOS, ERRinvalidparam,
+ NT_STATUS_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ if (create_dir) {
+ /*
+ * Try and create the directory.
+ */
- *action = FILE_WAS_CREATED;
+ /* We know bad_path is false as it's caught earlier. */
+ NTSTATUS status = mkdir_internal(conn, fname, False);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2,("open_directory: unable to create %s. "
+ "Error was %s\n", fname, strerror(errno) ));
+ /* Ensure we return the correct NT status to the
+ * client. */
+ set_saved_error_triple(0, 0, status);
+ return NULL;
}
- } else {
- /*
- * Don't create - just check that it *was* a directory.
- */
+ /* Ensure we're checking for a symlink here.... */
+ /* We don't want to get caught by a symlink racer. */
- if(!got_stat) {
- DEBUG(3,("open_directory: unable to stat name = %s. Error was %s\n",
- fname, strerror(errno) ));
- file_free(fsp);
+ if(SMB_VFS_LSTAT(conn,fname, psbuf) != 0) {
return NULL;
}
if(!S_ISDIR(psbuf->st_mode)) {
- DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
- file_free(fsp);
+ DEBUG(0,("open_directory: %s is not a directory !\n",
+ fname ));
return NULL;
}
+ }
- *action = FILE_WAS_OPENED;
+ fsp = file_new(conn);
+ if(!fsp) {
+ return NULL;
}
-
- DEBUG(5,("open_directory: opening directory %s\n", fname));
/*
* Setup the files_struct for it.
@@ -1709,20 +2054,21 @@ files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STR
fsp->can_lock = True;
fsp->can_read = False;
fsp->can_write = False;
- fsp->share_mode = share_mode;
- fsp->desired_access = desired_access;
+
+ fsp->share_access = share_access;
+ fsp->fh->private_options = create_options;
+ fsp->access_mask = access_mask;
+
fsp->print_file = False;
fsp->modified = False;
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = True;
fsp->is_stat = False;
- fsp->directory_delete_on_close = False;
string_set(&fsp->fsp_name,fname);
- if (delete_on_close) {
- NTSTATUS status = set_delete_on_close_internal(fsp, delete_on_close, 0);
-
+ if (create_options & FILE_DELETE_ON_CLOSE) {
+ NTSTATUS status = can_set_delete_on_close(fsp, True, 0);
if (!NT_STATUS_IS_OK(status)) {
file_free(fsp);
return NULL;
@@ -1730,10 +2076,14 @@ files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STR
}
/* Change the owner if required. */
- if ((*action == FILE_WAS_CREATED) && lp_inherit_owner(SNUM(conn))) {
+ if ((info == FILE_WAS_CREATED) && lp_inherit_owner(SNUM(conn))) {
change_owner_to_parent(conn, fsp, fsp->fsp_name, psbuf);
}
+ if (pinfo) {
+ *pinfo = info;
+ }
+
conn->num_files_open++;
return fsp;
@@ -1743,7 +2093,8 @@ files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STR
Open a pseudo-file (no locking checks - a 'stat' open).
****************************************************************************/
-files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf)
+files_struct *open_file_stat(connection_struct *conn, char *fname,
+ SMB_STRUCT_STAT *psbuf)
{
files_struct *fsp = NULL;
@@ -1772,15 +2123,12 @@ files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_ST
fsp->can_lock = False;
fsp->can_read = False;
fsp->can_write = False;
- fsp->share_mode = 0;
- fsp->desired_access = 0;
fsp->print_file = False;
fsp->modified = False;
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = False;
fsp->is_stat = True;
- fsp->directory_delete_on_close = False;
string_set(&fsp->fsp_name,fname);
conn->num_files_open++;