今天想看看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. sql优化案例1

    --访客数 ) from ( select v.idvisitor from ods.piwik_log_visit v , , group by v.idvisitor) --优化后的访客数查询 s ...

  2. 力扣——remove element(删除元素) python实现

    题目描述: 中文: 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) ...

  3. mysql中级操作

    解析sql执行过程 show VARIABLES like '%profil%' //查看是否开启了剖析 如没开启set profiling=1; 启用 show profiles; set @que ...

  4. OpenLayers API整理

    整理的Openlayers 的知识笔记,随着运用不断加深理解,也会不断更新. 本文链接:Openlayers API整理 作者:狐狸家的鱼 GitHub:八至 一.创建地图 1.地图Map 创建地图底 ...

  5. 如何给 List 集合排序

    一,List<Integer>的排序示例代码:List<Integer> list = new ArrayList<Integer>();list.add(6);l ...

  6. 【Bootstrapt】offset、push、pull

    实现方式的区别: col-md-offset-*,是利用margin-left实现的,col-md-push-*/col-md-pull-*是利用相对定位实现的. 效果的区别: col-md-offs ...

  7. Nacos 1.1.4 发布,业界率先支持 Istio MCP 协议

    Nacos是阿里巴巴开源的服务发现与配置管理项目,本次发布的1.1.4版本,主要带来的是与Istio的对接功能,使用的是Istio最新的MCP协议.本文将介绍包括这个功能在内的新版本发布的功能. 升级 ...

  8. jmeter之-聚合报告&分析结果

    Label:请求的名称 Sample:表示这次测试中一共发了多少个请求 Average:平均响应时间 median:中位数,也就是表示在所有请求响应时间中排在中间的那个响应的时间点,50%line 实 ...

  9. SQL执行计划详解explain

    1.使用explain语句去查看分析结果 如explain select * from test1 where id=1;会出现:id selecttype table type possible_k ...

  10. python 找到列表中满足某些条件的元素

    a = [0, 1, 2, 3, 4, 0, 2, 3, 6, 7, 5] selected = [x for x in a if x in range(1, 5)]   # 找到a中属于[1,5)中 ...