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 | |
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')
-rw-r--r-- | source3/include/smb.h | 3 | ||||
-rw-r--r-- | source3/locking/locking.c | 46 | ||||
-rw-r--r-- | source3/smbd/open.c | 40 | ||||
-rw-r--r-- | source3/smbd/reply.c | 54 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 5 |
5 files changed, 119 insertions, 29 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h index a7d63a6aed..dd6c17e475 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -742,6 +742,7 @@ struct pending_message_list { }; #define SHARE_MODE_FLAG_POSIX_OPEN 0x1 +#define SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE 0x2 /* struct returned by get_share_modes */ struct share_mode_entry { @@ -759,7 +760,7 @@ struct share_mode_entry { SMB_INO_T inode; unsigned long share_file_id; uint32 uid; /* uid of file opener. */ - uint16 flags; /* POSIX_OPEN only defined so far... */ + uint16 flags; /* See SHARE_MODE_XX above. */ }; /* oplock break message definition - linearization of share_mode_entry. diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 56ff3b9790..17c6d3e9c3 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -1001,10 +1001,13 @@ static void add_share_mode_entry(struct share_mode_lock *lck, } void set_share_mode(struct share_mode_lock *lck, files_struct *fsp, - uid_t uid, uint16 mid, uint16 op_type) + uid_t uid, uint16 mid, uint16 op_type, BOOL initial_delete_on_close_allowed) { struct share_mode_entry entry; fill_share_mode_entry(&entry, fsp, uid, mid, op_type); + if (initial_delete_on_close_allowed) { + entry.flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; + } add_share_mode_entry(lck, &entry); } @@ -1204,6 +1207,22 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close, return NT_STATUS_OK; } +/**************************************************************************** + Do we have an open file handle that created this entry ? +****************************************************************************/ + +BOOL can_set_initial_delete_on_close(const struct share_mode_lock *lck) +{ + int i; + + for (i=0; i<lck->num_share_modes; i++) { + if (lck->share_modes[i].flags & SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE) { + return True; + } + } + return False; +} + /************************************************************************* Return a talloced copy of a UNIX_USER_TOKEN. NULL on fail. (Should this be in locking.c.... ?). @@ -1304,6 +1323,31 @@ BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close, UNIX_USER_TOKE return True; } +/**************************************************************************** + Sets the allow initial delete on close flag for this share mode. +****************************************************************************/ + +BOOL set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, BOOL delete_on_close) +{ + struct share_mode_entry entry, *e; + + /* Don't care about the pid owner being correct here - just a search. */ + fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK); + + e = find_share_mode_entry(lck, &entry); + if (e == NULL) { + return False; + } + + if (delete_on_close) { + e->flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; + } else { + e->flags &= ~SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; + } + lck->modified = True; + return True; +} + struct forall_state { void (*fn)(const struct share_mode_entry *entry, const char *sharepath, 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) { |