今天想看看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. 【记录】@Configuration注解作用 mybatis @Param作用

    参考地址: 1:https://www.cnblogs.com/duanxz/p/7493276.html 2:https://www.wandouip.com/t5i91156/ 3:https:/ ...

  2. Oracle之子查询:Top-N问题

    学习了SQL子查询,遇到个Top-N问题,即:加入有张工资表(这里使用Oracle SCOTT用户的emp表),需要查找工资最高的3个员工信息,以下列格式输出: 乍眼一看,这很简单啊,对sal进行排序 ...

  3. win32程序使用CString

    https://www.cnblogs.com/qingtian224/p/5833456.html uafxcwd.lib(afxmem.obj) : error LNK2005: "vo ...

  4. 力扣—Remove Duplicates from Sorted List(删除排序链表中的重复元素)python实现

    题目描述: 中文: 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次. 示例 1: 输入: 1->1->2输出: 1->2 示例 2: 输入: 1->1->2 ...

  5. c++简单线程池实现(转)

    线程池,简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态,当有新的任务进来,从线程池中取出一个空闲的线程处理任务,然后当任务处理完成之后,该线程被重新放回到线程池中,供其他 ...

  6. 微信小程序学习一 微信小程序的四个基本文件

    微信小程序有四种类型的文件 js 类型文件 小程序的逻辑代码文件 小程序对js es6的处理比较友好,基本上我们的es6语法都需要使用babel插件去转化成es5(具体是什么原因,自己可以去了解一下) ...

  7. 【leetcode】679. 24 Game

    题目如下: 解题思路:24点是非常经典的游戏了,因为本题数据量小,可以使用穷举法,把所有的可能结果都算出来.假设nums = [a,b,c,d],记f(n)表示用nums中n个数字进行运算可以得到的结 ...

  8. Ceph的正确玩法之Ceph纠删码理论与实践

    http://blog.itpub.net/31545808/viewspace-2637083/ 注意空格,有的命令少空格 随着云计算业务的快速发展,国内外云计算企业的专利之争也愈发激烈.在云计算这 ...

  9. UNP学习第13章 守护进程和inetd超级服务器

    Unix系统中的syslogd守护进程通常由某个系统初始化脚本启动,而且在系统工作期间一直运行. 源自Berkeley的syslogd实现在启动时执行以下步骤. (1)读取配置文件.通常为/etc/s ...

  10. 初学Linux基本的命令操作应当记牢

    Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touc ...