mirror of
https://github.com/samba-team/samba.git
synced 2025-08-03 04:22:09 +03:00
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 a301467d5f
)
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
e85613f915
commit
dbfd6bf8c8
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
Reference in New Issue
Block a user