summaryrefslogtreecommitdiff
path: root/source3/smbd/reply.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-05-23 21:32:10 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:22:46 -0500
commitdbfd6bf8c8cc9945c4ba7e22ac44b1f33f9c7ce6 (patch)
tree04b65312f9eff3b6164e94e1d5b7fd53de03ab4c /source3/smbd/reply.c
parente85613f915a44f572eb4719f9e22943450c07b26 (diff)
downloadsamba-dbfd6bf8c8cc9945c4ba7e22ac44b1f33f9c7ce6.tar.gz
samba-dbfd6bf8c8cc9945c4ba7e22ac44b1f33f9c7ce6.tar.bz2
samba-dbfd6bf8c8cc9945c4ba7e22ac44b1f33f9c7ce6.zip
r23100: Implement the delete on close semantics I've just tested for
in Samba4 smbtorture. Fix rename on an open file handle. Needed for 3.0.25a. Jeremy. (This used to be commit a301467d5f645dada27093ddfd74890b88bb4ce8)
Diffstat (limited to 'source3/smbd/reply.c')
-rw-r--r--source3/smbd/reply.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index fb042a6b1d..98976dd39d 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1791,7 +1791,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
Check if a user is allowed to rename a file.
********************************************************************/
-static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst)
+static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst, BOOL self_open)
{
files_struct *fsp;
uint32 fmode;
@@ -1812,7 +1812,10 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
status = open_file_ntcreate(conn, fname, pst,
DELETE_ACCESS,
- FILE_SHARE_READ|FILE_SHARE_WRITE,
+ /* If we're checking our fsp don't deny for delete. */
+ self_open ?
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE :
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
0,
FILE_ATTRIBUTE_NORMAL,
@@ -4242,7 +4245,9 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin
ZERO_STRUCT(sbuf);
status = unix_convert(conn, newname, False, newname_last_component, &sbuf);
- if (!NT_STATUS_IS_OK(status)) {
+ /* We expect this to be NT_STATUS_OBJECT_PATH_NOT_FOUND */
+ if (!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, status)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
return status;
}
@@ -4310,9 +4315,20 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- status = can_rename(conn,fsp->fsp_name,attrs,&sbuf);
+ /* Ensure we have a valid stat struct for the source. */
+ if (fsp->fh->fd != -1) {
+ if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ } else {
+ if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
- if (dest_exists && !NT_STATUS_IS_OK(status)) {
+ status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True);
+
+ if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
nt_errstr(status), fsp->fsp_name,newname));
if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
@@ -4327,9 +4343,33 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin
lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
+ uint32 create_options = fsp->fh->private_options;
+
DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
fsp->fsp_name,newname));
+
rename_open_files(conn, lck, fsp->dev, fsp->inode, newname);
+
+ /*
+ * A rename acts as a new file create w.r.t. allowing an initial delete
+ * on close, probably because in Windows there is a new handle to the
+ * new file. If initial delete on close was requested but not
+ * originally set, we need to set it here. This is probably not 100% correct,
+ * but will work for the CIFSFS client which in non-posix mode
+ * depends on these semantics. JRA.
+ */
+
+ set_allow_initial_delete_on_close(lck, fsp, True);
+
+ if (create_options & FILE_DELETE_ON_CLOSE) {
+ status = can_set_delete_on_close(fsp, True, 0);
+
+ if (NT_STATUS_IS_OK(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;
+ }
+ }
TALLOC_FREE(lck);
return NT_STATUS_OK;
}
@@ -4580,7 +4620,7 @@ NTSTATUS rename_internals(connection_struct *conn,
return status;
}
- status = can_rename(conn,directory,attrs,&sbuf1);
+ status = can_rename(conn,directory,attrs,&sbuf1,False);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("rename_internals: Error %s rename %s -> "
@@ -4708,7 +4748,7 @@ NTSTATUS rename_internals(connection_struct *conn,
fname, nt_errstr(status)));
continue;
}
- status = can_rename(conn,fname,attrs,&sbuf1);
+ status = can_rename(conn,fname,attrs,&sbuf1,False);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(6, ("rename %s refused\n", fname));
continue;