diff options
author | Jeremy Allison <jra@samba.org> | 2005-12-13 18:11:50 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:05:49 -0500 |
commit | ab7a4f7e8e4b946a8acd0a205c16dbf6a3afecad (patch) | |
tree | d91dcd5c2a731925cec24e67c5a4e78dd3b7dac0 /source3/smbd | |
parent | 7d2771e758d4e8ef0adb45e55775b524de4dba9a (diff) | |
download | samba-ab7a4f7e8e4b946a8acd0a205c16dbf6a3afecad.tar.gz samba-ab7a4f7e8e4b946a8acd0a205c16dbf6a3afecad.tar.bz2 samba-ab7a4f7e8e4b946a8acd0a205c16dbf6a3afecad.zip |
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 used to be commit 932e337db8788e75344e1c7cf1ef009d090cb039)
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/close.c | 45 | ||||
-rw-r--r-- | source3/smbd/open.c | 47 | ||||
-rw-r--r-- | source3/smbd/reply.c | 28 | ||||
-rw-r--r-- | source3/smbd/server.c | 1 | ||||
-rw-r--r-- | source3/smbd/service.c | 5 |
5 files changed, 109 insertions, 17 deletions
diff --git a/source3/smbd/close.c b/source3/smbd/close.c index d84b9f925b..407c607838 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -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); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index b3f0589dc7..7621ee001d 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -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 )); + } + } +} diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index d3739c8847..5ddba4c2bf 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -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)); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 1bf9dbc374..304f1b588e 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -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 */ diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 210edde5d8..c9e2cdcf50 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -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); } |