Leaked source code of windows server 2003
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.

615 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. udfs_rec.c
  5. Abstract:
  6. This module contains the mini-file system recognizer for UDFS.
  7. Author:
  8. Dan Lovinger (danlo) 13-Feb-1997
  9. Environment:
  10. Kernel mode, local to I/O system
  11. Revision History:
  12. --*/
  13. #include "fs_rec.h"
  14. #include "udfs_rec.h"
  15. //
  16. // The local debug trace level
  17. //
  18. #define Dbg (FSREC_DEBUG_LEVEL_UDFS)
  19. //
  20. // Tables of tokens we have to parse up from mount-time on-disk structures
  21. //
  22. PARSE_KEYVALUE VsdIdentParseTable[] = {
  23. { VSD_IDENT_BEA01, VsdIdentBEA01 },
  24. { VSD_IDENT_TEA01, VsdIdentTEA01 },
  25. { VSD_IDENT_CDROM, VsdIdentCDROM },
  26. { VSD_IDENT_CD001, VsdIdentCD001 },
  27. { VSD_IDENT_CDW01, VsdIdentCDW01 },
  28. { VSD_IDENT_CDW02, VsdIdentCDW02 },
  29. { VSD_IDENT_NSR01, VsdIdentNSR01 },
  30. { VSD_IDENT_NSR02, VsdIdentNSR02 },
  31. { VSD_IDENT_BOOT2, VsdIdentBOOT2 },
  32. { VSD_IDENT_NSR03, VsdIdentNSR03 },
  33. { NULL, VsdIdentBad }
  34. };
  35. NTSTATUS
  36. UdfsRecGetLastSessionStart(
  37. IN PDEVICE_OBJECT DeviceObject,
  38. OUT PULONG Psn
  39. );
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text(PAGE,IsUdfsVolume)
  42. #pragma alloc_text(PAGE,UdfsFindInParseTable)
  43. #pragma alloc_text(PAGE,UdfsRecFsControl)
  44. #pragma alloc_text(PAGE,UdfsRecGetLastSessionStart)
  45. #endif // ALLOC_PRAGMA
  46. //
  47. // This macro copies an unaligned src longword to a dst longword,
  48. // performing an little/big endian swap.
  49. //
  50. #define SwapCopyUchar4(Dst,Src) { \
  51. *((UNALIGNED UCHAR *)(Dst)) = *((UNALIGNED UCHAR *)(Src) + 3); \
  52. *((UNALIGNED UCHAR *)(Dst) + 1) = *((UNALIGNED UCHAR *)(Src) + 2); \
  53. *((UNALIGNED UCHAR *)(Dst) + 2) = *((UNALIGNED UCHAR *)(Src) + 1); \
  54. *((UNALIGNED UCHAR *)(Dst) + 3) = *((UNALIGNED UCHAR *)(Src)); \
  55. }
  56. #define Max(a,b) (((a) > (b)) ? (a) : (b))
  57. NTSTATUS
  58. UdfsRecGetLastSessionStart(
  59. IN PDEVICE_OBJECT DeviceObject,
  60. OUT PULONG Psn
  61. )
  62. /*++
  63. Routine Description:
  64. This function queries the underlying device for the address of the
  65. first track in the last session. Does nothing for DISK devices.
  66. Arguments:
  67. DeviceObject - Pointer to this driver's device object.
  68. Psn - receives physical sector number of first block in last session,
  69. 0 for disk devices
  70. Return Value:
  71. The function value is the final status of the operation.
  72. -*/
  73. {
  74. KEVENT Event;
  75. NTSTATUS Status;
  76. IO_STATUS_BLOCK ioStatus;
  77. CDROM_TOC_SESSION_DATA SessionData;
  78. PIRP Irp;
  79. *Psn = 0;
  80. if (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM) {
  81. return STATUS_SUCCESS;
  82. }
  83. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  84. Irp = IoBuildDeviceIoControlRequest( IOCTL_CDROM_GET_LAST_SESSION,
  85. DeviceObject,
  86. (PVOID) NULL,
  87. 0,
  88. &SessionData,
  89. sizeof( SessionData ),
  90. FALSE,
  91. &Event,
  92. &ioStatus );
  93. if (!Irp) {
  94. return STATUS_INSUFFICIENT_RESOURCES;
  95. }
  96. //
  97. // Override verify logic - we don't care. The fact we're in the picture means
  98. // someone is trying to mount new/changed media in the first place.
  99. //
  100. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  101. Status = IoCallDriver( DeviceObject, Irp );
  102. if (Status == STATUS_PENDING) {
  103. (VOID) KeWaitForSingleObject( &Event,
  104. Executive,
  105. KernelMode,
  106. FALSE,
  107. (PLARGE_INTEGER) NULL );
  108. Status = ioStatus.Status;
  109. }
  110. if (!NT_SUCCESS( Status )) {
  111. return Status;
  112. }
  113. if (SessionData.FirstCompleteSession != SessionData.LastCompleteSession) {
  114. SwapCopyUchar4( Psn, &SessionData.TrackData[0].Address );
  115. }
  116. return STATUS_SUCCESS;
  117. }
  118. NTSTATUS
  119. UdfsRecFsControl(
  120. IN PDEVICE_OBJECT DeviceObject,
  121. IN PIRP Irp
  122. )
  123. /*++
  124. Routine Description:
  125. This function performs the mount and driver reload functions for this mini-
  126. file system recognizer driver.
  127. Arguments:
  128. DeviceObject - Pointer to this driver's device object.
  129. Irp - Pointer to the I/O Request Packet (IRP) representing the function to
  130. be performed.
  131. Return Value:
  132. The function value is the final status of the operation.
  133. -*/
  134. {
  135. NTSTATUS status;
  136. PIO_STACK_LOCATION irpSp;
  137. PDEVICE_EXTENSION deviceExtension;
  138. UNICODE_STRING driverName;
  139. ULONG bytesPerSector;
  140. PDEVICE_OBJECT targetDevice;
  141. PAGED_CODE();
  142. //
  143. // Begin by determining what function that is to be performed.
  144. //
  145. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  146. irpSp = IoGetCurrentIrpStackLocation( Irp );
  147. switch ( irpSp->MinorFunction ) {
  148. case IRP_MN_MOUNT_VOLUME:
  149. //
  150. // Attempt to mount a volume: There are two different cases here:
  151. //
  152. // 1) The device is being opened for DASD access, that is, no
  153. // file system is required, thus it is OK to allow RAW to
  154. // to open it.
  155. //
  156. // 2) We need to rummage the media to see if this is a UDF volume.
  157. //
  158. status = STATUS_UNRECOGNIZED_VOLUME;
  159. targetDevice = irpSp->Parameters.MountVolume.DeviceObject;
  160. if (FsRecGetDeviceSectorSize( targetDevice,
  161. &bytesPerSector )) {
  162. if (IsUdfsVolume( targetDevice,
  163. bytesPerSector )) {
  164. status = STATUS_FS_DRIVER_REQUIRED;
  165. }
  166. }
  167. break;
  168. case IRP_MN_LOAD_FILE_SYSTEM:
  169. status = FsRecLoadFileSystem( DeviceObject,
  170. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Udfs" );
  171. break;
  172. default:
  173. status = STATUS_INVALID_DEVICE_REQUEST;
  174. }
  175. //
  176. // Finally, complete the request and return the same status code to the
  177. // caller.
  178. //
  179. Irp->IoStatus.Status = status;
  180. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  181. return status;
  182. }
  183. BOOLEAN
  184. IsUdfsVolume (
  185. IN PDEVICE_OBJECT DeviceObject,
  186. IN ULONG SectorSize
  187. )
  188. /*++
  189. Routine Description:
  190. This routine walks the Volume Recognition Sequence to determine
  191. whether this volume contains an NSR02 (ISO 13346 Section 4) image.
  192. Note: this routine is pretty much diked out of UdfsRecognizeVolume
  193. in the real filesystem, modulo fitting it into the fs recognizer.
  194. Arguments:
  195. DeviceObject - device we are checking
  196. SectorSize - size of a physical sector on this device
  197. Return Value:
  198. Boolean TRUE if we found NSR02, FALSE otherwise.
  199. --*/
  200. {
  201. BOOLEAN FoundNSR;
  202. BOOLEAN FoundBEA;
  203. BOOLEAN Resolved;
  204. ULONG LastSessionStartPsn;
  205. ULONG AssumedDescriptorSize = sizeof(VSD_GENERIC);
  206. PVSD_GENERIC VolumeStructureDescriptor = NULL;
  207. PVOID Buffer = NULL;
  208. ULONGLONG Offset;
  209. ULONGLONG StartOffset;
  210. PAGED_CODE();
  211. DebugTrace(( +1, Dbg,
  212. "IsUdfsVolume, DevObj %08x SectorSize %08x\n",
  213. DeviceObject,
  214. SectorSize ));
  215. //
  216. // Find the start of the last session
  217. //
  218. if (!NT_SUCCESS( UdfsRecGetLastSessionStart( DeviceObject,
  219. &LastSessionStartPsn))) {
  220. return FALSE;
  221. }
  222. Retry:
  223. DebugTrace(( 0, Dbg, "IsUdfsVolume, Looking at session starting Psn == 0x%x\n", LastSessionStartPsn));
  224. StartOffset =
  225. Offset = (SectorSize * LastSessionStartPsn) + SectorAlignN( SectorSize, VRA_BOUNDARY_LOCATION );
  226. FoundNSR =
  227. FoundBEA =
  228. Resolved = FALSE;
  229. while (!Resolved) {
  230. //
  231. // The VRS descriptors are 2kb, and there's a lot of media out there where
  232. // people have interpreted this as meaning the descriptors should be aligned
  233. // on 2k boundries even on >2k sector size media. So we need to look at
  234. // both 2k and sector offsets on such media. (ECMA 2/8.4 specifies that these
  235. // descriptors shall all be aligned to the start of a sector).
  236. //
  237. if (0 == (Offset & (SectorSize - 1))) {
  238. if (!FsRecReadBlock( DeviceObject,
  239. (PLARGE_INTEGER)&Offset,
  240. sizeof(VSD_GENERIC),
  241. SectorSize,
  242. &Buffer,
  243. NULL )) {
  244. break;
  245. }
  246. VolumeStructureDescriptor = Buffer;
  247. }
  248. //
  249. // Now check the type of the descriptor. All ISO 13346 VSDs are
  250. // of Type 0, 9660 PVDs are Type 1, 9660 SVDs are Type 2, and 9660
  251. // terminating descriptors are Type 255.
  252. //
  253. if (VolumeStructureDescriptor->Type == 0) {
  254. //
  255. // In order to properly recognize the volume, we must know all of the
  256. // Structure identifiers in ISO 13346 so that we can terminate if a
  257. // badly formatted (or, shockingly, non 13346) volume is presented to us.
  258. //
  259. switch (UdfsFindInParseTable( VsdIdentParseTable,
  260. VolumeStructureDescriptor->Ident,
  261. VSD_LENGTH_IDENT )) {
  262. case VsdIdentBEA01:
  263. //
  264. // Only one BEA may exist and its version must be 1 (2/9.2.3)
  265. //
  266. DebugTrace(( 0, Dbg, "IsUdfsVolume, got a BEA01\n" ));
  267. if ((FoundBEA &&
  268. DebugTrace(( 0, Dbg,
  269. "IsUdfsVolume, ... but it is a duplicate!\n" ))) ||
  270. (VolumeStructureDescriptor->Version != 1 &&
  271. DebugTrace(( 0, Dbg,
  272. "IsUdfsVolume, ... but it has a wacky version number %02x != 1!\n",
  273. VolumeStructureDescriptor->Version )))) {
  274. Resolved = TRUE;
  275. break;
  276. }
  277. FoundBEA = TRUE;
  278. break;
  279. case VsdIdentTEA01:
  280. //
  281. // If we reach the TEA it must be the case that we don't recognize
  282. //
  283. DebugTrace(( 0, Dbg, "IsUdfsVolume, got a TEA01\n" ));
  284. Resolved = TRUE;
  285. break;
  286. case VsdIdentNSR02:
  287. case VsdIdentNSR03:
  288. //
  289. // We recognize NSR02 version 1 embedded after a BEA (3/9.1.3). For
  290. // simplicity we will not bother being a complete nitpick and check
  291. // for a bounding TEA, although we will be optimistic in the case where
  292. // we fail to match the version.
  293. //
  294. DebugTrace(( 0, Dbg, "IsUdfsVolume, got an NSR02/3\n" ));
  295. if ((FoundBEA ||
  296. !DebugTrace(( 0, Dbg, "IsUdfsVolume, ... but we haven't seen a BEA01 yet!\n" ))) &&
  297. (VolumeStructureDescriptor->Version == 1 ||
  298. !DebugTrace(( 0, Dbg, "IsUdfsVolume, ... but it has a wacky version number %02x != 1\n",
  299. VolumeStructureDescriptor->Version )))) {
  300. FoundNSR = Resolved = TRUE;
  301. break;
  302. }
  303. break;
  304. case VsdIdentCD001:
  305. case VsdIdentCDW01:
  306. case VsdIdentNSR01:
  307. case VsdIdentCDW02:
  308. case VsdIdentBOOT2:
  309. DebugTrace(( 0, Dbg, "IsUdfsVolume, got a valid but uninteresting 13346 descriptor\n" ));
  310. //
  311. // Valid but uninteresting (to us) descriptors
  312. //
  313. break;
  314. default:
  315. DebugTrace(( 0, Dbg, "IsUdfsVolume, got an invalid 13346 descriptor\n" ));
  316. //
  317. // This probably was a false alert, but in any case there is nothing
  318. // on this volume for us. Exception is if this media sector size
  319. // is >= 4k, and this was the second descriptor. We'll allow
  320. // a failure here, and switch to reading in whole sector increments.
  321. //
  322. if ((Offset == (StartOffset + sizeof(VSD_GENERIC))) &&
  323. (SectorSize > sizeof( VSD_GENERIC))) {
  324. Offset -= AssumedDescriptorSize;
  325. AssumedDescriptorSize = SectorSize;
  326. }
  327. else {
  328. Resolved = TRUE;
  329. }
  330. break;
  331. }
  332. }
  333. else if (!FoundBEA && (VolumeStructureDescriptor->Type < 3 ||
  334. VolumeStructureDescriptor->Type == 255)) {
  335. DebugTrace(( 0, Dbg, "IsUdfsVolume, got a 9660 descriptor\n" ));
  336. //
  337. // Only HSG (CDROM) and 9660 (CD001) are possible, and they are only legal
  338. // before the ISO 13346 BEA/TEA extent. By design, an ISO 13346 VSD precisely
  339. // overlaps a 9660 PVD/SVD in the appropriate fields.
  340. //
  341. // Note that we aren't being strict about the structure of the 9660 descriptors
  342. // since that really isn't very interesting. We care more about the 13346.
  343. //
  344. //
  345. switch (UdfsFindInParseTable( VsdIdentParseTable,
  346. VolumeStructureDescriptor->Ident,
  347. VSD_LENGTH_IDENT )) {
  348. case VsdIdentCDROM:
  349. case VsdIdentCD001:
  350. DebugTrace(( 0, Dbg, "IsUdfsVolume, ... seems we have 9660 here\n" ));
  351. //
  352. // Note to our caller that we seem to have ISO 9660 here
  353. //
  354. break;
  355. default:
  356. DebugTrace(( 0, Dbg, "IsUdfsVolume, ... but it looks wacky\n" ));
  357. //
  358. // This probably was a false alert, but in any case there is nothing
  359. // on this volume for us. Exception is if this media sector size
  360. // is >= 4k, and this was the second descriptor. We'll allow
  361. // a failure here, and switch to reading in whole sector increments.
  362. //
  363. if ((Offset == (StartOffset + sizeof(VSD_GENERIC))) &&
  364. (SectorSize > sizeof( VSD_GENERIC))) {
  365. Offset -= AssumedDescriptorSize;
  366. AssumedDescriptorSize = SectorSize;
  367. }
  368. else {
  369. Resolved = TRUE;
  370. }
  371. break;
  372. }
  373. } else {
  374. //
  375. // Something else must be recorded on this volume.
  376. //
  377. DebugTrace(( 0, Dbg, "IsUdfsVolume, got an unrecognizeable descriptor, probably not 13346/9660\n" ));
  378. break;
  379. }
  380. Offset += AssumedDescriptorSize;
  381. VolumeStructureDescriptor = (PVSD_GENERIC)(((PUCHAR)VolumeStructureDescriptor) + sizeof( VSD_GENERIC));
  382. }
  383. //
  384. // If we were looking in the last session, and failed to find anything, then
  385. // go back and try the first.
  386. //
  387. if (!FoundNSR && (0 != LastSessionStartPsn)) {
  388. LastSessionStartPsn = 0;
  389. goto Retry;
  390. }
  391. DebugTrace(( -1, Dbg, "IsUdfsVolume -> %c\n", ( FoundNSR ? 'T' : 'F' )));
  392. //
  393. // Free up our temporary buffer
  394. //
  395. if (Buffer) {
  396. ExFreePool( Buffer );
  397. }
  398. return FoundNSR;
  399. }
  400. ULONG
  401. UdfsFindInParseTable (
  402. IN PPARSE_KEYVALUE ParseTable,
  403. IN PCHAR Id,
  404. IN ULONG MaxIdLen
  405. )
  406. /*++
  407. Routine Description:
  408. This routine walks a table of string key/value information for a match of the
  409. input Id. MaxIdLen can be set to get a prefix match.
  410. Arguments:
  411. Table - This is the table being searched.
  412. Id - Key value.
  413. MaxIdLen - Maximum possible length of Id.
  414. Return Value:
  415. Value of matching entry, or the terminating (NULL) entry's value.
  416. --*/
  417. {
  418. PAGED_CODE();
  419. while (ParseTable->Key != NULL) {
  420. if (RtlEqualMemory(ParseTable->Key, Id, MaxIdLen)) {
  421. break;
  422. }
  423. ParseTable++;
  424. }
  425. return ParseTable->Value;
  426. }