CreateFile的內部實現


  今天想看看CreateFile的內部實現,不過網上沒有想要的資料,都只是對參數分析了一下。找了找WRK源碼,找到CreateFile的源碼自己來分析一下。

  

  1 HANDLE WINAPI CreateFileW (    
  2 LPCWSTR        lpFileName,
  3                 DWORD            dwDesiredAccess,
  4                 DWORD            dwShareMode,
  5                 LPSECURITY_ATTRIBUTES    lpSecurityAttributes,
  6                 DWORD            dwCreationDisposition,
  7                 DWORD            dwFlagsAndAttributes,
  8                 HANDLE        hTemplateFile)
  9 {
 10    OBJECT_ATTRIBUTES ObjectAttributes;
 11    IO_STATUS_BLOCK IoStatusBlock;
 12    UNICODE_STRING NtPathU;
 13    HANDLE FileHandle;
 14    NTSTATUS Status;
 15    ULONG FileAttributes, Flags = 0;
 16    PVOID EaBuffer = NULL;
 17    ULONG EaLength = 0;
 18    switch (dwCreationDisposition)
 19    {
 20      case CREATE_NEW://強制創建一個文件(原文件不能存在)
 21     dwCreationDisposition = FILE_CREATE;
 22     break;
 23      case CREATE_ALWAYS://原文件存在就覆蓋
 24     dwCreationDisposition = FILE_OVERWRITE_IF;
 25     break;
 26      case OPEN_EXISTING://原文件必須存在
 27     dwCreationDisposition = FILE_OPEN;
 28     break;
 29      case OPEN_ALWAYS://原文件不存在就創建
 30     dwCreationDisposition = FILE_OPEN_IF;
 31     break;
 32      case TRUNCATE_EXISTING://原文件存在就清空內容
 33     dwCreationDisposition = FILE_OVERWRITE;
 34         break;
 35    }
 36    if (0 == _wcsicmp(L"CONOUT$", lpFileName)|| 0 == _wcsicmp(L"CONIN$", lpFileName))
 37    {
 38       return OpenConsoleW(lpFileName,dwDesiredAccess, 
 39                           lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE,
 40                           FILE_SHARE_READ | FILE_SHARE_WRITE);
 41    }
 42    if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
 43       Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
 44    if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
 45       Flags |= FILE_WRITE_THROUGH;
 46    if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
 47       Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
 48    if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
 49       Flags |= FILE_RANDOM_ACCESS;
 50    if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
 51       Flags |= FILE_SEQUENTIAL_ONLY;
 52    if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
 53       Flags |= FILE_DELETE_ON_CLOSE;
 54    if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
 55    if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
 56       Flags |= FILE_OPEN_REPARSE_POINT;
 57    if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
 58       Flags |= FILE_OPEN_NO_RECALL;
 59    FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
 60    dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
 61    if (!RtlDosPathNameToNtPathName_U (lpFileName,&NtPathU,NULL,NULL))
 62    {
 63      SetLastError(ERROR_PATH_NOT_FOUND);
 64      return INVALID_HANDLE_VALUE;
 65    }
 66    if (hTemplateFile != NULL) 
 67    {
 68       FILE_EA_INFORMATION EaInformation;
 69 
 70       for (;;)
 71       {
 72          Status = NtQueryInformationFile(hTemplateFile,&IoStatusBlock,&EaInformation,
 73                                          sizeof(FILE_EA_INFORMATION),FileEaInformation);
 74          if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
 75          {
 76             EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),0,EaInformation.EaSize);
 77             Status = NtQueryEaFile(hTemplateFile,&IoStatusBlock,EaBuffer,
 78                                    EaInformation.EaSize,FALSE,NULL,0,NULL,TRUE);
 79             if (NT_SUCCESS(Status))
 80             {
 81                EaLength = EaInformation.EaSize;
 82                break;
 83             }
 84             Else
 85          }
 86          else
 87             break;
 88       }
 89    }
 90 
 91    InitializeObjectAttributes(&ObjectAttributes,&NtPathU,0,NULL,NULL);
 92    if (lpSecurityAttributes)
 93    {
 94       if(lpSecurityAttributes->bInheritHandle)
 95          ObjectAttributes.Attributes |= OBJ_INHERIT;
 96       ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
 97    }
 98 
 99    if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
100     ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
101 
102    Status = NtCreateFile (&FileHandle,
103 dwDesiredAccess,
104               &ObjectAttributes,
105               &IoStatusBlock,NULL,
106               FileAttributes,
107               dwShareMode,
108               dwCreationDisposition,
109               Flags,
110               EaBuffer,
111               EaLength);
112    if (!NT_SUCCESS(Status))
113    {
114       if (Status == STATUS_OBJECT_NAME_COLLISION && dwCreationDisposition == FILE_CREATE)
115          SetLastError( ERROR_FILE_EXISTS );
116       else
117          SetLastErrorByStatus (Status);
118       return INVALID_HANDLE_VALUE;
119    }
120   if (dwCreationDisposition == FILE_OPEN_IF)
121     SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : 0);
122   else if (dwCreationDisposition == FILE_OVERWRITE_IF)
123     SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
124   return FileHandle;//返回的文件句柄就是文件對象的句柄
125 }

都知道函數CreateFile返回值是文件句柄,我們發現返回的文件句柄其實是函數內部聲明的一個傳入系統服務NTCreateFile的句柄。接下來,我們一步步跟進, NTCreateFile只是調用了IO管理器的IoCreateFile函數。

IoCreateFile函數的實現也比較簡單,就不貼代碼了。首先將參數復制到內核空間,構造打開請求包OpenPacket(這個結構體寫驅動好像不是很常用?),接下來調用IopParseDevice解析文件路徑,這個函數比較關鍵,會在這里創建文件對象和IRP請求包。最后就是打開文件對象,再返回Status就Ok啦。

IopParseDevice函數我直接定位到自己最感興趣的地方:

InitializeObjectAttributes(&ObjectAttributes,NULL,Attributes,NULL,NULL);
        Status = ObCreateObject(KernelMode,IoFileObjectType,
                                &ObjectAttributes,AccessMode,NULL,
                                sizeof(FILE_OBJECT)
                                0,0, (PVOID*)&FileObject);
        RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
        if (OpenPacket->CreateOptions &
            (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
        {
            FileObject->Flags |= FO_SYNCHRONOUS_IO;
            if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
                FileObject->Flags |= FO_ALERTABLE_IO;
        }
        if (FileObject->Flags & FO_SYNCHRONOUS_IO)
            KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
        if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
            FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
        if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
            FileObject->Flags |= FO_WRITE_THROUGH;
        if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
            FileObject->Flags |= FO_SEQUENTIAL_ONLY;
        if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
            FileObject->Flags |= FO_RANDOM_ACCESS;

在判斷完操作類型之后終於開始ObCreateObject創建對象(注意,僅僅是查詢、刪除命令的話不需要創建對象,使用內部預先的公共的文件對象就ok),接下來就是發送IRP,等待完成。

  簡單的分析一下,很多細節沒有仔細的看,了解一下底層實現。    說真的,這個函數名字取得真心不好,這函數能打開創建的那么多,只叫CreateFile。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM