Delphi驱动开发研究第九篇--文件与目录(2)

本文深入探讨了使用Delphi进行驱动开发时,如何操作文件和目录,包括文件属性设置、对象操作以及删除和IO管理等关键知识点,为Delphi开发者提供了实用的指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
还记得我们是如何处理I/O请求的(见前面的章节)。例如,在驱动程序SharingMemory中对IRP_MJ_CREATE和IRP_MJ_CLOSE的处理如下:
p_Irp^.IoStatus.Status := STATUS_SUCCESS;
p_Irp^.IoStatus.Information := 0;
IofCompleteRequest(p_Irp, IO_NO_INCREMENT);

本例的驱动程序也大致相同,即将完成创建文件的请求。只有放入IO_STATUS_BLOCK结构体的域中的值会依赖于请求的类型。
因为我们定义了FILE_OPEN_IF标志,通过iosb.Information的值,我们可以知道是该建立新的目录还是因该目录已经存在而将其打开。
ZwClose(hDirectory);

我再重复一遍,在内核模式下一定要显式地关闭所有打开的句柄。
RtnCode := ZwCreateFile(@hFile, SYNCHRONIZE, @oa, @iosb, nil,
                     FILE_ATTRIBUTE_NORMAL, 0,
                     FILE_CREATE,
                     FILE_SYNCHRONOUS_IO_NONALERT, nil, 0);

如您所见,文件的创建实际上是相同的,只是要去掉FILE_DIRECTORY_FILE标志。而FILE_CREATE标志我将其用于多种情况。它表示只可以创建文件。如果文件已经存在,则对ZwCreateFile会以失败结束。

9.4 文件对象
每一个打开的文件句柄都对应着一个文件对象(file object),在内核内存区中有FILE_OBJECT结构体。
TFileObject=packed record
    wType:Word;
    Size:Word;
    DeviceObject:PDeviceObject;
    DoNotUser1:Pointer;
    FsContext:Pointer;
    FsContext2:Pointer;
    SectionObjectPointer:Pointer;
    PrivateCacheMap:Pointer;
    FinalStatus:NTSTATUS;
    RelatedFileObject:PFileObject;
    LockOperation:Boolean;
    DeletePending:Boolean;
    ReadAccess:Boolean;
    WriteAccess:Boolean;
    DeleteAccess:Boolean;
    SharedRead:Boolean;
    SharedWrite:Boolean;
    SharedDelete:Boolean;
    Flags:Cardinal;
    FileName:TUnicodeString;
    CurrentByteOffset:TLargeInteger;
    Waiters:Cardinal;
    Busy:Cardinal;
    LastLock:Pointer;
    Lock:TKEvent;
    Event:TKEvent;
   CompletionContext:Pointer;
end;

例如,我们可以两次打开同一个文件,但是两次的访问请求却不相同:第一次读(FILE_READ_DATA)而第二次写(FILE_WRITE_DATA)。结果内核会建立两个FILE_OBJECT结构体,每一个都对应于自己相应的文件句柄。但是两个句柄和相对应的两个FILE_OBJECT结构体都对应着同一个磁盘文件。第一个FILE_OBJECT结构体将设置ReadAccess域,第二个则设置WriteAccess域。例如,试图写入第一个句柄指向的文件时,系统会发现域WriteAccess = FALSE并结束请求。
DeviceObject域将包含指向设备对象\Device\HarddiskVolume1的指针,因为这个设备是对\??\c:符号链接,我们创建文件时在文件名中使用了\??\c:。
在读完本文后您可能会进行文件操作的实验并会发现系统是如何填充并管理FILE_OBJECT结构体的。如果在内存中定位它时发生问题,可以使用ObReferenceObjectByHandle函数,形式大致如下:
var
pFileObject:PFILE_OBJECT;
. . .
begin
RtnCode := ObReferenceObjectByHandle(hFile, FILE_READ_DATA, nil, KernelMode, @pFileObject,nil);
  if RtnCode = STATUS_SUCCESS then
begin
    {pFileObject指向对应于hFile的FILE_OBJECT}
    ObfDereferenceObject(pFileObject);
end;
end;

ObReferenceObjectByHandle向参数pFileObject中返回指向对应于该文件句柄的FILE_OBJECT结构体的指针。这时,引用计数会增一。之后一定要调用ObfDereferenceObject来使其复原。
9.5 写入文件
到这里我们已经有了大小为0目录和文件。该向文件中写点东西了。
RtnCode := ZwCreateFile(@hFile, FILE_WRITE_DATA + SYNCHRONIZE,
                     @oa, @iosb, nil, 0, FILE_SHARE_READ,
                     FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT,
                     nil, 0);

借助于ZwCreateFile不止可以创建文件,还可以打开已有的文件(恰好,不只是文件,其它某些对象也是这样)。为此需要指定标志FILE_OPEN。
为了写入文件,需要相应的访问权——使用FILE_WRITE_DATA。
在单元文件中定义了几个常量以用于对文件的一般访问。例如,FILE_GENERIC_WRITE不仅允许向文件中写入数据,还可以更改其属性并添加数据。
FILE_GENERIC_WRITE = (STANDARD_RIGHTS_WRITE or
                                    FILE_WRITE_DATA or
                                    FILE_WRITE_ATTRIBUTES or
                                    FILE_WRITE_EA or
                                    FILE_APPEND_DATA or
                                    SYNCHRONIZE);

显然,当我们写文件,其它的程序不应向该文件写入。使用FILE_SHARE_READ标志,则没有程序能写入或是删除文件,而只能读取文件。
if RtnCode = STATUS_SUCCESS then
begin
    DbgPrint('FileWorks: File openeded'#13#10);
    g_szData := 'Data can be written to an open file';
    RtnCode := ZwWriteFile(hFile, 0, nil, nil, @iosb, 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值