今天想看看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. Ansible--03 ansible 变量

    目录 Ansible 变量 变量概述 定义变量的方式 如何定义变量 Ansible变量优先级测试 变量注册 ansibl e层级定义变量 facts缓存 Ansible 变量 变量概述 变量提供了便捷 ...

  2. node 添加个人经历的接口

    1.定义experience const profileFields = {}; profileFields.experience=[]; 2.查找用户id const profile = await ...

  3. python3.x 扯扯【切片】这玩意儿

    在此之前先了解一下list这个玩意儿: list对应cpp这的数组,一维数组,二维数组,或者是嵌套都行: L=[] #空列表 L=[1,2,3,4,5,6] #六项 L=['a',['b','c']] ...

  4. mysql中limit 和 limit 与 offset 的用法(效果相同,用法不通过)

    例1,假设数据库表student存在13条数据. 代码示例: 语句1:select * from student limit 9,4 语句2:slect * from student limit 4 ...

  5. Hibernate的优点与缺点

    Hibernate优点: 1.对象化.人员以面相对象的思想来操作数据库.Hibernate支持许多面向对象的特性,如组合,继承,多态等. 2.更好的移植性.对于不同的数据库,开发者只需要使用相同的数据 ...

  6. mui使用总结

    mui是一个高性能的HTML5开发框架,从UI到效率,都在极力追求原生体验:这个框架自身有一些规则,刚接触的同学不很熟悉,特总结本文:想了解mui更详细的信息,请访问mui官网 DOM结构 关于mui ...

  7. 升级ceph

    参考文档 https://blog.51cto.com/jerrymin/2140258 https://www.virtualtothecore.com/en/upgrade-ceph-cluste ...

  8. I2C_24c02实验

    一.RCC初始化 /* Setup the microcontroller system. Initialize the Embedded Flash Interface, initialize th ...

  9. jetson资料

    http://www.waveshare.net/wiki/Jetson_Nano_Developer_Kit http://www.waveshare.net/wiki/JetBot_AI_Kit ...

  10. rabbitmq安装-1

    原文地址和下载地址 原方地址: https://www.cnblogs.com/jiagoushi/p/9961388.html rabbitmq下载地址: https://github.com/ra ...