vfs_stat called but ignored when client has dir open

Andrew Klaassen clawsoon at yahoo.com
Mon Apr 23 12:00:25 MDT 2012


I've got a VFS stat function that replaces the mtime on a directory with the mtime from another directory.  It works as designed except when the client has the directory open in another window.  In that case, the VFS function does the right thing, but its result is ignored and the client always gets the mtime that the directory had when the client first opened it.

Is this a feature, a bug, or me screwing something up?

To replicate, use the simplified VFS stat function below, then:

 1. Create testdir and testdir.foo.
 2. Open testdir in a Windows Explorer window and leave it open.
 3. A few minutes later, create or delete a file in testdir.foo from another Windows Explorer window.
 4. Refresh the share's root directory listing on Windows.  Instead of testdir getting the latest mtime of testdir.foo as expected, it will get the mtime of whatever testdir.foo was when the testdir window was opened - a bad result for me.

If you skip step 2, everything works as expected.  Close the window opened in step 2 and refresh again, and everything works as expected.  Only with this exact sequence does the bad result appear.

Wireshark confirms that Samba is returning the bad result for both SMB1 and SMB2, so it's not a Windows caching thing.

The debug output confirms that the VFS stat function is being called and is returning the right result.

So... it looks like Samba is calling the VFS stat function afresh each time, but returning an old stat result while the client has a Windows Explorer window open in the directory in question.

I've been digging through Samba code this morning trying to figure out why and where this happens, but haven't pinned it down yet.  Does anyone know offhand, and/or know where to point me?  (Or, better yet, a way to get around it?)

Here's a simplified version of the VFS stat function in question, with error handling removed for readability:

static int vfs_stat_fname_stat(vfs_handle_struct *handle,
                           struct smb_filename *smb_fname)
{
        DEBUG(0, ("smb_fname->base_name '%s'\n", smb_fname->base_name));

        int ret = -1;

        char *fakeStatPath;
        SMB_STRUCT_STAT fakeStat;
        TALLOC_CTX *ctx = talloc_tos();

        ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
        DEBUG(0, ("Before: smb_fname->st.st_ex_mtime %s\n",
                        ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
        fakeStatPath = talloc_strdup(ctx, smb_fname->base_name);
        fakeStatPath = talloc_strdup_append(fakeStatPath, ".foo");
        if (sys_stat(fakeStatPath, &fakeStat,
                        lp_fake_dir_create_times(SNUM(handle->conn))))
        {
                goto nofakestat;
        }

        smb_fname->st.st_ex_mtime = fakeStat.st_ex_mtime;

nofakestat:

        DEBUG(0, ("After: smb_fname->st.st_ex_mtime %s\n",
                        ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
        return ret;
}

You can find a similar function that exhibits similar behaviour in the media_harmony module attached to bug 8841.

Thanks.

Andrew




More information about the samba-technical mailing list