diff options
author | Jeremy Allison <jra@samba.org> | 2007-05-23 21:32:10 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:22:46 -0500 |
commit | dbfd6bf8c8cc9945c4ba7e22ac44b1f33f9c7ce6 (patch) | |
tree | 04b65312f9eff3b6164e94e1d5b7fd53de03ab4c /source3/smbd | |
parent | e85613f915a44f572eb4719f9e22943450c07b26 (diff) | |
download | samba-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')
-rw-r--r-- | source3/smbd/open.c | 40 | ||||
-rw-r--r-- | source3/smbd/reply.c | 54 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 5 |
3 files changed, 72 insertions, 27 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 7784740063..89ff9ae809 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1123,6 +1123,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, 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; @@ -1763,28 +1764,31 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, 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))) { @@ -2142,7 +2146,7 @@ NTSTATUS open_directory(connection_struct *conn, 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. */ 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; diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index a41aa3c7df..bd66980983 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -4650,10 +4650,11 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, pstrcpy(base_name, fname); p = strrchr_m(base_name, '/'); if (p) { - *p = '\0'; + p[1] = '\0'; + } else { + pstrcpy(base_name, "./"); } /* Append the new name. */ - pstrcat(base_name, "/"); pstrcat(base_name, newname); if (fsp) { |