summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2005-12-13 18:11:50 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:05:49 -0500
commitab7a4f7e8e4b946a8acd0a205c16dbf6a3afecad (patch)
treed91dcd5c2a731925cec24e67c5a4e78dd3b7dac0 /source3/smbd
parent7d2771e758d4e8ef0adb45e55775b524de4dba9a (diff)
downloadsamba-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.c45
-rw-r--r--source3/smbd/open.c47
-rw-r--r--source3/smbd/reply.c28
-rw-r--r--source3/smbd/server.c1
-rw-r--r--source3/smbd/service.c5
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);
}