簡體   English   中英

windows 網絡驅動器上的文件操作錯誤

[英]File operation error on windows network drives

最近我遇到了低級文件操作的問題(在舊的遺留代碼中)

fd = open(file, O_RDWR);
...
lseek(fd, 0L, SEEK_END);
write(fd, buffer, len);
...
lseek(fd, pos, SEEK_SET);
read(fd, buffer, len);

on Windows 10 (client), if the file is on a shared network drive provided by eg Windows Server 2012 or 2016. In case of Windows Server 2012 the SMB version of the connection is 3.02, for Windows Server 2016 it is 3.1.1.

錯誤不是每次或同時發生 position,有時 lseek() 的返回值表示錯誤,但大多數時候似乎 lseek() 沒有返回正確的 EOF position,或者 write() EOF 的操作在下一個 lseek() 之前沒有完成,這是一種同步/緩存問題。 還嘗試了 fsync(fd)(或 _commit(fd))、O_SYNC 和延遲,但似乎並不可靠。

使用 Windows 7 作為客戶端,它的工作方式就像在本地驅動器上工作了多年一樣。 此外,當我在 Linux 中安裝該驅動器時,它適用於 SMB 版本 2.1、3.02、3.1.1。

所以我的問題是,SMB 協議、網絡共享和 Windows 10 是否存在已知問題,從而影響 lseek() 等這些低級文件操作?

更新:

這是一個例子

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>

#ifdef _WIN32
    #include <io.h>
#else
    #include <unistd.h>
    #define  _O_CREAT   O_CREAT
    #define  _O_RDWR    O_RDWR
    #define  _S_IREAD   S_IREAD
    #define  _S_IWRITE  S_IWRITE
    #define  _open      open
    #define  _write     write
    #define  _lseek     lseek
    #define  _close     close
#endif

char file[] = "file.txt";

int main() {

    int fd = 0;
    int ret = 0;
    int len = 0;
    off_t pos = 0;
    off_t last_eof = 0;
    char buffer[] = "12345";
    int buflen = 0;
    int n = 0;

    buflen = strlen(buffer);

    //unlink(file);

    fd = _open(file, _O_CREAT|_O_RDWR, _S_IREAD|_S_IWRITE);
    if (fd == -1) { fprintf(stderr, "ERROR open\n"); exit(1); }

    ret = _close(fd);
    if (ret == -1) { fprintf(stderr, "ERROR close\n"); exit(1); }

    for (n = 0; n < 10000; n++)
    {
        fd = _open(file, _O_RDWR, _S_IREAD|_S_IWRITE);
        if (fd == -1) { fprintf(stderr, "ERROR open [%d]\n", n); exit(1); }

        pos = _lseek(fd, 0, SEEK_END);
        if (pos == -1) { fprintf(stderr, "ERROR lseek1 [%d] pos: %ld\n", n, pos); exit(1); }
        if (last_eof > 0 && pos != last_eof) {
            fprintf(stderr, "ERROR [%d] eof: %ld last_eof: %ld\n", n, pos, last_eof);
            exit(1);
        }

        len = _write(fd, buffer, buflen);
        if (len != buflen) { fprintf(stderr, "ERROR write [%d]\n", n); exit(1); }

        pos = _lseek(fd, 0, SEEK_END);
        if (pos == -1) { fprintf(stderr, "ERROR lseek2 [%d] pos: %ld\n", n, pos); exit(1); }

        last_eof = pos;

        ret = _close(fd);
        if (ret == -1) { fprintf(stderr, "ERROR close [%d]\n", n); exit(1); }

        if (last_eof != (n+1)*buflen) {
            fprintf(stderr, "ERROR [%d] eof: %ld\n", n, last_eof);
            exit(1);
        }
    }

    fprintf(stdout, "[%d] EOF: %ld\n", n, last_eof);

    return 0;
}

(運行前刪除file.txt !)

用 Visual Studio 編譯,在 Windows 10 和網絡驅動器上執行,它碰巧以“eof-error”退出,例如

> seek5win.exe
ERROR [112] eof: 555 last_eof: 560

即文件以 eof/size 560 關閉,然后以 eof/size 555 重新打開。如果沒有其他進程訪問該文件,則完成而不會出錯。 但是,如果資源管理器或其他一些進程掃描目錄,則 lseek/eof-estimate 有時會關閉。 使用_sopen_s()和不同的 sh_flags 沒有幫助。

在 ProcessMonitor 中它看起來像這樣(當 Explorer 和 sublime-text 發揮作用時):

08:41:10,3133  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 540, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,3191  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,3192  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,3347  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,3460  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,3594  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 540, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,3643  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 539, Length: 1, Priority: Normal
08:41:10,3644  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 540, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,3754  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 540, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,3838  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 540, Length: 5
08:41:10,4013  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 545, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,4101  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,4102  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,4363  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,4537  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,4751  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 545, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,4870  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 544, Length: 1, Priority: Normal
08:41:10,4870  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 545, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,5171  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 545, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,5239  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 545, Length: 5
08:41:10,5375  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 550, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,5475  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,5476  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,5646  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,5957  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,6111  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 550, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,6210  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 549, Length: 1, Priority: Normal
08:41:10,6211  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 550, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,6418  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 550, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,6501  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 550, Length: 5
08:41:10,6547  Explorer.exe  QueryDirectory                \\;LanmanRedirector\...\file.txt  SUCCESS  Filter: file.txt, 1: file.txt
08:41:10,6715  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,6934  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,6935  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,6962  Explorer.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
08:41:10,7229  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,7408  Explorer.exe  QueryBasicInformationFile     \\;LanmanRedirector\...\file.txt  SUCCESS  CreationTime: 31.10.2019 08:41:00, LastAccessTime: 31.10.2019 08:41:00, LastWriteTime: 31.10.2019 08:41:12, ChangeTime: 31.10.2019 08:41:12, FileAttributes: A
08:41:10,7456  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,7483  Explorer.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,7585  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,7645  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 554, Length: 1, Priority: Normal
08:41:10,7646  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 555, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,7886  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,8013  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 555, Length: 5
08:41:10,8221  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 560, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,8246  sublime_.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
08:41:10,8319  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,8319  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,8453  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,8477  sublime_.exe  QueryBasicInformationFile     \\;LanmanRedirector\...\file.txt  SUCCESS  CreationTime: 31.10.2019 08:41:00, LastAccessTime: 31.10.2019 08:41:00, LastWriteTime: 31.10.2019 08:41:12, ChangeTime: 31.10.2019 08:41:12, FileAttributes: A
08:41:10,8679  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,8690  sublime_.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,8843  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,8918  sublime_.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
08:41:10,8925  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 554, Length: 1, Priority: Normal
08:41:10,9146  sublime_.exe  QueryBasicInformationFile     \\;LanmanRedirector\...\file.txt  SUCCESS  CreationTime: 31.10.2019 08:41:00, LastAccessTime: 31.10.2019 08:41:00, LastWriteTime: 31.10.2019 08:41:12, ChangeTime: 31.10.2019 08:41:12, FileAttributes: A
08:41:10,9167  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,9324  sublime_.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,9485  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  

它發生在 smb 版本 3.02 和 2.1 上。

在本地驅動器上,我從未觀察到這一點。 在 Windows 7 上,它在網絡驅動器上無錯誤地運行循環(掃描文件的其他進程可能使其非常慢)。 在 Linux 上,它也適用於網絡驅動器(mount -t cifs..)。

(部分答案和更多細節;解決方法)

write() 操作更新文件中的當前偏移量。 如果 write() 從 eof 開始,則新的偏移量成為新的 eof。 另一個文件句柄可能有不同的偏移量,盡管文件大小和 eof 應該是相同的(“全局”信息)。 因此,如果在為在 eof 處寫入的句柄更新當前偏移量之后更新 eof,並且如果操作系統(或某些驅動程序)沒有采取進一步的預防措施,則可能會發生lseek(fd, 0, SEEK_CUR)並且lseek(fd, 0, SEEK_END)返回不同的位置。

這是上面示例的更新,它在 Windows 10 和網絡驅動器上顯示了類似的內容。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <io.h>

char file[] = "file.txt";

int main() {

    int fd = 0;
    int ret = 0;
    int len = 0;
    off_t pos = 0,
          pos_eof = 0,
          last_pos = 0,
          last_eof = 0;
    char buffer[] = "12345";
    int buflen = 0;
    int n = 0;


    buflen = strlen(buffer);

    //unlink(file);

    fd = _open(file, _O_CREAT|_O_RDWR, _S_IREAD|_S_IWRITE);

    ret = _close(fd);

    for (n = 0; n < 10000; n++)
    {
        fd = _open(file, _O_RDWR, _S_IREAD|_S_IWRITE);

        pos_eof = _lseek(fd, 0, SEEK_END);
        if (last_eof > 0 && pos_eof != last_eof) {
            fprintf(stderr, "ERROR [%d] eof: %ld last_eof: %ld\n", n, pos_eof, last_eof);
            pos = _lseek(fd, 0, SEEK_CUR);
            fprintf(stderr, "CUR pos: %ld\n", pos);
            exit(1);
        }

        len = _write(fd, buffer, buflen);

        pos     = _lseek(fd, 0, SEEK_CUR);
        pos_eof = _lseek(fd, 0, SEEK_END);

        last_pos = pos;
        last_eof = pos_eof;

        ret = _close(fd);

        if (last_pos != (n+1)*buflen) {
            fprintf(stderr, "ERROR [%d] pos: %ld\n", n, last_pos);
            //exit(1);
        }
        if (last_eof != (n+1)*buflen) {
            fprintf(stderr, "ERROR [%d] eof: %ld (pos: %ld)\n", n, last_eof, last_pos);
            //exit(1);
        }
    }

    fprintf(stdout, "[%d] EOF: %ld\n", n, last_eof);

    return 0;
}

由於我從未從文件操作中得到錯誤<0,因此沒有錯誤處理。 如果沒有其他進程接觸(讀取)該文件,則它運行時不會出錯。 如果有其他進程打開文件,我通常會得到這樣的 output:

ERROR [460] eof: 2295 last_eof: 2300
CUR pos: 2295

如果我用 windows CreateFile、WriteFile、SetFilePointer、...(版本(b))替換 io 函數,它運行得更快,但我仍然得到例如

ERROR [39] eof: 195 (pos: 200)
ERROR [40] eof: 200 last_eof: 195
CUR pos: 200

類似 posix 的調用(調用 CreateFile、WriteFile、...)需要更多時間,並且看起來文件在 eof 更新之前已關閉。 重新打開后最后 5 個字節消失了。

在 windows 版本 (b) 中,windows 調用顯示當前 position 和 eof 之間的差異,eof 不是最新的,當 SetFilePointer 被第二次調用時

        pos     = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); //_lseek(fd, 0, SEEK_CUR)
        pos_eof = SetFilePointer(hFile, 0, NULL, FILE_END); //_lseek(fd, 0, SEEK_END);

但是關閉后文件大小就可以了。

編輯:也張貼在這里

https://social.msdn.microsoft.com/Forums/en-US/56f3cdf6-c14b-4053-aaeb-e121706f2866/ioh-file-operations?forum=vcgeneral

更新:

如上面鏈接中所述,設置以下win10注冊表項可以規避問題(據我測試......):

HKLM\system\currentcontrolset\services\lanmanworkstation\parameters
FileInfoCacheLifetime       REG_DWORD 0x0
FileNotFoundCacheLifetime   REG_DWORD 0x0
DirectoryCacheLifetime      REG_DWORD 0x0

看起來像 smb 協議的緩存參數,必須閱讀更多信息。 我相信默認值是不同的; 如果它在不設置這些值(為零)的情況下工作,那就太好了。

此處還描述了解決方法https://answers.microsoft.com/en-us/msoffice/forum/msoffice_access-mso_winother-msoversion_other/access-database-is-getting-corrupt-again-and-again/d3fcc0a2-7d35- 4a09-9269-c5d93ad0031d?messageId=c9ddd419-da56-42dd-a7ca-f93d29cf2c7f&page=13&auth=1 (Windows 10 中的租賃模式中的一個錯誤影響 Access 數據庫)

信息:

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-7/ff686200(v=ws.10)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM