Bug 1729 - file modtimes can get stale
Summary: file modtimes can get stale
Status: CLOSED FIXED
Alias: None
Product: Samba 3.0
Classification: Unclassified
Component: File Services (show other bugs)
Version: 3.0.4
Hardware: All All
: P3 normal
Target Milestone: none
Assignee: Samba Bugzilla Account
QA Contact: Samba QA Contact
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-09-07 11:27 UTC by Terence H Dineen
Modified: 2005-08-24 10:18 UTC (History)
5 users (show)

See Also:


Attachments
Patch for smbd/trans2.c (821 bytes, patch)
2004-11-23 05:48 UTC, Sarah Livne
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Terence H Dineen 2004-09-07 11:27:32 UTC
When smbd receives SMB Transact2 SetFileInfo command setting the modification
timestamp of the opened file, it keeps the timestamp in the pending_modtime
field and skips file_utime(). (See call_trans2setfilepathinfo() in
"source/smbd/trans2.c".) Thus, the follow-on SMB Transact2 QueryFileInfo command
(by the same process and others) asking the modtime of this opened file returns
the stale information (despite the fact that SetFileInfo command succeeded). The
modtime is updated when SMB CloseFile command is received, but by that time the
clients may have already cached the last modtime (which is stale!). This
behavior breaks the applications which rely on the modtime to detect the file
change.

smbd should call file_utime() after saving the pending_modtime. (Note: The
pending_modtime is still needed to set it at SMB CloseFile.)

Here is the sample test program.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef _UNICODE
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
#else
int main(int argc, char *argv[], char *envp[])
#endif
{
    HANDLE fh = INVALID_HANDLE_VALUE;
    const DWORD da = GENERIC_READ|GENERIC_WRITE;
    const DWORD sm = FILE_SHARE_READ|FILE_SHARE_WRITE;
    TCHAR *fp = NULL;
    DWORD n = 1;
    FILETIME lwt;
    DWORD i;
    BOOL failed = FALSE;

    if (argc < 2) {
	_ftprintf(stderr, _TEXT("Usage: %s pathname [count]\n"), argv[0]);
	exit(2);
    }

    fp = argv[1];

    if (argc > 2)
        n = _tcstoul((const TCHAR *)argv[2], NULL, 0);

    _ftprintf(stdout, _TEXT("%s %u\n"), fp, n);

    if ((fh = CreateFile(fp, da, sm,
                         NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
                         NULL)) == INVALID_HANDLE_VALUE) {
        _ftprintf(stderr, _TEXT("CreateFile(%s): %u\n"),
                  fp, GetLastError());
        return 1;
    }

    if (!GetFileTime(fh, NULL, NULL, &lwt)) {
        _ftprintf(stderr, _TEXT("GetFileTime(%s): %u\n"),
                  fp, GetLastError());
        return 1;
    }

    for (i = 0; i < n; i++) {
        FILETIME wt = lwt;
        FILETIME new_t;
        DWORDLONG t;

        t = ((DWORDLONG)(wt.dwHighDateTime) << 32)
            | (DWORDLONG)(wt.dwLowDateTime);
        t += (10*1000*1000);	/* +1 second */

        new_t.dwHighDateTime = (DWORD)((t >> 32) & 0xffffffff);
        new_t.dwLowDateTime = (DWORD)(t & 0xffffffff);

        if (!SetFileTime(fh, NULL, NULL, &new_t)) {
            _ftprintf(stderr, _TEXT("SetFileTime(%s): %u\n"),
                      fp, GetLastError());
            return 1;
        }

        if (!GetFileTime(fh, NULL, NULL, &lwt)) {
            _ftprintf(stderr, _TEXT("GetFileTime(%s): %u\n"),
                      fp, GetLastError());
            return 1;
        }

        if (CompareFileTime(&lwt, &new_t) != 0) {
            _ftprintf(stderr, _TEXT("**** The new time is different!\n"));
            failed = TRUE;
        }

        if (CompareFileTime(&lwt, &wt) == 0) {
            _ftprintf(stderr, _TEXT("**** Not changed from the previous!\n"));
            failed = TRUE;
        }
    }

    if (!CloseHandle(fh)) {
        _ftprintf(stderr, _TEXT("CloseHandle(): %u\n"), GetLastError());
        return 1;
    }

    if (failed) {
        FILETIME wt = lwt;

        if ((fh = CreateFile(fp, da, sm,
                             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
                             NULL)) == INVALID_HANDLE_VALUE) {
            _ftprintf(stderr, _TEXT("CreateFile(%s): %u\n"),
                      fp, GetLastError());
            return 1;
        }

        if (!GetFileTime(fh, NULL, NULL, &lwt)) {
            _ftprintf(stderr, _TEXT("GetFileTime(%s): %u\n"),
                      fp, GetLastError());
            return 1;
        }

        if (CompareFileTime(&lwt, &wt) != 0)
            _ftprintf(stderr, _TEXT("**** Changed after CloseHandle()!\n"));

        if (!CloseHandle(fh)) {
            _ftprintf(stderr, _TEXT("CloseHandle(): %u\n"), GetLastError());
            return 1;
        }
    }

    return 0;
}
Comment 1 Paul Jesze 2004-09-27 03:41:19 UTC
We (Swiss Life, Zurich, Switzerland) would like to reference against this bug.
We have an interop ClearCase environment, using Samba 2.2.8a on ClearCase 
2003.06.00 Solaris 5.8 servers, and are receiving out-of-sync errors from the 
Eclipse IDE when writing to files. This behaviour was originally thought to be 
an Eclipse problem. However, the support, resp. research from IBM proved this 
assumption to be wrong and identified it as a samba bug.

Paul Jesze
paul.jesze@swisslife.ch
Comment 2 Paul Jesze 2004-09-27 03:58:00 UTC
Correction to our last comment:

This was thought to be a problem with ClearCase and/or the ClearCase-Eclipse 
plugin.

Paul Jesze
paul.jesze@swisslife.ch
Comment 3 Sarah Livne 2004-11-23 05:48:35 UTC
Created attachment 805 [details]
Patch for smbd/trans2.c

The attached patch worked for me and solved the bug demonstrated by the
above-mentioned test application.
In the function that handles query_path_info transactions, it first checks if
it has a pending_modtime on this opened file, and if so - returns it instead of
the stale st_mtime. 
Please consider adding this patch to the next release
Comment 4 Jeremy Allison 2004-11-23 10:47:21 UTC
This patch (or something very similar) has gone into the SVN and will be in
Samba 3.0.10.
Jeremy.
Comment 5 Nick Hemsley 2004-12-22 22:36:46 UTC
Has this pach gone in? I am getting similar problems using eclipse editing files
on a samba share, even after updating to samba 3.0.10 (debian unstable), I
cannot find the patch in the file trans2.c, but havent looked too hard for
something similar.
Comment 6 Nick Hemsley 2004-12-22 23:43:38 UTC
I have rebuilt samba-3.0.10 on debian unstable with the patch applied, and it
seems to fix the problems I have been having (although strangely, changing back
to the old smbd does not yeild as many (only 1) out-of-sync errors... hmm).

Has this patch been lost in the ether? perhaps consider re-opening this until
the patch is applied.
Comment 7 Jeremy Allison 2004-12-23 10:07:54 UTC
Unfortunately this patch didn't make it into 3.0.10 as this was a security-only
release. This fix will officially be in 3.0.11 (so long as there isn't another
security release :-).
Jeremy.
Comment 8 Gerald (Jerry) Carter (dead mail address) 2005-08-24 10:18:14 UTC
sorry for the same, cleaning up the database to prevent unecessary reopens of bugs.