开发者

Documented SetFileTime() procedure to preserve LastAccessTime not working for UNC paths

There is a documented method from Microsoft on how to prevent the last access time from being updated by operations on a file handle. I have used this method successfully accessing files locally, but not remotely. Should this work for remote files as well?

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

#include <string>

#define FAIL(x) { printf(x" FAILED: %d\n", GetLastError()); exit(-1); }

static std::wstring GetDateTimeString(SYSTEMTIME* datetime)
{
    TCHAR buffer[256];
    TCHAR* current = buffer;

    int idx = GetDateFormat(LOCALE_SYSTEM_DEFAULT,NULL, datetime, L"dd-MMM-yyyy", current, 256);

    if(idx > 0)
    {
        buffer[idx -1] = ' ';
        current += idx;
        int idx2 = GetTimeFormat(LOCALE_SYSTEM_DEFAULT,NULL, datetime, L"HH:mm:ss", current, 256 - idx);
        if(idx2 > 0)
        {
            current += idx2 - 1;
            _sntprintf(current, 256 - (idx + idx2), L".%d", datetime->wMilliseconds);
        }
        else
            FAIL("GetTimeFormat");
    }
    else
        FAIL("GetDateFormat");

    return std::wstring(buffer);
}

static void ReportLastAccessTime(TCHAR* path)
{
    WIN32_FILE_ATTRIBUTE_DATA data;

    if(GetFileAttributesEx(path, GetFileExInfoStandard, &data))
    {
        SYSTEMTIME accessSysTime;

        if(FileTimeToSystemTime(&data.ftLastAccessTime, &accessSysTime))
        {
            SYSTEMTIME nowSysTime;
            GetSystemTime(&nowSysTime);
            printf("(%S) LastAccess=%S\n", GetDateTimeString(&nowSysTime).c_str(), GetDateTimeString(&accessSysTime).c_str());
        }
        else
            FAIL("FileTimeToSystemTime");
    }
    else
        FAIL("GetFileAttributesEx");
}

static void TestPreservingLastAccessTime(TCHAR* path)
{
    printf("Checking times before opening the file handle...\n");
    ReportLastAccessTime(path);

    HANDLE hFile = CreateFile(
           path,
           GENERIC_READ | FILE_WRITE_ATTRIBUTES,
           FILE_SHARE_READ,
           NULL,
           OPEN_EXISTING,
           0,
           NULL);

    if(hFile != INVALID_HANDLE_VALUE)
    {
        static const FILETIME ftLeaveUnchanged = { 0xFFFFFFFF, 0xFFFFFFFF };

        printf("Handle open, SetFileTime -1...\n");
        if(SetFileTime(hFile, NULL, &ftLeaveUnchanged, NULL))
        {
            char buf[512];
            DWORD numRead = 0;

            printf("Checking times after opening handle and SetFileTime...\n");
            ReportLastAccessTime(path);

            printf("Reading the file开发者_JAVA百科...\n");
            long total = 0;

            while (ReadFile(hFile, buf, sizeof(buf), &numRead, NULL))
            {
                if (numRead == 0) break;
                total += numRead;
                printf("Read: %d bytes (total=%d)\n", numRead, total);
                Sleep(1000);
            }

            printf("Checking times after reading the file...\n");
            ReportLastAccessTime(path);

            printf("Sleeping 30\n");
            Sleep(30 * 1000);

            printf("Checking times after reading the file before closing the file...\n");
            ReportLastAccessTime(path);

            printf("Closing the file\n");
            CloseHandle(hFile);

            printf("Sleeping 30\n");
            Sleep(30 * 1000);

            printf("Checking times after closing the file...\n");
            ReportLastAccessTime(path);
       }
       else
       {
           CloseHandle(hFile);
           FAIL("SetFileTime");
       }
    }
    else
        FAIL("CreateFile");
}

int _tmain(int argc, TCHAR* argv[])
{
    TCHAR* localPath = L"C:\\tmp\\file.txt";
    TCHAR* uncPath = L"\\\\localhost\\C$\\tmp\\file.txt";

    printf("Testing local path: %S\n", localPath);
    TestPreservingLastAccessTime(localPath);

    printf("Sleeping 30\n");
    Sleep(30 * 1000);

    printf("Testing UNC path: %S\n", uncPath);
    TestPreservingLastAccessTime(uncPath);

    return 0;
}

The results of running the above:

Testing local path: C:\tmp\file.txt
Checking times before opening the file handle...
(08-Nov-2011 21:06:18.432) LastAccess=08-Nov-2011 19:50:20.833
Handle open, SetFileTime -1...
Checking times after opening handle and SetFileTime...
(08-Nov-2011 21:06:18.432) LastAccess=08-Nov-2011 19:50:20.833
Reading the file...
Read: 512 bytes (total=512)
....
Read: 512 bytes (total=7680)
Checking times after reading the file...
(08-Nov-2011 21:06:33.432) LastAccess=08-Nov-2011 19:50:20.833
Sleeping 30
Checking times after reading the file before closing the file...
(08-Nov-2011 21:07:03.432) LastAccess=08-Nov-2011 19:50:20.833
Closing the file
Sleeping 30
Checking times after closing the file...
(08-Nov-2011 21:07:33.432) LastAccess=08-Nov-2011 19:50:20.833
Sleeping 30
Testing UNC path: \\localhost\C$\tmp\file.txt
Checking times before opening the file handle...
(08-Nov-2011 21:08:03.448) LastAccess=08-Nov-2011 19:50:20.833
Handle open, SetFileTime -1...
Checking times after opening handle and SetFileTime...
(08-Nov-2011 21:08:03.448) LastAccess=08-Nov-2011 19:50:20.833
Reading the file...
Read: 512 bytes (total=512)
....
Read: 512 bytes (total=7680)
Checking times after reading the file...
(08-Nov-2011 21:08:18.448) LastAccess=08-Nov-2011 19:50:20.833
Sleeping 30
Checking times after reading the file before closing the file...
(08-Nov-2011 21:08:48.448) LastAccess=08-Nov-2011 19:50:20.833
Closing the file
Sleeping 30
Checking times after closing the file...
(08-Nov-2011 21:09:18.448) LastAccess=08-Nov-2011 21:08:48.448


The request you did not recognize is

#define FSCTL_READ_FILE_USN_DATA        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58,  METHOD_NEITHER, FILE_ANY_ACCESS) // Read the Usn Record for a file

Which is docomented here

If this is sent for the handle you are using before the SET_FILE_INFO then that would explain why you were unable to diable last access time change.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜