今天想看看CreateFile的内部实现,不过网上没有想要的资料,都只是对参数分析了一下。找了找WRK源码,找到CreateFile的源码自己来分析一下。

  

 HANDLE WINAPI CreateFileW (
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING NtPathU;
HANDLE FileHandle;
NTSTATUS Status;
ULONG FileAttributes, Flags = ;
PVOID EaBuffer = NULL;
ULONG EaLength = ;
switch (dwCreationDisposition)
{
case CREATE_NEW://强制创建一个文件(原文件不能存在)
dwCreationDisposition = FILE_CREATE;
break;
case CREATE_ALWAYS://原文件存在就覆盖
dwCreationDisposition = FILE_OVERWRITE_IF;
break;
case OPEN_EXISTING://原文件必须存在
dwCreationDisposition = FILE_OPEN;
break;
case OPEN_ALWAYS://原文件不存在就创建
dwCreationDisposition = FILE_OPEN_IF;
break;
case TRUNCATE_EXISTING://原文件存在就清空内容
dwCreationDisposition = FILE_OVERWRITE;
break;
}
if ( == _wcsicmp(L"CONOUT$", lpFileName)|| == _wcsicmp(L"CONIN$", lpFileName))
{
return OpenConsoleW(lpFileName,dwDesiredAccess,
lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE,
FILE_SHARE_READ | FILE_SHARE_WRITE);
}
if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
Flags |= FILE_WRITE_THROUGH;
if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
Flags |= FILE_RANDOM_ACCESS;
if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
Flags |= FILE_SEQUENTIAL_ONLY;
if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
Flags |= FILE_DELETE_ON_CLOSE;
if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
Flags |= FILE_OPEN_REPARSE_POINT;
if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
Flags |= FILE_OPEN_NO_RECALL;
FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
if (!RtlDosPathNameToNtPathName_U (lpFileName,&NtPathU,NULL,NULL))
{
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
if (hTemplateFile != NULL)
{
FILE_EA_INFORMATION EaInformation; for (;;)
{
Status = NtQueryInformationFile(hTemplateFile,&IoStatusBlock,&EaInformation,
sizeof(FILE_EA_INFORMATION),FileEaInformation);
if (NT_SUCCESS(Status) && (EaInformation.EaSize != ))
{
EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),,EaInformation.EaSize);
Status = NtQueryEaFile(hTemplateFile,&IoStatusBlock,EaBuffer,
EaInformation.EaSize,FALSE,NULL,,NULL,TRUE);
if (NT_SUCCESS(Status))
{
EaLength = EaInformation.EaSize;
break;
}
Else
}
else
break;
}
} InitializeObjectAttributes(&ObjectAttributes,&NtPathU,,NULL,NULL);
if (lpSecurityAttributes)
{
if(lpSecurityAttributes->bInheritHandle)
ObjectAttributes.Attributes |= OBJ_INHERIT;
ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
} if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; Status = NtCreateFile (&FileHandle,
dwDesiredAccess,
&ObjectAttributes,
&IoStatusBlock,NULL,
FileAttributes,
dwShareMode,
dwCreationDisposition,
Flags,
EaBuffer,
EaLength);
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_OBJECT_NAME_COLLISION && dwCreationDisposition == FILE_CREATE)
SetLastError( ERROR_FILE_EXISTS );
else
SetLastErrorByStatus (Status);
return INVALID_HANDLE_VALUE;
}
if (dwCreationDisposition == FILE_OPEN_IF)
SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : );
else if (dwCreationDisposition == FILE_OVERWRITE_IF)
SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : );
return FileHandle;//返回的文件句柄就是文件对象的句柄
}

都知道函数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)
,, (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。。。

CreateFile的内部实现的更多相关文章

  1. [14]Windows内核情景分析 --- 文件系统

    文件系统 一台机器上可以安装很多物理介质来存放资料(如磁盘.光盘.软盘.U盘等).各种物理介质千差万别,都配备有各自的驱动程序,为了统一地访问这些物理介质,windows设计了文件系统机制.应用程序要 ...

  2. 第10章 同步设备I/O和异步设备I/O(1)_常见设备及CreateFile函数

    10.1 打开和关闭设备 10.1.1 设备的定义——在Windows中可以与之进行通信的任何东西. (1)常见设备及用途 设备 用途 用来打开设备的函数 文件 永久存储任何数据 CreateFile ...

  3. Windows API 之 CreateFile

    Creates or opens a file or I/O device. The most commonly used I/O devices are as follows: file, file ...

  4. [原]CreateFile中的dwShareMode

    原 总结 API  一直对CreateFile的参数dwDesiredAccess和dwShareMode有什么不同不是很清楚,今天重读 windows核心编程的时候终于豁然开朗了. 真是书读百遍,其 ...

  5. Windows内核开发-Windows内部概述-2-

    Windows内部概述-2- 线程: 执行代码的实体是线程.一个线程的包含在进程里面的,线程使用进程提供的资源来运行代码. 一个线程拥有以下的内容: 1:明确的运行模式,用户态或者内核态. 2:执行的 ...

  6. 通过ProGet搭建一个内部的Nuget服务器

    .NET Core项目完全使用Nuget 管理组件之间的依赖关系,Nuget已经成为.NET 生态系统中不可或缺的一个组件,从项目角度,将项目中各种组件的引用统统交给NuGet,添加组件/删除组件/以 ...

  7. 微软Azure 经典模式下创建内部负载均衡(ILB)

    微软Azure 经典模式下创建内部负载均衡(ILB) 使用之前一定要注意自己的Azure的模式,老版的为cloud service模式,新版为ARM模式(资源组模式) 本文适用于cloud servi ...

  8. 简单搭建 nuget 内部服务器

    搭建 nuget 内部服务器,最好的方式是使用 ProGet,参考博文<用 ProGet 搭建内部的 NuGet 服务器>,好处非常多,但需要使用 SQL Server 数据库,如果不想使 ...

  9. 用ProGet搭建内部的NuGet服务器

    最近团队内部用的一个很简陋的NuGet服务器出问题了,nuget push发包,客户端显示发布成功,服务器上就是没有.懶得再去排查这个问题,早就想换掉这个过于简陋的NuGet服务器,借此机会直接弃旧迎 ...

随机推荐

  1. for循环(foreach型)流程

  2. Rsync备份服务实战

    目录 Rsync备份服务实战 一.Rsync 二.rsync的应用场景 1.Rync的数据同步模式 2.rsync的三种模式 三.rsync配置服务端客户端 四.rsync实战 实战一 报错解决方法: ...

  3. 2019牛客多校第七场H Pair 数位DP

    题意:给你一个3个数A, B, C问有多少对pair(i, j),1 <= i <= A, 1 <= j <= B, i AND j > C或 i XOR j < ...

  4. Nginx有哪些作用?

    Nginx有哪些作用? http协议代理 搭建虚拟主机 服务的反向代理 在反向代理中配置集群的负载均衡   什么是正向代理? 正向代理,意思是一个位于客户端和原始服务器(origin server)之 ...

  5. webpack 学习4 使用loader 以及常用的一些loader

    webpack本身只支持处理JavaScript,其他的文件,如css img less是不识别的,所以才会有loader这个东西,它就是可以使webpack能够处理其他非js文件的拓展程序 首先我们 ...

  6. OpenCV常用基本处理函数(4)简单变换,阈值等

    几何变换 缩放 img=cv2.imread('messi5.jpg') # 下面的 None 本应该是输出图像的尺寸,但是因为后边我们设置了缩放因子 # 因此这里为 None res=cv2.res ...

  7. 使用nano编辑器进行查找和替换

    笔者自己常用的是vim.这里nano的使用场景就是刚安装好Ubuntu系统,想要替换更新源,这时候还没装上vim.所以,学一下如何用nano查找和替换,可以解决这个小问题. 首先sudo nano / ...

  8. 区间第k大的几种解法

    区间第K大问题,变化包括带修改和不带修改,强制在线和允许离线 修改主要是单点修改,我们前面也只讨论这种情况. 接下来我们从编程复杂度和时空复杂度来讨论几种做法. 1.整体二分(编程复杂度:低-中,时间 ...

  9. Java Software Engineer Skill Map

    # Java Software Engineer Skill Map## Basic### Core Java- Java The Complete Reference Ninth Edition.p ...

  10. 自动化测试之CSS定位

    之前做自动化测试一直用RF框架来操作,发现了明显与unittest的灵活性相差一点. 重新温习了unittest框架,其中这个框架,元素定位是难点,以前更多的使用JQUERY方式定位, 发现其实与CS ...