PageRenderTime 31ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/sys/directory.c

https://github.com/clone/dokan
C | 421 lines | 272 code | 100 blank | 49 comment | 57 complexity | aca524472fa2445a33bdffd6ccaf60bd MD5 | raw file
  1. /*
  2. Dokan : user-mode file system library for Windows
  3. Copyright (C) 2008 Hiroki Asakawa info@dokan-dev.net
  4. http://dokan-dev.net/en
  5. This program is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU Lesser General Public License as published by the Free
  7. Software Foundation; either version 3 of the License, or (at your option) any
  8. later version.
  9. This program is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "dokan.h"
  16. NTSTATUS
  17. DokanQueryDirectory(
  18. __in PDEVICE_OBJECT DeviceObject,
  19. __in PIRP Irp);
  20. NTSTATUS
  21. DokanNotifyChangeDirectory(
  22. __in PDEVICE_OBJECT DeviceObject,
  23. __in PIRP Irp);
  24. NTSTATUS
  25. DokanDispatchDirectoryControl(
  26. __in PDEVICE_OBJECT DeviceObject,
  27. __in PIRP Irp
  28. )
  29. {
  30. NTSTATUS status = STATUS_NOT_IMPLEMENTED;
  31. PFILE_OBJECT fileObject;
  32. PIO_STACK_LOCATION irpSp;
  33. PDokanCCB ccb;
  34. PDokanVCB vcb;
  35. PAGED_CODE();
  36. __try {
  37. FsRtlEnterFileSystem();
  38. DDbgPrint("==> DokanDirectoryControl\n");
  39. irpSp = IoGetCurrentIrpStackLocation(Irp);
  40. fileObject = irpSp->FileObject;
  41. if (fileObject == NULL) {
  42. DDbgPrint(" fileObject is NULL\n");
  43. status = STATUS_INVALID_PARAMETER;
  44. __leave;
  45. }
  46. vcb = DeviceObject->DeviceExtension;
  47. if (GetIdentifierType(vcb) != VCB ||
  48. !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) {
  49. status = STATUS_INVALID_PARAMETER;
  50. __leave;
  51. }
  52. DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp));
  53. DokanPrintFileName(fileObject);
  54. if (irpSp->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
  55. status = DokanQueryDirectory(DeviceObject, Irp);
  56. } else if( irpSp->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) {
  57. status = DokanNotifyChangeDirectory(DeviceObject, Irp);
  58. } else {
  59. DDbgPrint(" invalid minor function\n");
  60. status = STATUS_INVALID_PARAMETER;
  61. }
  62. } __finally {
  63. if (status != STATUS_PENDING) {
  64. Irp->IoStatus.Status = status;
  65. Irp->IoStatus.Information = 0;
  66. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  67. }
  68. DokanPrintNTStatus(status);
  69. DDbgPrint("<== DokanDirectoryControl\n");
  70. FsRtlExitFileSystem();
  71. }
  72. return status;
  73. }
  74. NTSTATUS
  75. DokanQueryDirectory(
  76. __in PDEVICE_OBJECT DeviceObject,
  77. __in PIRP Irp)
  78. {
  79. PFILE_OBJECT fileObject;
  80. PIO_STACK_LOCATION irpSp;
  81. PDokanVCB vcb;
  82. PDokanCCB ccb;
  83. PDokanFCB fcb;
  84. NTSTATUS status;
  85. PUNICODE_STRING searchPattern;
  86. ULONG eventLength;
  87. PEVENT_CONTEXT eventContext;
  88. ULONG index;
  89. BOOLEAN initial;
  90. ULONG flags = 0;
  91. irpSp = IoGetCurrentIrpStackLocation(Irp);
  92. fileObject = irpSp->FileObject;
  93. vcb = DeviceObject->DeviceExtension;
  94. if (GetIdentifierType(vcb) != VCB) {
  95. return STATUS_INVALID_PARAMETER;
  96. }
  97. ccb = fileObject->FsContext2;
  98. if (ccb == NULL) {
  99. return STATUS_INVALID_PARAMETER;
  100. }
  101. ASSERT(ccb != NULL);
  102. fcb = ccb->Fcb;
  103. ASSERT(fcb != NULL);
  104. if (irpSp->Flags & SL_INDEX_SPECIFIED) {
  105. DDbgPrint(" index specified %d\n", irpSp->Parameters.QueryDirectory.FileIndex);
  106. }
  107. if (irpSp->Flags & SL_RETURN_SINGLE_ENTRY) {
  108. DDbgPrint(" return single entry\n");
  109. }
  110. if (irpSp->Flags & SL_RESTART_SCAN) {
  111. DDbgPrint(" restart scan\n");
  112. }
  113. if (irpSp->Parameters.QueryDirectory.FileName) {
  114. DDbgPrint(" pattern:%wZ\n", irpSp->Parameters.QueryDirectory.FileName);
  115. }
  116. switch (irpSp->Parameters.QueryDirectory.FileInformationClass) {
  117. case FileDirectoryInformation:
  118. DDbgPrint(" FileDirectoryInformation\n");
  119. break;
  120. case FileFullDirectoryInformation:
  121. DDbgPrint(" FileFullDirectoryInformation\n");
  122. break;
  123. case FileNamesInformation:
  124. DDbgPrint(" FileNamesInformation\n");
  125. break;
  126. case FileBothDirectoryInformation:
  127. DDbgPrint(" FileBothDirectoryInformation\n");
  128. break;
  129. case FileIdBothDirectoryInformation:
  130. DDbgPrint(" FileIdBothDirectoryInformation\n");
  131. break;
  132. default:
  133. DDbgPrint(" unknown FileInfoClass %d\n", irpSp->Parameters.QueryDirectory.FileInformationClass);
  134. break;
  135. }
  136. // make a MDL for UserBuffer that can be used later on another thread context
  137. if (Irp->MdlAddress == NULL) {
  138. status = DokanAllocateMdl(Irp, irpSp->Parameters.QueryDirectory.Length);
  139. if (!NT_SUCCESS(status)) {
  140. return status;
  141. }
  142. flags = DOKAN_MDL_ALLOCATED;
  143. }
  144. // size of EVENT_CONTEXT is sum of its length and file name length
  145. eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length;
  146. initial = (BOOLEAN)(ccb->SearchPattern == NULL && !(ccb->Flags & DOKAN_DIR_MATCH_ALL));
  147. // this is an initial query
  148. if (initial) {
  149. DDbgPrint(" initial query\n");
  150. // and search pattern is provided
  151. if (irpSp->Parameters.QueryDirectory.FileName) {
  152. // free current search pattern stored in CCB
  153. if (ccb->SearchPattern)
  154. ExFreePool(ccb->SearchPattern);
  155. // the size of search pattern
  156. ccb->SearchPatternLength = irpSp->Parameters.QueryDirectory.FileName->Length;
  157. ccb->SearchPattern = ExAllocatePool(ccb->SearchPatternLength + sizeof(WCHAR));
  158. if (ccb->SearchPattern == NULL) {
  159. return STATUS_INSUFFICIENT_RESOURCES;
  160. }
  161. RtlZeroMemory(ccb->SearchPattern, ccb->SearchPatternLength + sizeof(WCHAR));
  162. // copy provided search pattern to CCB
  163. RtlCopyMemory(ccb->SearchPattern,
  164. irpSp->Parameters.QueryDirectory.FileName->Buffer,
  165. ccb->SearchPatternLength);
  166. } else {
  167. ccb->Flags |= DOKAN_DIR_MATCH_ALL;
  168. }
  169. }
  170. // if search pattern is provided, add the length of it to store pattern
  171. if (ccb->SearchPattern) {
  172. eventLength += ccb->SearchPatternLength;
  173. }
  174. eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb);
  175. if (eventContext == NULL) {
  176. return STATUS_INSUFFICIENT_RESOURCES;
  177. }
  178. eventContext->Context = ccb->UserContext;
  179. //DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext);
  180. // index which specified index-1 th directory entry has been returned
  181. // this time, 'index'th entry should be returned
  182. index = 0;
  183. if (irpSp->Flags & SL_INDEX_SPECIFIED) {
  184. index = irpSp->Parameters.QueryDirectory.FileIndex;
  185. DDbgPrint(" using FileIndex %d\n", index);
  186. } else if (FlagOn(irpSp->Flags, SL_RESTART_SCAN)) {
  187. DDbgPrint(" SL_RESTART_SCAN\n");
  188. index = 0;
  189. } else {
  190. index = (ULONG)ccb->Context;
  191. DDbgPrint(" ccb->Context %d\n", index);
  192. }
  193. eventContext->Directory.FileInformationClass = irpSp->Parameters.QueryDirectory.FileInformationClass;
  194. eventContext->Directory.BufferLength = irpSp->Parameters.QueryDirectory.Length; // length of buffer
  195. eventContext->Directory.FileIndex = index; // directory index which should be returned this time
  196. // copying file name(directory name)
  197. eventContext->Directory.DirectoryNameLength = fcb->FileName.Length;
  198. RtlCopyMemory(eventContext->Directory.DirectoryName,
  199. fcb->FileName.Buffer, fcb->FileName.Length);
  200. // if search pattern is specified, copy it to EventContext
  201. if (ccb->SearchPatternLength) {
  202. PVOID searchBuffer;
  203. eventContext->Directory.SearchPatternLength = ccb->SearchPatternLength;
  204. eventContext->Directory.SearchPatternOffset = eventContext->Directory.DirectoryNameLength;
  205. searchBuffer = (PVOID)((SIZE_T)&eventContext->Directory.SearchPatternBase[0] +
  206. (SIZE_T)eventContext->Directory.SearchPatternOffset);
  207. RtlCopyMemory(searchBuffer,
  208. ccb->SearchPattern,
  209. ccb->SearchPatternLength);
  210. DDbgPrint(" ccb->SearchPattern %ws\n", ccb->SearchPattern);
  211. }
  212. status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, flags);
  213. return status;
  214. }
  215. NTSTATUS
  216. DokanNotifyChangeDirectory(
  217. __in PDEVICE_OBJECT DeviceObject,
  218. __in PIRP Irp)
  219. {
  220. PDokanCCB ccb;
  221. PDokanFCB fcb;
  222. PFILE_OBJECT fileObject;
  223. PIO_STACK_LOCATION irpSp;
  224. PDokanVCB vcb;
  225. DDbgPrint("\tNotifyChangeDirectory\n");
  226. irpSp = IoGetCurrentIrpStackLocation(Irp);
  227. fileObject = irpSp->FileObject;
  228. vcb = DeviceObject->DeviceExtension;
  229. if (GetIdentifierType(vcb) != VCB) {
  230. return STATUS_INVALID_PARAMETER;
  231. }
  232. ccb = fileObject->FsContext2;
  233. ASSERT(ccb != NULL);
  234. fcb = ccb->Fcb;
  235. ASSERT(fcb != NULL);
  236. if (!(fcb->Flags & DOKAN_FILE_DIRECTORY)) {
  237. return STATUS_INVALID_PARAMETER;
  238. }
  239. FsRtlNotifyFullChangeDirectory(
  240. vcb->NotifySync,
  241. &vcb->DirNotifyList,
  242. ccb,
  243. (PSTRING)&fcb->FileName,
  244. irpSp->Flags & SL_WATCH_TREE ? TRUE : FALSE,
  245. FALSE,
  246. irpSp->Parameters.NotifyDirectory.CompletionFilter,
  247. Irp,
  248. NULL,
  249. NULL);
  250. return STATUS_PENDING;
  251. }
  252. VOID
  253. DokanCompleteDirectoryControl(
  254. __in PIRP_ENTRY IrpEntry,
  255. __in PEVENT_INFORMATION EventInfo
  256. )
  257. {
  258. PIRP irp;
  259. PIO_STACK_LOCATION irpSp;
  260. NTSTATUS status = STATUS_SUCCESS;
  261. ULONG info = 0;
  262. ULONG bufferLen= 0;
  263. PVOID buffer = NULL;
  264. //FsRtlEnterFileSystem();
  265. DDbgPrint("==> DokanCompleteDirectoryControl\n");
  266. irp = IrpEntry->Irp;
  267. irpSp = IrpEntry->IrpSp;
  268. // buffer pointer which points DirecotryInfo
  269. if (irp->MdlAddress) {
  270. //DDbgPrint(" use MDL Address\n");
  271. buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
  272. } else {
  273. //DDbgPrint(" use UserBuffer\n");
  274. buffer = irp->UserBuffer;
  275. }
  276. // usable buffer size
  277. bufferLen = irpSp->Parameters.QueryDirectory.Length;
  278. //DDbgPrint(" !!Returning DirecotyInfo!!\n");
  279. // buffer is not specified or short of length
  280. if (bufferLen == 0 || buffer == NULL || bufferLen < EventInfo->BufferLength) {
  281. info = 0;
  282. status = STATUS_INSUFFICIENT_RESOURCES;
  283. } else {
  284. PDokanCCB ccb = IrpEntry->FileObject->FsContext2;
  285. ULONG orgLen = irpSp->Parameters.QueryDirectory.Length;
  286. //
  287. // set the information recieved from user mode
  288. //
  289. ASSERT(buffer != NULL);
  290. RtlZeroMemory(buffer, bufferLen);
  291. //DDbgPrint(" copy DirectoryInfo\n");
  292. RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength);
  293. DDbgPrint(" eventInfo->Directory.Index = %d\n", EventInfo->Directory.Index);
  294. DDbgPrint(" eventInfo->BufferLength = %d\n", EventInfo->BufferLength);
  295. DDbgPrint(" eventInfo->Status = %x (%d)\n", EventInfo->Status, EventInfo->Status);
  296. // update index which specified n-th directory entry is returned
  297. // this should be locked before writing?
  298. ccb->Context = EventInfo->Directory.Index;
  299. ccb->UserContext = EventInfo->Context;
  300. //DDbgPrint(" set Context %X\n", (ULONG)ccb->UserContext);
  301. // written bytes
  302. //irpSp->Parameters.QueryDirectory.Length = EventInfo->BufferLength;
  303. status = EventInfo->Status;
  304. info = EventInfo->BufferLength;
  305. }
  306. if (IrpEntry->Flags & DOKAN_MDL_ALLOCATED) {
  307. DokanFreeMdl(irp);
  308. IrpEntry->Flags &= ~DOKAN_MDL_ALLOCATED;
  309. }
  310. irp->IoStatus.Status = status;
  311. irp->IoStatus.Information = info;
  312. IoCompleteRequest(irp, IO_NO_INCREMENT);
  313. DokanPrintNTStatus(status);
  314. DDbgPrint("<== DokanCompleteDirectoryControl\n");
  315. //FsRtlExitFileSystem();
  316. }