Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

547 lines
15 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1996, Microsoft Corporation
  4. //
  5. // File: create.c
  6. //
  7. // Contents: Implements the Create code for the Dfs server. The Dfs server
  8. // only allows opening the File System Device object for the
  9. // express purpose of FsControlling to the Dfs server.
  10. //
  11. // Classes:
  12. //
  13. // Functions: DfsFsdCreate
  14. // DfsOpenDevice
  15. //
  16. //-----------------------------------------------------------------------------
  17. #include "dfsprocs.h"
  18. #include "attach.h"
  19. #include "dfswml.h"
  20. //
  21. // The debug trace level
  22. //
  23. #define Dbg (DEBUG_TRACE_CREATE)
  24. //
  25. // Local procedure prototypes
  26. //
  27. NTSTATUS
  28. DfsOpenFile(
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN PIRP Irp);
  31. NTSTATUS
  32. DfsCompleteOpenFile(
  33. IN PDEVICE_OBJECT DeviceObject,
  34. IN PIRP Irp,
  35. IN PVOID Context);
  36. NTSTATUS
  37. DfsOpenDevice (
  38. IN PFILE_OBJECT FileObject,
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN ULONG CreateOptions);
  41. VOID
  42. DfspDoesPathCrossJunctionPoint(
  43. IN PUNICODE_STRING Path,
  44. OUT BOOLEAN *IsExitPoint,
  45. OUT BOOLEAN *CrossesExitPoint);
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text( PAGE, DfsFsdCreate )
  48. #pragma alloc_text( PAGE, DfsOpenFile )
  49. #pragma alloc_text( PAGE, DfsOpenDevice )
  50. #endif // ALLOC_PRAGMA
  51. //+-------------------------------------------------------------------
  52. //
  53. // Function: DfsFsdCreate, public
  54. //
  55. // Synopsis: This routine implements the FSD part of the NtCreateFile
  56. // and NtOpenFile API calls.
  57. //
  58. // Arguments: [DeviceObject] -- Supplies the device object relative to which
  59. // the open is to be processed.
  60. // [Irp] - Supplies the Irp being processed.
  61. //
  62. // Returns: NTSTATUS - The Fsd status for the Irp
  63. //
  64. //--------------------------------------------------------------------
  65. NTSTATUS
  66. DfsFsdCreate (
  67. IN PDEVICE_OBJECT DeviceObject,
  68. IN PIRP Irp
  69. )
  70. {
  71. NTSTATUS status;
  72. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  73. PFILE_OBJECT FileObject = irpSp->FileObject;
  74. PFILE_OBJECT fileObject;
  75. ULONG createOptions;
  76. DebugTrace(+1, Dbg, "DfsFsdCreate: Entered\n", 0);
  77. DFS_TRACE_HIGH(TRACE_IRP, DfsFsdCreate_Entry,
  78. LOGPTR(DeviceObject)
  79. LOGPTR(FileObject)
  80. LOGUSTR(FileObject->FileName)
  81. LOGPTR(Irp));
  82. ASSERT(IoIsOperationSynchronous(Irp) == TRUE);
  83. //
  84. // If someone is coming in via a device object attached to a file system
  85. // device object, pass it through.
  86. //
  87. if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
  88. status = DfsVolumePassThrough(DeviceObject, Irp);
  89. DebugTrace(-1, Dbg, "DfsFsdCreate: FS Device Pass Through Exit %08lx\n", ULongToPtr( status ));
  90. return status;
  91. }
  92. //
  93. // If someone is coming in via a device object attached to a file system
  94. // volume, we need to see if they are opening an exit point via its local
  95. // file system name.
  96. //
  97. if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
  98. if (((PDFS_VOLUME_OBJECT)DeviceObject)->DfsEnable == TRUE) {
  99. status = DfsOpenFile(DeviceObject, Irp);
  100. DebugTrace(-1, Dbg, "DfsFsdCreate: Local File Open Exit %08lx\n", ULongToPtr( status ));
  101. }
  102. else {
  103. status = DfsVolumePassThrough(DeviceObject, Irp);
  104. DebugTrace(-1, Dbg, "DfsFsdCreate: (DfsDisable) FS Device Pass Through Exit %08lx\n", ULongToPtr( status ));
  105. }
  106. return status;
  107. }
  108. //
  109. // The only other create we handle is someone trying to open our own
  110. // file system device object.
  111. //
  112. ASSERT(DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM);
  113. FsRtlEnterFileSystem();
  114. fileObject = irpSp->FileObject;
  115. createOptions = irpSp->Parameters.Create.Options;
  116. if (fileObject->FileName.Length == 0 &&
  117. fileObject->RelatedFileObject == NULL) {
  118. //
  119. // This is the only case we handle
  120. //
  121. status = DfsOpenDevice(
  122. fileObject,
  123. DeviceObject,
  124. createOptions);
  125. } else {
  126. status = STATUS_INVALID_DEVICE_REQUEST;
  127. }
  128. FsRtlExitFileSystem();
  129. //
  130. // And return to our caller
  131. //
  132. DebugTrace(-1, Dbg, "DfsFsdCreate: Exit -> %08lx\n", ULongToPtr( status ));
  133. DfsCompleteRequest( Irp, status );
  134. DFS_TRACE_HIGH(TRACE_IRP, DfsFsdCreate_Exit,
  135. LOGSTATUS(status)
  136. LOGPTR(fileObject)
  137. LOGPTR(Irp));
  138. return status;
  139. }
  140. //+----------------------------------------------------------------------------
  141. //
  142. // Function: DfsOpenFile, local
  143. //
  144. // Synopsis: This routine handles file opens that come in via attached
  145. // volumes. The semantics of this open are:
  146. //
  147. // If the named file is a child of a DfsExitPath, fail it
  148. // with access denied.
  149. //
  150. // If the named file is a DfsExitPath, and CreateOptions specify
  151. // DELETE_ON_CLOSE, fail it with access denied.
  152. //
  153. // In all other cases, allocate an FCB, and pass the open through
  154. // to the underlying FS. If the open succeeds, then insert the
  155. // FCB in our FCB table. If the open fails, destroy the FCB.
  156. //
  157. // Arguments: [DeviceObject] -- The attached device object through which
  158. // the Create Irp came in.
  159. //
  160. // [Irp] -- The Create Irp.
  161. //
  162. // Returns: [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate an FCB.
  163. //
  164. // [STATUS_ACCESS_DENIED] -- The file is a child of a Dfs exit
  165. // path or the file is a Dfs exit path and
  166. // DELETE_ON_CLOSE was specified.
  167. //
  168. // Status from the underlying FS.
  169. //
  170. //-----------------------------------------------------------------------------
  171. NTSTATUS
  172. DfsOpenFile(
  173. IN PDEVICE_OBJECT DeviceObject,
  174. IN PIRP Irp)
  175. {
  176. NTSTATUS status;
  177. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  178. PIO_STACK_LOCATION nextIrpSp;
  179. PFILE_OBJECT fileObject = irpSp->FileObject;
  180. ULONG createOptions = irpSp->Parameters.Create.Options;
  181. PDFS_FCB fcb = NULL;
  182. DebugTrace(+1, Dbg, "DfsOpenFile - Entered\n", 0);
  183. DFS_TRACE_LOW(TRACE_IRP, DfsOpenFile_Entry,
  184. LOGPTR(fileObject)
  185. LOGPTR(Irp));
  186. //
  187. // Optimistically, we allocate an FCB for this open.
  188. //
  189. status = DfsAllocateFcb(DeviceObject, fileObject, &fcb);
  190. if (NT_SUCCESS(status)) {
  191. BOOLEAN isExitPoint, crossesExitPoint;
  192. DfspDoesPathCrossJunctionPoint(
  193. &fcb->FullFileName,
  194. &isExitPoint,
  195. &crossesExitPoint);
  196. if (isExitPoint && (createOptions & FILE_DELETE_ON_CLOSE))
  197. status = STATUS_ACCESS_DENIED;
  198. if (crossesExitPoint)
  199. status = STATUS_ACCESS_DENIED;
  200. }
  201. //
  202. // If we haven't failed yet, we need to pass this open down to the
  203. // underlying file system. If we failed, then we need to complete the
  204. // Create Irp.
  205. //
  206. if (NT_SUCCESS(status)) {
  207. PDEVICE_OBJECT vdo;
  208. //
  209. // Copy the stack from one to the next...
  210. //
  211. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  212. (*nextIrpSp) = (*irpSp);
  213. IoSetCompletionRoutine(
  214. Irp,
  215. DfsCompleteOpenFile,
  216. (PVOID) fcb,
  217. TRUE,
  218. TRUE,
  219. TRUE);
  220. //
  221. // Find out what device to call...and call it
  222. //
  223. vdo = ((PDFS_VOLUME_OBJECT) DeviceObject)->Provider.DeviceObject;
  224. status = IoCallDriver( vdo, Irp );
  225. DFS_TRACE_ERROR_HIGH(status, ALL_ERROR, DfsOpenFile_Error_IoCallDriver,
  226. LOGSTATUS(status)
  227. LOGPTR(fileObject)
  228. LOGPTR(Irp));
  229. } else {
  230. if (fcb != NULL) {
  231. DfsDestroyFcb(fcb);
  232. }
  233. DfsCompleteRequest( Irp, status );
  234. }
  235. DebugTrace(-1, Dbg, "DfsOpenFile - Exited %08lx\n", ULongToPtr( status ));
  236. DFS_TRACE_LOW(TRACE_IRP, DfsOpenFile_Exit,
  237. LOGSTATUS(status)
  238. LOGPTR(fileObject)
  239. LOGPTR(Irp));
  240. return( status );
  241. }
  242. //+----------------------------------------------------------------------------
  243. //
  244. // Function: DfsCompleteOpenFile, local
  245. //
  246. // Synopsis: Completion routine for DfsOpenFile. If the underlying FS
  247. // successfully opened the file, we insert the FCB into our
  248. // FCB table, else we destroy the preallocated FCB.
  249. //
  250. // Arguments: [DeviceObject] -- Our device object, unused.
  251. //
  252. // [Irp] -- The Create Irp that is being completed, unused.
  253. //
  254. // [Context] -- Actually, a pointer to our pre-allocated FCB
  255. //
  256. // Returns: [STATUS_SUCCESS] -- This function always succeeds.
  257. //
  258. //-----------------------------------------------------------------------------
  259. NTSTATUS
  260. DfsCompleteOpenFile(
  261. IN PDEVICE_OBJECT DeviceObject,
  262. IN PIRP Irp,
  263. IN PVOID Context)
  264. {
  265. PDFS_FCB fcb = (PDFS_FCB) Context;
  266. if (Irp->PendingReturned) {
  267. //
  268. // We need to call IpMarkIrpPending so the IoSubsystem will realize
  269. // that our FSD routine returned STATUS_PENDING. We can't call this
  270. // from the FSD routine itself because the FSD routine doesn't have
  271. // access to the stack location when the underlying guy returns
  272. // STATUS_PENDING
  273. //
  274. IoMarkIrpPending( Irp );
  275. }
  276. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  277. DfsAttachFcb( fcb->FileObject, fcb );
  278. } else {
  279. DfsDestroyFcb( fcb );
  280. }
  281. return( STATUS_SUCCESS );
  282. }
  283. //+-------------------------------------------------------------------
  284. //
  285. // Function: DfsOpenDevice, local
  286. //
  287. // Synopsis: This routine opens the specified device for direct
  288. // access.
  289. //
  290. // Arguments: [FileObject] - Supplies the File object
  291. // [DeviceObject] - Supplies the object denoting the device
  292. // being opened
  293. // [CreateOptions] - Supplies the create options for
  294. // this operation
  295. //
  296. // Returns: [IO_STATUS_BLOCK] - Returns the completion status for
  297. // the operation
  298. //
  299. //--------------------------------------------------------------------
  300. NTSTATUS
  301. DfsOpenDevice (
  302. IN PFILE_OBJECT FileObject,
  303. IN PDEVICE_OBJECT DeviceObject,
  304. IN ULONG CreateOptions
  305. ) {
  306. NTSTATUS status;
  307. //
  308. // Check to see which type of device is being opened.
  309. // We don't permit all open modes on the file system
  310. // device object.
  311. //
  312. ULONG CreateDisposition = (CreateOptions >> 24) & 0x000000ff;
  313. DFS_TRACE_LOW(TRACE_IRP, DfsOpenDevice_Entry,
  314. LOGPTR(FileObject)
  315. LOGPTR(DeviceObject)
  316. LOGULONG(CreateOptions));
  317. //
  318. // Check for proper desired access and rights
  319. //
  320. if (CreateDisposition != FILE_OPEN
  321. && CreateDisposition != FILE_OPEN_IF ) {
  322. status = STATUS_ACCESS_DENIED;
  323. DebugTrace(0, Dbg,
  324. "DfsOpenDevice: Invalid CreateDisposition\n", 0);
  325. DFS_TRACE_HIGH(ERROR, DfsOpenDevice_Error1,
  326. LOGSTATUS(status)
  327. LOGPTR(FileObject)
  328. LOGPTR(DeviceObject));
  329. return( status );
  330. }
  331. //
  332. // Check if we were to open a directory
  333. //
  334. if (CreateOptions & FILE_DIRECTORY_FILE) {
  335. status = STATUS_NOT_A_DIRECTORY;
  336. DebugTrace(0, Dbg,
  337. "DfsOpenDevice: Cannot open device as a directory\n", 0);
  338. DFS_TRACE_HIGH(ERROR, DfsOpenDevice_Error3,
  339. LOGSTATUS(status)
  340. LOGPTR(FileObject)
  341. LOGPTR(DeviceObject));
  342. return( status );
  343. }
  344. FileObject->FsContext = UIntToPtr( DFS_OPEN_CONTEXT );
  345. status = STATUS_SUCCESS;
  346. DFS_TRACE_LOW(TRACE_IRP, DfsOpenDevice_Exit,
  347. LOGSTATUS(status)
  348. LOGPTR(FileObject)
  349. LOGPTR(DeviceObject));
  350. return( status );
  351. }
  352. //+----------------------------------------------------------------------------
  353. //
  354. // Function: DfspDoesPathCrossJunctionPoint
  355. //
  356. // Synopsis: Given a fully formed local FS path
  357. // (looks like "\DosDevices\C:\foo\bar") this routine figures out
  358. // if the path matches an exit point exactly, or crosses an
  359. // exit point.
  360. //
  361. // Arguments: [Path] -- The path to check.
  362. // [IsExitPoint] -- The path refers to an exit point.
  363. // [CrossesExitPoint] -- The path crosses an exit point.
  364. //
  365. // Returns: NOTHING. The results are returned in the two out parameters.
  366. //
  367. //-----------------------------------------------------------------------------
  368. VOID
  369. DfspDoesPathCrossJunctionPoint(
  370. IN PUNICODE_STRING Path,
  371. OUT BOOLEAN *IsExitPoint,
  372. OUT BOOLEAN *CrossesExitPoint)
  373. {
  374. PDFS_PKT pkt;
  375. PDFS_LOCAL_VOL_ENTRY lv;
  376. UNICODE_STRING remPath;
  377. *IsExitPoint = FALSE;
  378. *CrossesExitPoint = FALSE;
  379. pkt = _GetPkt();
  380. PktAcquireShared(pkt, TRUE);
  381. lv = PktEntryLookupLocalService(pkt, Path, &remPath);
  382. if (lv != NULL && remPath.Length != 0) {
  383. PDFS_PKT_ENTRY pktEntry, pktExitEntry;
  384. USHORT prefixLength;
  385. UNICODE_STRING remExitPt;
  386. PUNICODE_STRING exitPrefix;
  387. pktEntry = lv->PktEntry;
  388. prefixLength = pktEntry->Id.Prefix.Length;
  389. pktExitEntry = PktEntryFirstSubordinate(pktEntry);
  390. //
  391. // As long as there are more exit points see if the path crosses
  392. // the exit point.
  393. //
  394. while (pktExitEntry != NULL &&
  395. !(*IsExitPoint) &&
  396. !(*CrossesExitPoint)) {
  397. exitPrefix = &pktExitEntry->Id.Prefix;
  398. if (exitPrefix->Buffer[prefixLength/sizeof(WCHAR)] == UNICODE_PATH_SEP)
  399. prefixLength += sizeof(WCHAR);
  400. remExitPt.Length = pktExitEntry->Id.Prefix.Length - prefixLength;
  401. remExitPt.MaximumLength = remExitPt.Length + 1;
  402. remExitPt.Buffer = &exitPrefix->Buffer[prefixLength/sizeof(WCHAR)];
  403. //
  404. // If the Path has the potential of crossing past the junction
  405. // point, we have something to return!
  406. //
  407. if (DfsRtlPrefixPath(&remExitPt, &remPath, TRUE)) {
  408. if (remExitPt.Length == remPath.Length) {
  409. *IsExitPoint = TRUE;
  410. } else {
  411. *CrossesExitPoint = TRUE;
  412. }
  413. }
  414. pktExitEntry = PktEntryNextSubordinate(pktEntry, pktExitEntry);
  415. } //while exit pt exists
  416. } // lv != NULL && remPath.Length != 0
  417. PktRelease(pkt);
  418. }