除在所有 IRP_MJ_XXX 之前自己从头创建 IRP 发送到下层设备查询全路径外,不要尝试在 IRP_MJ_CREATE 以外的地方获得全路径,因为只有在 IRP_MJ_CREATE
中才会使用 ObCreateObject() 来建立一个有效的 FILE_OBJECT。而在 IRP_READ IRP_WRITE 中它们是直接 *** 作 FCB (File Control Block)的。
2、从头建立 IRP 发送关注点
无论你建立什么样的 IRP,是 IRP_MJ_CREATE 也好还是 IRP_MJ_DIRECTORY_CONTROL也罢,最要提醒的就是一些标志。不同的标志会代来不同的结果,有些结果是直接返回失败。这里指的标志不光是 IRP->Flags,还要考虑 IO_STACK_LOCATION->Flags还有其它等等。尤其是你要达到一些特殊目的,这时候更需要注意,如 IRP_MN_QUERY_DIRECTORY,不同的标志结果有很大的不同。
3、从头建立 IRP 获取全路径注意点
自己从头建立一个 IRP_MJ_QUERY_INFORMATION 的 IRP 获取全路径时需要注意,不仅在 IRP_MJ_CREATE 要做区别处理,在 IRP_MJ_CLOSE 也要做同样的处理,否则如果目标是 NTFS 文件系统的话可能产生 deadlock。如果是 NTFS 那么在 IRP_MJ_CLEANUP 的时候也需要对 FO_STREAM_FILE 类型的文件做同样处理。
4、获得本地/远程访问用户名(域名/SID)
方法只有在 IRP_MJ_CREATE 中才可用,那是因为 IO_SECURITY_CONTEXT 只有在 IO_STACK_LOCATION->Parameters.Create.SecurityContext 才会有效。这样你才有可能从 IO_SECURITY_CONTEXT->SecurityContext->AccessState->SubjectSecurityContext.XXXToken 中获得访问 TOKEN,从而进一步得到用户名或 SID。记得 IFS 中有一个库,它的 LIB 导出一个函数可以让你在获得以上信息后得到用户名与域名。但如果你想兼容 NT4 的话,只能自己分析来得出本地和远程的 SID。
5、文件与目录的判断
正确的方法在楚狂人的文档里已经说过了,再补充一句。如果你的文件过滤驱动要兼容所有文件系统,那么不要神耐桐十分相信从 FileObject->FsContext 里取得的数据。正确的方法还是在你传递下去 IRP_MJ_CREATE 后从最下层文件系统延设备栈返回到你这里后再获得。
6、加/解密中判断点
只判断 IRP_PAGING_IO,IRP_SYNCHRONOUS_PAGING_IO,IRP_NOCACHE 是没错的。如果有问题,相信是自己的问题。关于有人提到在 FILE_OBJECT->Flags中的 FO_NO_INTERMEDIATE_BUFFERING 是否需要判断,对此问题的回答是只要你判断了 IRP_NOCACHE 就不用再判断 FILE_OBJECT 中的,因为它最终会设置 IRP->Flags 为 IRP_NOCACHE。关于你看到的诸如 IRP_DEFER_IO_COMPLETION 等 IRP 不要去管它,因为它只是一个过程。最游坦终读写还是如上所介绍。至于以上这些 IRP 哪个是由 CC MGR 发送的,哪些是由 I/O MGR 发送和在什么时候发送的,这个已经有很多讨论了,相信可以找到。
7、举例说明关于 IRP 传递与完成注意事项
只看 Walter Oney 的那本 《Programming the Microsoft Windows driver model》里介绍的流程,自己没有实际的体会还是不够的,那里只介绍了基础概念,让自己有了知识。知道如何用,在什么情况下用,用哪种方法,能够用的稳定这叫有了技术。我们从另一个角度出发,把问题分为两段来看,这样利于总结。一个 IRP 在过滤驱动中,把它分为需要亩纯安装 CompleteRoutine 的与无需安装 CompleteRoutine 的。那么在不需要安装 CompleteRoutine 的有以下几类情况。
(1) 拿到这个 IRP 后什么都不做,直接调用 IoCompleteRequest() 来返回。
(2) 拿到这个 IRP 后什么都不做,直接传递到底层设备,使用IoSkipCurrentIrpStackLocation() 后调用 IoCallDriver() 传递。
(3) 使用 IoBuildSynchronousFsdRequest() 或 IoBuildDeviceIoControlRequest()来建立 IRP 的。
以上几种根据需要直接使用即可,除了一些参数与标志需要注意外,没有什么系统机制相关的东西需要注意了。那么再来看需要安装 CompleteRoutine 的情况。我们把这种情况再细分为两种,一是在 CompleteRoutine 中返回标志为STATUS_MORE_PROCESSING_REQUIRED 的情况。二是返回处这个外的标志,需要使用函数IoMarkIrpPending() 的情况。在 CompleteRoutine 中绝大多数就这么两种情况,你需要使用其中的一种情况。那么为什么需要安装 CompleteRoutine 呢?那是因为我们对其 IRP 从上层驱动,经过我们驱动,在经过底层设备栈返回到我们这一层驱动时需要得到其中内容作为参考依据的,还有对其中内容需要进行修改的。再有一种情况是没有经过上层驱动,而 IRP 的产生是在我们驱动直接下发到底层驱动,而经过设备栈后返回到我们这一层,且我们不在希望它继续向上返回的,因为这个 IRP 本身就不是从上层来的。综上所述,先来看下 IoMarkIrpPending() 的情况。
(1) 在 CompleteRoutine 中判断 Irp->PendingReturned 并使用 IoMarkIrpPending()然后返回。这种方法在没有使用 KeSetEvent() 的情况下,且不是自建 IRP 发送到底层驱动返回时使用。也就是说有可能我所做的工作都是在 CompleteRoutine 中进行的。比如加/解密时,我在这里对下层驱动返回数据的判断并修改。修改后因为没有使用 STATUS_MORE_PROCESSING_REQUIRED 标志,它会延设备堆一直向上返回并到用户得到数据为止。这里一定要注意,在这种情况下 CompleteRoutine返回后,不要在碰这个 IRP。也就是说如果这个时候你使用了 IoCompleteRequest()的话会出现一个 MULTIPLE_IRP_COMPLIETE_REQUEST 的 BSOD 错误。
(2) 在 CompleteRoutine 中直接返回 STATUS_MORE_PROCESSING_REQUIRED 标志。这种情况在使用了 KeSetEvent() 的函数下出现。这里又有两个小小的分之。
1) 出现于上层发送到我这里,当我这里使用 IoCallDriver() 后,底层返回数据经过我这一层时,我想让它暂时停止继续向上传递,让这个 IRP 稍微歇息一会,等我对这个 IRP 返回的数据 *** 作完成后(一般是没有在 CompleteRoutine中对返回数据进行 *** 作情况下,也就是说等到完成例程返回后再进行 *** 作),由我来调用 IoCompleteRequest() 让它延着设备栈继续返回。这里要注意,我们是想让它返回的,所以调用了 IoCompleteRequest()。这个可不同于下面所讲的自己从头分配 IRP 时在 CompleteRoutine 中已经调用 IoFreeIrp() 释放了当前IRP 的情况。比如我在做一个改变文件大小,向文件头写入加密标志的驱动时,在上层发来了 IRP_MJ_QUERY_INFORMATION 查询文件,我想在这个时候获得文件信息进行判断,然后根据我的判断结果再移动文件指针。注意:上面是两步,第一步是先获得文件大小,那么在这个时候我就需要用到上述办法,先让这个 IRP传递下去,得到我想要的东西后在进行对比。等待适当时机完成这个 IRP,让数据继续传递,直到用户收到为止。第二步我会结合下面小节来讲。
2) 出现于自己从头建立 IRP,当使用 IoAllocate() 或 IoBuildAsynchronousFsdRequest()创建 IRP 调用 IoCallDriver() 后,底层返回数据到我这一层时,我不想让这个 IRP 继续向上延设备栈传递。因为这个 IRP 就是在我这层次建立的,上层本就不知道有这么一个 IRP。那么到这里我就要在 CompleteRoutine 中使用 IoFreeIrp()来释放掉这个 IRP,并不让它继续传递。这里一定要注意,在 CompleteRoutine函数返回后,这个 IRP 已经释放了,如果这个时候在有任何关于这个 IRP 的 *** 作那么后果是灾难性的,必定导致 BSOD 错误。前面 1) 小节给出的例子只完成了第一步这里继续讲第二步,第一步我重用这个 IRP 得到了文件大小,那么这个时候虽然知道大小,但我还是无法知道这个文件是否被我加过密。这时,我就需要在这里自己从头建立一个 IRP_MJ_READ 的 IRP 来读取文件来判断是否我加密过了的文件,如果是,则要减少相应的大小,然后继续返回。注意:这里的返回是指让第一步的IRP 返回。而不是我们自己创建的。我们创建的都已经在CompleteRoutine 中销毁了。
8、关于完成 IRP 的动作简介
当一个底层驱动调用了 IoCompleteRequest() 函数时,基本上所有设备栈相关 IRP 处理工作都是在它那里完成的。包括 IRP->Flags 的一些标志的判断,对 APC 的处理,抛出MULTIPLE_IRP_COMPLETE_REQUESTS 错误等。当它延设备栈一直调用驱动所安装的 CompleteRoutine时,如果发现 STATUS_MORE_PROCESSING_REQUIRED 这个标志,则会停止向上继续回滚。这也是为什么在 CompleteRoutine 中使用这个标志即可暂停 IRP 的原因。
9、关于 ObQueryNameString 的使用
这个函数的使用,在有些环境下会有问题。它的上层函数是 ZwQueryObject()。在某些情况下会导致系统挂起,或者直接 BSOD。它是从 对象管理器中的 ObpRootDirectoryObject开始遍历,通过 OBJECT_HEADER_TO_NAME_INFO 获得对象名称。今天问了下 PolyMeta好象是在处理 PIPE 时会挂启,这个问题出现在 2000 系统。在 XP 上好象补丁了。
10、关于重入问题
其实这个问题在很久前的 IFS FAQ 里已经介绍的很清楚,包括处理方法以及每种方法可能带来的问题。IFS FAQ 里的 Q34 一共介绍了四种方法,包括自己从头建立 IRP发送,使用 ShadowDevice,使用特征字符串,根据线程 ID,在 XP 下使用IoCreateFileSpecifyDeviceObjectHint() 函数。并且把以上几种在不同环境下使用要处理的问题也做了简单的介绍。且在 Q33 里介绍了在 CIFS 碰到的 FILE_COMPLETE_IF_OPLOCKED 问题的解决方法。
我本是出国狂人接舆的后代,祖先接舆就曾唱着“凤歌”嘲笑过孔丘。李白的诗一向以其飘逸豪放著称,不受传统的约束,率性而为。正如他在《庐山谣寄庐侍御虚舟》一诗中写到“我本楚狂人,凤歌笑孔丘”,一个“狂”字,将他狂妄不羁的性格表露无遗。他的这种狂妄使得他这个渺小人类之中的一员,在言语构筑的想象世界中,一下子扩充到了世界宇宙的范畴。他在《宣州谢眺楼饯别校书叔云》中,简简单单的一句“欲上青天揽日月”,就唯妙唯肖的描绘出了他“笑孔丘”的“狂”态,而这句话中所传递出来的他作为一位心比天高的宇宙间的自由人的身份,也正是他“笑孔丘”的原因所在。孔丘之道正是儒家思想的根本,注重的是忠孝仁义,其人格观也是以“爱君忧键敬碧民之心,经国匡世之略” 为标准的。这种人格观的本质是一种社会集体的人格观。在当时封建制度的统治下,这种社会集体的人格观其实也是封建制度的人格观,而非是个人的人格观。李白能够“笑孔丘”,就足以看出他对当时占统治地位的儒家思想的反叛。李白是个极其个性化的诗人,他敢爱、敢恨,敢喜、敢忧,他的一切似乎都是和儒家提倡的中庸之道背道而驰。在他的诗里,常会出现诸如愁杀、笑杀、狂杀、醉杀、恼杀等夸张的用字,如:
荷花娇欲语,愁杀荡舟人! ---《绿水曲》
笑杀陶泉明,不饮杯中酒。 ---《嘲王历阳不肯饮酒》
春风狂杀人,一日剧三年。 ---《寄韦南陵冰余江上乘兴访之遇寻颜尚书笑有此赠》
巴陵无限酒,醉杀洞庭秋! ---《陪侍郎叔游洞庭醉后》
此句并非是李白自比楚狂,嘲笑孔丘,而是以孔丘自比,托孔丘以自伤。李白整个人生态度是积极入仕的,和楚狂隐而不仕的消极人生态度不同,李白自称“楚狂”实是用反照法表现自己政治上找不到出路的痛苦。李白对孔丘是尊敬的,“凤歌笑孔丘”中的“笑”也是反照写法,郁结着李白一生的辛酸与愤懑,以孔丘相托,笑自己太天真,而感伤于自己。
《全文》庐山谣寄卢侍御虚舟 李白
我本楚狂人,凤歌笑孔丘。 手持绿玉杖,朝别黄鹤楼。
五岳寻仙不辞远,一生好入名山游。
庐山秀出南斗傍稿举,屏风九叠云锦张, 影落明湖青黛光。
金阙前开二峰长,银河倒挂三石梁。
香炉瀑布遥相望,回崖沓嶂凌苍苍。
翠影红霞映朝日,鸟飞不到吴天长。
登高壮观天地间,大江茫茫去不还。
黄云万里动风色,白波九道流雪山。
好为庐山谣,兴因庐山发。
闲窥石镜清我心,谢公行处苍苔没。
早服还丹无世情,琴心三叠道初成。
遥见仙人彩云里,手把芙蓉朝玉京。
先期汗漫九垓上,愿接卢敖游太清。
我本是楚狂人,唱着凤歌笑孔丘。手里拿着绿玉杖,清晨就辞别了黄鹤楼。寻访五岳找仙人,不畏路程远,这一生就喜欢踏上名山游。秀美的庐山挺拔在南斗星旁,九叠云屏就像是锦幕张,山影在鄱阳湖上映出青黛光。石门在山前开,香炉峰和双剑峰高耸入云真雄壮。三叠泉水飞泻而下,像银河倒挂一样。香炉峰和瀑布遥遥相望,曲折回旋的山崖、层层叠起的峰峦直插穹苍。山色苍翠,红霞映朝阳,鸟迹看不见,只有吴天寥廓苍茫茫。登上高山,满怀豪情让目光驰骋在天地间,大江悠悠东去不回还。黄云涌出,万里天色变,九条支流,白波滚滚有如流动的雪山。心情真好啊,写出这首《庐山谣》,面对庐山,更使我诗兴发。悠闲中,我对着石镜洗净尘世心,谢公的行迹早就被苍苔填没。我早就服下仙丹再没有尘世情,三丹和积,可说是学道已初成。远远望见仙人正在彩云里,手捧着莲稿销花去朝拜玉帝。早已约好天神会面在九天之上,希望迎接你一同邀游太清。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)