1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

r12213: Final fix for #3303 - send rename messages to smbd's

that have open file handles to allow them to correctly
implement delete on close. There is a further correctness
fix I'm intending to add to this to cope with different share
paths, but not right now...
Jeremy.
This commit is contained in:
Jeremy Allison 2005-12-13 18:11:50 +00:00 committed by Gerald (Jerry) Carter
parent 9d93af713f
commit 932e337db8
8 changed files with 168 additions and 19 deletions

View File

@ -68,6 +68,7 @@
#define MSG_SMB_ASYNC_LEVEL2_BREAK 3008
#define MSG_SMB_OPEN_RETRY 3009
#define MSG_SMB_KERNEL_BREAK 3010
#define MSG_SMB_FILE_RENAME 3011
/* winbind messages */
#define MSG_WINBIND_FINISHED 4001

View File

@ -1459,6 +1459,12 @@ struct kernel_oplock_message {
unsigned long file_id;
};
struct file_renamed_message {
SMB_DEV_T dev;
SMB_INO_T inode;
char names[1]; /* A variable area containing sharepath and filename. */
};
/*
* On the wire return values for oplock types.
*/

View File

@ -642,14 +642,24 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx,
/*******************************************************************
Sets the service name and filename for rename.
At this point we should emit "rename" smbd messages to all
interested process id's.
At this point we emit "file renamed" messages to all
process id's that have this file open.
Based on an initial code idea from SATOH Fumiyasu <fumiya@samba.gr.jp>
********************************************************************/
BOOL rename_share_filename(struct share_mode_lock *lck,
const char *servicepath,
const char *newname)
{
struct file_renamed_message *frm = NULL;
size_t sp_len;
size_t fn_len;
size_t msg_len;
int i;
DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n",
servicepath, newname));
/*
* rename_internal_fsp() and rename_internals() add './' to
* head of newname if newname does not contain a '/'.
@ -658,13 +668,53 @@ BOOL rename_share_filename(struct share_mode_lock *lck,
newname += 2;
}
lck->filename = talloc_strdup(lck, newname);
lck->servicepath = talloc_strdup(lck, servicepath);
lck->filename = talloc_strdup(lck, newname);
if (lck->filename == NULL || lck->servicepath == NULL) {
DEBUG(0, ("rename_share_filename: talloc failed\n"));
return False;
}
lck->modified = True;
sp_len = strlen(lck->servicepath);
fn_len = strlen(lck->filename);
msg_len = sizeof(*frm) + sp_len + 1 + fn_len + 1;
/* Set up the name changed message. */
frm = TALLOC(lck, msg_len);
if (!frm) {
return False;
}
frm->dev = lck->dev;
frm->inode = lck->ino;
DEBUG(10,("rename_share_filename: msg_len = %d\n", msg_len ));
safe_strcpy(&frm->names[0], lck->servicepath, sp_len);
safe_strcpy(&frm->names[sp_len + 1], lck->filename, fn_len);
/* Send the messages. */
for (i=0; i<lck->num_share_modes; i++) {
struct share_mode_entry *se = &lck->share_modes[i];
if (!is_valid_share_mode_entry(se)) {
continue;
}
/* But not to ourselves... */
if (procid_is_me(&se->pid)) {
continue;
}
DEBUG(10,("rename_share_filename: sending rename message to pid %u "
"dev %x, inode %.0f sharepath %s newname %s\n",
(unsigned int)procid_to_pid(&se->pid),
(unsigned int)frm->dev, (double)frm->inode,
lck->servicepath, lck->filename ));
message_send_pid(se->pid, MSG_SMB_FILE_RENAME,
frm, msg_len, True);
}
return True;
}

View File

@ -227,20 +227,43 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
*/
if (normal_close && delete_file) {
SMB_STRUCT_STAT sbuf;
DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n",
fsp->fsp_name));
if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
/*
* This call can potentially fail as another smbd may have
* had the file open with delete on close set and deleted
* it when its last reference to this file went away. Hence
* we log this but not at debug level zero.
*/
DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \
with error %s\n", fsp->fsp_name, strerror(errno) ));
/* We can only delete the file if the name we have
is still valid and hasn't been renamed. */
if(SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) != 0) {
DEBUG(5,("close_file: file %s. Delete on close was set "
"and stat failed with error %s\n",
fsp->fsp_name, strerror(errno) ));
} else {
if(sbuf.st_dev != fsp->dev || sbuf.st_ino != fsp->inode) {
DEBUG(5,("close_file: file %s. Delete on close was set and "
"dev and/or inode does not match\n",
fsp->fsp_name ));
DEBUG(5,("close_file: file %s. stored dev = %x, inode = %.0f "
"stat dev = %x, inode = %.0f\n",
fsp->fsp_name,
(unsigned int)fsp->dev, (double)fsp->inode,
(unsigned int)sbuf.st_dev, (double)sbuf.st_ino ));
} else if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
/*
* This call can potentially fail as another smbd may have
* had the file open with delete on close set and deleted
* it when its last reference to this file went away. Hence
* we log this but not at debug level zero.
*/
DEBUG(5,("close_file: file %s. Delete on close was set "
"and unlink failed with error %s\n",
fsp->fsp_name, strerror(errno) ));
}
process_pending_change_notify_queue((time_t)0);
}
process_pending_change_notify_queue((time_t)0);
}
talloc_free(lck);

View File

@ -2042,3 +2042,50 @@ files_struct *open_file_stat(connection_struct *conn, char *fname,
return fsp;
}
/****************************************************************************
Receive notification that one of our open files has been renamed by another
smbd process.
****************************************************************************/
void msg_file_was_renamed(int msg_type, struct process_id src, void *buf, size_t len)
{
files_struct *fsp;
struct file_renamed_message *frm = (struct file_renamed_message *)buf;
const char *sharepath;
const char *newname;
size_t sp_len;
if (buf == NULL || len < sizeof(*frm)) {
DEBUG(0, ("msg_file_was_renamed: Got invalid msg len %d\n", (int)len));
return;
}
sharepath = &frm->names[0];
newname = sharepath + strlen(sharepath) + 1;
sp_len = strlen(sharepath);
DEBUG(10,("msg_file_was_renamed: Got rename message for sharepath %s, new name %s, "
"dev %x, inode %.0f\n",
sharepath, newname, (unsigned int)frm->dev, (double)frm->inode ));
for(fsp = file_find_di_first(frm->dev, frm->inode); fsp; fsp = file_find_di_next(fsp)) {
if (memcmp(fsp->conn->connectpath, sharepath, sp_len) == 0) {
DEBUG(10,("msg_file_was_renamed: renaming file fnum %d from %s -> %s\n",
fsp->fnum, fsp->fsp_name, newname ));
string_set(&fsp->fsp_name, newname);
} else {
/* TODO. JRA. */
/* Now we have the complete path we can work out if this is
actually within this share and adjust newname accordingly. */
DEBUG(10,("msg_file_was_renamed: share mismatch (sharepath %s "
"not sharepath %s) "
"fnum %d from %s -> %s\n",
fsp->conn->connectpath,
sharepath,
fsp->fnum,
fsp->fsp_name,
newname ));
}
}
}

View File

@ -4082,13 +4082,15 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
}
/****************************************************************************
Ensure open files have their names updates.
Ensure open files have their names updated. Updated to notify other smbd's
asynchronously.
****************************************************************************/
static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, char *newname)
static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, const char *newname)
{
files_struct *fsp;
BOOL did_rename = False;
struct share_mode_lock *lck = NULL;
for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) {
DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n",
@ -4098,9 +4100,24 @@ static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T
did_rename = True;
}
if (!did_rename)
if (!did_rename) {
DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n",
(unsigned int)dev, (double)inode, newname ));
}
/* Notify all remote smbd's. */
lck = get_share_mode_lock(NULL, dev, inode, NULL, NULL);
if (lck == NULL) {
DEBUG(5,("rename_open_files: Could not get share mode lock for file %s\n",
fsp->fsp_name));
return;
}
/* Change the stored filename. */
rename_share_filename(lck, conn->connectpath, newname);
/* Send messages to all smbd's (not ourself) that the name has changed. */
talloc_free(lck);
}
/****************************************************************************
@ -4238,10 +4255,11 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
return NT_STATUS_OK;
}
if (errno == ENOTDIR || errno == EISDIR)
if (errno == ENOTDIR || errno == EISDIR) {
error = NT_STATUS_OBJECT_NAME_COLLISION;
else
} else {
error = map_nt_error_from_unix(errno);
}
DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
nt_errstr(error), fsp->fsp_name,newname));

View File

@ -330,6 +330,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
message_register(MSG_SMB_SAM_SYNC, msg_sam_sync);
message_register(MSG_SMB_SAM_REPL, msg_sam_repl);
message_register(MSG_SHUTDOWN, msg_exit_server);
message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed);
/* now accept incoming connections - forking a new process
for each incoming connection */

View File

@ -44,7 +44,7 @@ void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
while (*s == '/') {
s++;
}
if ((d != destname) && (*s != '\0')) {
if ((d > destname + 1) && (*s != '\0')) {
*d++ = '/';
}
start_of_name_component = True;
@ -119,6 +119,9 @@ void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
*(d-1) = '\0';
}
DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
lp_servicename(SNUM(conn)), destname ));
string_set(&conn->connectpath, destname);
}