Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File 重复文件句柄以避免共享冲突错误消息_File_Winapi_Api_Duplicates_Handler - Fatal编程技术网

File 重复文件句柄以避免共享冲突错误消息

File 重复文件句柄以避免共享冲突错误消息,file,winapi,api,duplicates,handler,File,Winapi,Api,Duplicates,Handler,我尝试在增量备份系统上工作,当我运行脚本时,由于共享冲突,我总是得到无法打开的文件,因为我尝试打开以执行增量备份的文件已被另一个进程使用。 我知道我可以终止这个过程,释放文件并进行增量备份,但这是我必须避免的事情。 我已经读到,通过Win32 API,我可以复制文件处理程序,所以我应该怎么做 下面是我的一段代码: FILE *GetFileHandle(WIN32_FIND_DATA *pWfdStruct, BOOL bWrite){ FILE *fFile; DWORD nGLE; fF

我尝试在增量备份系统上工作,当我运行脚本时,由于共享冲突,我总是得到无法打开的文件,因为我尝试打开以执行增量备份的文件已被另一个进程使用。 我知道我可以终止这个过程,释放文件并进行增量备份,但这是我必须避免的事情。 我已经读到,通过Win32 API,我可以复制文件处理程序,所以我应该怎么做

下面是我的一段代码:

FILE *GetFileHandle(WIN32_FIND_DATA *pWfdStruct, BOOL bWrite){

FILE *fFile;
DWORD nGLE;

fFile = fopen(pWfdStruct->cFileName, "rb");
if (!fFile)
{
    nGLE = GetLastError();

    if (nGLE == ERROR_SHARING_VIOLATION)    // 32
    {
        char szCurDir[8192];

        GetCurrentDirectory(8192, szCurDir);
        ODS("WARN: cannot open %s file due to sharing violation [fRenameFile: %s\\%s]\n",
            bWrite ? "dst" : "src", szCurDir, pWfdStruct->cFileName);
        return 0;
    }

    if (nGLE == ERROR_ACCESS_DENIED)        // 5
    {
        char szCurDir[8192];

        GetCurrentDirectory(8192, szCurDir);
        ODS("WARN: cannot open %s file, access denied [fRenameFile: %s\\%s]\n",
            bWrite ? "dst" : "src", szCurDir, pWfdStruct->cFileName);
        return 0;
    }

    if (nGLE == ERROR_FILE_NOT_FOUND)       // 2
    {
        char szCurDir[8192];

        GetCurrentDirectory(8192, szCurDir);
        ODS("WARN: cannot open %s file, file not present [fRenameFile: %s\\%s]\n",
            bWrite ? "dst" : "src", szCurDir, pWfdStruct->cFileName);
        return 0;
    }

    char szCurDir[8192];
    GetCurrentDirectory(8192, szCurDir);

    if (bWrite)
    {
        ODS("WARN: cannot open dst file [fRenameFile: %s\\%s] [GLE: %d]\n",
            szCurDir, pWfdStruct->cFileName, nGLE);
        return 0;
    }

    ODS("WARN: cannot open src file [fRenameFile: %s\\%s] [GLE: %d] trying alt name [%s]\n",
        szCurDir, pWfdStruct->cFileName, nGLE, pWfdStruct->cAlternateFileName);
    ReportSystemError("GetFileHandle", nGLE);

    __try
    {
        if (pWfdStruct->cAlternateFileName[0])
        {
            fFile = fopen(pWfdStruct->cAlternateFileName, "rb");
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        ODS("Exception caught\n");  // give up
    }

    if (!fFile)
    {
        nGLE = GetLastError();
        ReportSystemError("GetFileHandle 2nd try", nGLE);
        FATALODS("FATAL error, cannot open src file [%s] [GLE: %d]", pWfdStruct->cFileName, nGLE);
    }
    else
    {
        ODS("File: %s open success\n", pWfdStruct->cAlternateFileName);
    }
}
return fFile;} // GetFileHandle

您能帮助我吗?

如果文件被其他进程锁定,您将无法打开它。句号

Windows有专门用于构建备份客户端的服务VSS。它提供了复制锁定文件、确保快照一致性等功能。API有点复杂,但如果您想要一个强健的备份解决方案,则没有其他方法

您可以查看一个开源备份工具,以获取使用VSS的示例

编辑:在谷歌搜索之后,我找到了两个你想要的例子。我不能保证这些工作,但至少看起来是合理的

第一个例子,清晰且注释良好,语言是一些基本方言,但可读性很强:

$include "windowssdk.inc"
$include "ntddk.inc"
$include "undocumented.inc"
$include "stdio.inc"
$use "_crtdll.lib"


'-------------------------- example
$include "shlwapi.inc"
$define REPLACE_ALWAYS
' open youtube in internet explorer, watch any video (should be downloaded in 100%)
' then run this program to copy the locked fla***.tmp file from your TEMP directory
istring tmppath[MAX_PATH]

' 1. enumerate fla*.tmp files in TEMP directory
ExpandEnvironmentStrings("%TEMP%\\", tmppath, MAX_PATH)
int pathlen = len(tmppath)
strcpy(&tmppath[pathlen], "fla*.tmp")
UINT hFind = findopen(tmppath)
int nFilesFound = 0
int nFilesCopied = 0

if (hFind)
    istring name[256] = findnext(hFind)
    while (name[0] <> 0)

        strncpy(&tmppath[pathlen], name, MAX_PATH-pathlen)
        ' tmppath = local path to flash video

        ' 2. copy the file with renamed extension (supported by media player classic)
        istring newpath[MAX_PATH]
        newpath = tmppath
        PathRenameExtension(newpath, ".flv")

        ' check if we can open the file directly
        HANDLE hFile = CreateFile(tmppath, GENERIC_READ, FILE_SHARE_READ _
            | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, 0, 0)

        if (hFile <> INVALID_HANDLE_VALUE)
            ' file opened, so you can copy it with your favorite file manager
            CloseHandle(hFile)

        else

            nFilesFound++
            ' the file is opened with exclusive access, call the subroutine below to open it
            HANDLE hProcess
            hFile = OpenFileEx(tmppath, &hProcess)
            if (hFile = INVALID_HANDLE_VALUE)
                ' failed
                MessageBox 0, "failed to open " + tmppath, ""
            else
                ' copy it now ...
$ifdef REPLACE_ALWAYS
                HANDLE hOutFile = CreateFile(newpath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0)
$else
                HANDLE hOutFile = CreateFile(newpath, GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0)
$endif
                if (hOutFile = INVALID_HANDLE_VALUE)
                    ' failed ?
                    MessageBox 0, "failed to create " + newpath, ""
                else
                    ' ... but first suspend the owner process (because the handle is duplicated, and
                    ' if the owner process changes file pointer, it will be reflected also in this process)
                    declare import, NtSuspendProcess(HANDLE hProcess), NTSTATUS
                    declare import, NtResumeProcess(HANDLE hProcess), NTSTATUS
                    NtSuspendProcess(hProcess)

                    ' save original file pointer in originalFilePos variable
                    LARGE_INTEGER originalFilePos
                    LARGE_INTEGER nullFilePos
                    nullFilePos.QuadPart = 0q
                    SetFilePointerEx(hFile, nullFilePos, &originalFilePos, FILE_CURRENT)

                    ' seek to beginning
                    SetFilePointerEx(hFile, nullFilePos, NULL, FILE_BEGIN)

                    '  copy, using string name as the buffer
                    DWORD BytesRead, BytesWriten
                    while (ReadFile(hFile, &name, 256, &BytesRead, 0) and BytesRead)
                        WriteFile(hOutFile, name, BytesRead, &BytesWriten, 0)
                    endwhile
                    '
                    nFilesCopied++
                    ' restore file pointer
                    SetFilePointerEx(hFile, originalFilePos, NULL, FILE_BEGIN)
                    ' cleanup
                    CloseHandle(hOutFile)
                    ' resume the process
                    NtResumeProcess(hProcess)
                endif
                CloseHandle(hFile)
            endif
        endif
        name = findnext(hFind)
    endwhile

    findclose(hFind)
endif

if (MessageBox(0, using("Copied # from # locked .FLV files. Open Directory ?", nFilesCopied, nFilesFound), "", MB_YESNO) = IDYES)
    tmppath[pathlen-1] = 0
    system tmppath
endif

'-------------------------- code

type SYSTEM_HANDLE_ENTRY
    ULONG OwnerPid
    BYTE ObjectType
    BYTE HandleFlags
    USHORT HandleValue
    PVOID ObjectPointer
    ACCESS_MASK GrantedAccess
endtype

type SYSTEM_HANDLE_INFORMATION
    ULONG HandleCount
    SYSTEM_HANDLE_ENTRY Handles[1]
endtype

type MY_OBJECT_TYPE_INFORMATION
    OBJECT_TYPE_INFORMATION t
    iwstring buffer[64]
endtype

type MY_OBJECT_NAME_INFORMATION
    OBJECT_NAME_INFORMATION t
    iwstring buffer[280]
endtype

declare import, NtQuerySystemInformation(_
    int SystemInformationClass,_
    PVOID SystemInformation,_
    ULONG SystemInformationLength,_
    pointer ReturnLength),NTSTATUS

const SystemHandleInformation = 16




sub OpenFileEx(string path, pointer pphProcess),HANDLE
    MY_OBJECT_TYPE_INFORMATION htype
    MY_OBJECT_NAME_INFORMATION name

    *<HANDLE>pphProcess = 0
    HANDLE h = INVALID_HANDLE_VALUE

    ' convert c:\ to \Device\HardDiskVolume...
    ' 1. extract partition letter
    iwstring root[4]
    root[0] = path[0], 58, 0
    ' 2. convert it to \Device\HardDiskVolumeX
    iwstring wszNTPath[280]
    int cch = QueryDosDeviceW(root, wszNTPath, 280)
    if (!cch) then return INVALID_HANDLE_VALUE
    ' 3. append remaining folders and file name from string path parameter
    ' so <path> "c:\Program Files" gets converted to <wszNTPath> "\Device\HardDiskVolume1\Program Files"
    cch = wcslen(wszNTPath)
    _snwprintf(&wszNTPath[cch], 280-cch, L"%S", &path[2])
    ' now get the list of all handles, and find the handle which name is equal to wszNTPath

    ULONG BytesNeeded, BufferSize = 4096
    pointer handles = new(char, BufferSize) ' SYSTEM_HANDLE_INFORMATION*

    while (handles)

        ' get the list of all user-mode handles
        NTSTATUS status = NtQuerySystemInformation(SystemHandleInformation, handles, BufferSize, &BytesNeeded)
        if (status = STATUS_INFO_LENGTH_MISMATCH)

            ' BytesNeeded is not adjusted, so we need to increase buffer size
            delete handles
            BufferSize += 32768
            handles = new(char, BufferSize)

        elseif (!status)

            settype handles, SYSTEM_HANDLE_INFORMATION
            ' sort handles by owning process id
            qsort(&*handles.Handles, *handles.HandleCount, len(SYSTEM_HANDLE_ENTRY), &SortHandlesCb)

            pointer node = *handles.Handles
            settype node, SYSTEM_HANDLE_ENTRY
            ULONG OwnerPid = 0
            HANDLE hProcess = 0
            HANDLE hThisProcess = GetCurrentProcess()
            BYTE ObjectTypeFile = 0

            while (*handles.HandleCount)

                *handles.HandleCount--

                if (*node.GrantedAccess & FILE_READ_DATA) ' 13019F

                    if (OwnerPid <> *node.OwnerPid)

                        OwnerPid = *node.OwnerPid
                        if (hProcess) then CloseHandle(hProcess)
                        hProcess = OpenProcess(PROCESS_DUP_HANDLE|PROCESS_SUSPEND_RESUME, FALSE, OwnerPid)

                    endif
                    if (hProcess)

                        HANDLE hObject
                        if (DuplicateHandle(hProcess, *node.HandleValue, hThisProcess, &hObject, 0, FALSE, DUPLICATE_SAME_ACCESS))

                            if (GetFileType(hObject) = FILE_TYPE_DISK)

                                if (!ObjectTypeFile) ' query object type name as "integer"

                                    if (!NtQueryObject(hObject, ObjectTypeInformation, &htype, len(htype), &BytesNeeded))

                                        if (!_wcsnicmp(htype.t.TypeName.Buffer, L"File", 4))
                                            ObjectTypeFile = *node.ObjectType
                                        endif
                                    endif
                                endif

                                ' do not query object name with granted access 0x0012019f (deadloock)
                                if (ObjectTypeFile and (ObjectTypeFile = *node.ObjectType) and (*node.GrantedAccess <> 0x0012019f))

                                    ' query file name
                                    if (!NtQueryObject(hObject, ObjectNameInformation, &name, len(name), &BytesNeeded))

                                        if (name.t.Name.Buffer and !wcsicmp(name.t.Name.Buffer, wszNTPath)) ' compare

                                            *<HANDLE>pphProcess = hProcess
                                            delete handles
                                            return hObject
                                        endif
                                    endif
                                endif
                            endif
                            CloseHandle(hObject)
                        endif
                    endif
                endif
                node = &*node[1]
            endwhile
            if (hProcess) then CloseHandle(hProcess)
            delete handles

        else
            ' NtQuerySystemInformation failed
            delete handles
        endif

    endwhile

    if (handles) then delete handles
    return h
endsub


declare cdecl SortHandlesCb(SYSTEM_HANDLE_ENTRY p1, SYSTEM_HANDLE_ENTRY p2),int

sub SortHandlesCb(SYSTEM_HANDLE_ENTRY p1, SYSTEM_HANDLE_ENTRY p2),int
    if (p1.OwnerPid = p2.OwnerPid) then return 0
    if (p1.OwnerPid > p2.OwnerPid) then return 1
    return -1
endsub
另一个混乱的例子是at

请注意,这两个示例都使用本机API函数及其一些未记录的功能

基本步骤是:

获取锁定过程中看到的文件句柄值。这是通过调用NtQuerySystemInformation获取系统中所有句柄的列表,并调用NtQueryObject查找具有匹配文件名的句柄来完成的。 请注意,文件名必须转换为NT设备格式。 打开拥有句柄的进程OpenProcess with suffucent privileges process_DUP_handle and process_SUSPEND_RESUME并调用DuiplicateHandle,将该进程作为源、步骤1中的句柄值和您的进程作为目标。 使用NtSuspendProcess可暂停进程并防止其修改文件指针和文件内容。 使用复制句柄复制文件。 还原文件指针,关闭句柄,调用NtResumeProcess取消暂停进程。 EDIT2:就我个人而言,我使用了另一种方式来访问锁定的文件——使用手动NTFS解析的原始磁盘访问。例如,给定文件名,找到其MFT条目,解码数据运行位置并从原始磁盘读取。只要您具有管理员权限,原始磁盘访问始终可用,因此任何文件都是可读的。缺点是零一致性保证,因此不适合用于备份目的


另外,如果我是你,我仍然会选择官方支持的VSS。备份软件不应依赖黑客攻击。

即使我使用CreateFile?@Bruno而不是fopen,无论您使用什么方法。他们最后都调用了CreateFile。很抱歉,我刚才读到了duplicateHandle,这是否能够复制进程句柄,然后使我能够使用与另一个进程使用的相同的文件?