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.

2084 lines
44 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. UdfsBoot.c
  5. Abstract:
  6. Implements UDF File System Reader for reading UDF volumes from DVD/CD.
  7. Note : Read ISO-13346(ECMA-167) and UDF 2.0 document to understand the
  8. UDF format. UDF is a subset for ECMA-167 standard.
  9. Author:
  10. Vijayachandran Jayaseelan (vijayj@microsoft.com)
  11. Revision History:
  12. None
  13. --*/
  14. #ifdef UDF_TESTING
  15. #include <tbldr.h> // to test this code from user mode
  16. #else
  17. #include "bootlib.h"
  18. #include "blcache.h"
  19. //#define UDF_DEBUG 1
  20. //#define SHOW_UDF_USAGE 1
  21. #endif // for UDF_TESTING
  22. #include "udfsboot.h"
  23. #include <udf.h> // predefined IS0-13346 & UDF structures
  24. #define UDFS_ALIGN_BUFFER(Buffer, Size) (PVOID) \
  25. ((((ULONG_PTR)(Buffer) + Size - 1)) & (~((ULONG_PTR)Size - 1)))
  26. #ifndef UNALIGNED
  27. #define UNALIGNED
  28. #endif
  29. #ifdef UDF_DEBUG
  30. ULONG
  31. BlGetKey(
  32. VOID
  33. );
  34. #define DBG_PAUSE while (!BlGetKey())
  35. VOID
  36. BlClearScreen(
  37. VOID
  38. );
  39. VOID
  40. BlPositionCursor(
  41. IN ULONG Column,
  42. IN ULONG Row
  43. );
  44. #endif // for UDF_DEBUG
  45. //
  46. // Global Data
  47. //
  48. BOOTFS_INFO UdfsBootFsInfo = {L"udfs"};
  49. //
  50. // Volume table(s) for all the volumes on different devices
  51. //
  52. UDF_VOLUME UDFVolumes[UDF_MAX_VOLUMES];
  53. //
  54. // UDF file system methods
  55. //
  56. BL_DEVICE_ENTRY_TABLE UDFSMethods;
  57. //
  58. // Per Volume Cache which contains the traversed UDF directories and currently
  59. // opened UDF files.
  60. //
  61. // N.B. Its being assumed here that this reader would be reading files from
  62. // relatively few (may be 1 or 2) directorie(s) which are not nested deeply
  63. //
  64. UDF_CACHE_ENTRY UDFCache[UDF_MAX_VOLUMES][UDF_MAX_CACHE_ENTRIES];
  65. #ifdef __cplusplus
  66. #define extern "C" {
  67. #endif
  68. //
  69. // Internal Types
  70. //
  71. typedef enum _COMPARISON_RESULTS {
  72. LessThan = -1,
  73. EqualTo = 0,
  74. GreaterThan = 1
  75. } COMPARISON_RESULTS;
  76. //
  77. // Macros
  78. //
  79. #define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
  80. #define UDF_ROUND_TO(X, Y) (((X) % (Y)) ? (X) + (Y) - ((X) % (Y)) : (X))
  81. #define TOUPPER(C) ((((C) >= 'a') && ((C) <= 'z')) ? (C) - 'a' + 'A' : (C))
  82. // file entry operations
  83. #define FILE_ENTRY_TO_VOLUME(X) (((PUDFS_STRUCTURE_CONTEXT)((X)->StructureContext))->\
  84. Volume)
  85. #define FILE_ENTRY_TO_FILE_CONTEXT(X) ((PUDFS_FILE_CONTEXT)&((X)->u.UdfsFileContext))
  86. // NSR_FID operations
  87. #define UDF_FID_NAME(X) (((PUCHAR)(X)) + 38 + (X)->ImpUseLen)
  88. #define UDF_FID_LEN(X) UDF_ROUND_TO((X)->FileIDLen + (X)->ImpUseLen + 38, 4)
  89. #define UDF_BLOCK_TO_FID(X, Y) ((NSR_FID UNALIGNED *)(((PUCHAR)(X)) + (Y)->Offset))
  90. #define UDF_FID_IS_DIRECTORY(X) ((((NSR_FID UNALIGNED *)(X))->Flags & NSR_FID_F_DIRECTORY) ? TRUE : FALSE)
  91. #define UDF_FID_IS_PARENT(X) ((((NSR_FID UNALIGNED *)(X))->Flags & NSR_FID_F_PARENT) ? TRUE : FALSE)
  92. #define UDF_FID_IS_DELETED(X) ((((NSR_FID UNALIGNED *)(X))->Flags & NSR_FID_F_DELETED) ? TRUE : FALSE)
  93. #define UDF_FID_IS_HIDDEN(X) ((((NSR_FID UNALIGNED *)(X))->Flags & NSR_FID_F_HIDDEN) ? TRUE : FALSE)
  94. #define UDF_FID_SKIP(X) (UDF_FID_IS_PARENT(X) || UDF_FID_IS_DELETED(X) || UDF_FID_IS_HIDDEN(X))
  95. // ICBFILE operations
  96. #define UDF_ICB_IS_DIRECTORY(X) ((X)->Icbtag.FileType == ICBTAG_FILE_T_DIRECTORY)
  97. #define UDF_ICB_NUM_ADS(X) ((X)->AllocLength / sizeof(SHORTAD))
  98. #define UDF_ICB_GET_AD_BUFFER(X) (((PUCHAR)&((X)->AllocLength)) + 4 + (X)->EALength)
  99. #define UDF_ICB_GET_AD(X, Y) (((SHORTAD UNALIGNED *)UDF_ICB_GET_AD_BUFFER(X)) + (Y))
  100. //
  101. // Local procedure prototypes.
  102. //
  103. ARC_STATUS
  104. UDFSReadDisk(
  105. IN ULONG DeviceId,
  106. IN ULONG BlockIdx,
  107. IN ULONG Size,
  108. IN OUT PVOID Buffer,
  109. IN BOOLEAN CacheNewData
  110. );
  111. COMPARISON_RESULTS
  112. UDFSCompareAnsiNames(
  113. IN PSTRING Name1,
  114. IN PSTRING Name2
  115. );
  116. COMPARISON_RESULTS
  117. UDFSCompareStrings(
  118. IN PCHAR Str1,
  119. IN PCHAR Str2
  120. );
  121. BOOLEAN
  122. UDFSVerifyPathName(
  123. IN PCHAR Name
  124. );
  125. BOOLEAN
  126. UDFSGetPathComponent(
  127. IN PCHAR Name,
  128. IN USHORT ComponentIdx,
  129. OUT PCHAR ReqComponent
  130. );
  131. USHORT
  132. UDFSCountPathComponents(
  133. IN PCHAR Name
  134. );
  135. ULONG
  136. UDFCacheGetBestEntryByName(
  137. IN PUDF_CACHE_ENTRY,
  138. IN PCHAR Name
  139. );
  140. VOID
  141. UDFSInitUniStrFromDString(
  142. OUT PUNICODE_STRING UniStr,
  143. IN PUCHAR Buffer,
  144. IN ULONG Length
  145. );
  146. int
  147. UDFSCompareAnsiUniNames(
  148. IN CSTRING AnsiString,
  149. IN UNICODE_STRING UnicodeString
  150. );
  151. #ifdef __cplusplus
  152. }
  153. #endif
  154. //////////////////////////////////////////////////////////////////////////////
  155. //
  156. // Implementation
  157. //
  158. /////////////////////////////////////////////////////////////////////////////
  159. ARC_STATUS
  160. UDFSInitialize(
  161. VOID
  162. )
  163. /*++
  164. Routine Description:
  165. Initialize file system specific data structures.
  166. Arguments:
  167. None
  168. Return Value:
  169. ESUCCESS if successful otherwise appropriate error code
  170. --*/
  171. {
  172. //
  173. // fill in the global device entry table
  174. //
  175. UDFSMethods.Open = UDFSOpen;
  176. UDFSMethods.Close = UDFSClose;
  177. UDFSMethods.Read = UDFSRead;
  178. UDFSMethods.Write = UDFSWrite;
  179. UDFSMethods.Seek = UDFSSeek;
  180. UDFSMethods.GetFileInformation = UDFSGetFileInformation;
  181. UDFSMethods.SetFileInformation = UDFSSetFileInformation;
  182. return ESUCCESS;
  183. }
  184. PBL_DEVICE_ENTRY_TABLE
  185. IsUDFSFileStructure (
  186. IN ULONG DeviceId,
  187. IN PVOID StructureContext
  188. )
  189. /*++
  190. Routine Description:
  191. This routine determines if the partition on the specified channel
  192. contains a UDF file system volume.
  193. Arguments:
  194. DeviceId - Supplies the file table index for the device on which
  195. read operations are to be performed.
  196. StructureContext - Supplies a pointer to a UDFS file structure context.
  197. Return Value:
  198. A pointer to the UDFS entry table is returned if the partition is
  199. recognized as containing a UDFS volume. Otherwise, NULL is returned.
  200. --*/
  201. {
  202. PBL_DEVICE_ENTRY_TABLE DevMethods = 0;
  203. ULONG Index;
  204. ULONG FreeSlot = UDF_MAX_VOLUMES;
  205. //
  206. // make sure that we have not mounted the file system on
  207. // the device already
  208. //
  209. for (Index=0; Index < UDF_MAX_VOLUMES; Index++) {
  210. if ((UDFVolumes[Index].DeviceId == DeviceId) &&
  211. (UDFVolumes[Index].Cache != 0)) {
  212. break;
  213. }
  214. if ((!UDFVolumes[Index].Cache) && (FreeSlot == UDF_MAX_VOLUMES))
  215. FreeSlot = Index;
  216. }
  217. if ((Index == UDF_MAX_VOLUMES) && (FreeSlot != UDF_MAX_VOLUMES)) {
  218. if (UDFSVolumeOpen(UDFVolumes + FreeSlot, DeviceId) == ESUCCESS) {
  219. UDF_FILE_DIRECTORY RootDir;
  220. PUDF_VOLUME Volume = UDFVolumes + FreeSlot;
  221. UCHAR UBlock[UDF_BLOCK_SIZE + 256] = {0};
  222. PUCHAR Block = ALIGN_BUFFER(UBlock);
  223. BOOLEAN Result = FALSE;
  224. DevMethods = &UDFSMethods;
  225. // save off the volume context
  226. ((PUDFS_STRUCTURE_CONTEXT)StructureContext)->Volume = Volume;
  227. // initialize cache
  228. Volume->Cache = UDFCache[FreeSlot];
  229. //
  230. // Read and Cache the root directory
  231. //
  232. RootDir.Volume = Volume;
  233. RootDir.FileId.BlockIdx = -1; // invalid
  234. RootDir.FileId.Offset = -1; // invalid
  235. RootDir.IsDirectory = TRUE;
  236. RootDir.IcbBlk = Volume->RootDirBlk;
  237. if (UDFSReadDisk(Volume->DeviceId, Volume->StartBlk + RootDir.IcbBlk,
  238. UDF_BLOCK_SIZE, Block, CACHE_NEW_DATA) == ESUCCESS) {
  239. ICBFILE UNALIGNED *Icb = (ICBFILE UNALIGNED *)Block;
  240. if (Icb->Destag.Ident == DESTAG_ID_NSR_FILE) {
  241. RootDir.Size = Icb->InfoLength;
  242. RootDir.StartDataBlk = UDF_ICB_GET_AD(Icb, 0)->Start;
  243. RootDir.NumExtents = (UCHAR)UDF_ICB_NUM_ADS(Icb);
  244. Result = (UDFCachePutEntry(Volume->Cache, "\\", &RootDir) != -1);
  245. }
  246. }
  247. if (!Result) {
  248. memset(Volume, 0, sizeof(UDF_VOLUME));
  249. DevMethods = 0;
  250. }
  251. }
  252. }
  253. else {
  254. // use already mounted volume
  255. if (Index != UDF_MAX_VOLUMES) {
  256. DevMethods = &UDFSMethods;
  257. ((PUDFS_STRUCTURE_CONTEXT)StructureContext)->Volume =
  258. UDFVolumes + Index;
  259. }
  260. }
  261. return DevMethods;
  262. }
  263. //
  264. // Volume methods
  265. //
  266. ARC_STATUS
  267. UDFSVolumeOpen(
  268. IN PUDF_VOLUME Volume,
  269. IN ULONG DeviceId
  270. )
  271. /*++
  272. Routine Description:
  273. Mounts the UDFS Volume on the device and updates the
  274. file system state (global data structures)
  275. Arguments:
  276. Volume - UDF Volume pointer
  277. DeviceId - Device on which the Volume may be residing
  278. Return Value:
  279. ESUCCESS if successful otherwise EBADF (if no UDF volume was found)
  280. --*/
  281. {
  282. ARC_STATUS Status = ESUCCESS;
  283. UCHAR UBlock[UDF_BLOCK_SIZE+256] = {0};
  284. PUCHAR Block = ALIGN_BUFFER(UBlock);
  285. ULONG BlockIdx = 256;
  286. ULONG LastBlock = 0;
  287. while (Status == ESUCCESS) {
  288. // get hold of Anchor Volume Descriptor
  289. Status = UDFSReadDisk(DeviceId, BlockIdx, UDF_BLOCK_SIZE, Block, CACHE_NEW_DATA);
  290. if (Status == ESUCCESS) {
  291. NSR_ANCHOR UNALIGNED *Anchor = (NSR_ANCHOR UNALIGNED *)Block;
  292. Status = EBADF;
  293. if (Anchor->Destag.Ident == DESTAG_ID_NSR_ANCHOR) {
  294. // get partition descriptor
  295. NSR_PART UNALIGNED *Part;
  296. WCHAR UNALIGNED *TagID;
  297. ULONG BlockIdx = Anchor->Main.Lsn;
  298. do {
  299. Status = UDFSReadDisk(DeviceId, BlockIdx++, UDF_BLOCK_SIZE, Block, CACHE_NEW_DATA);
  300. TagID = (WCHAR UNALIGNED *)Block;
  301. }
  302. while ((Status == ESUCCESS) && (*TagID) &&
  303. (*TagID != DESTAG_ID_NSR_TERM) && (*TagID != DESTAG_ID_NSR_PART));
  304. if ((Status == ESUCCESS) && (*TagID == DESTAG_ID_NSR_PART)){
  305. Part = (NSR_PART UNALIGNED *)Block;
  306. if (strstr(Part->ContentsID.Identifier, "+NSR")){
  307. Volume->DeviceId = DeviceId;
  308. Volume->StartBlk = Part->Start;
  309. Volume->BlockSize = UDF_BLOCK_SIZE;
  310. // get FSD at partition starting
  311. if (UDFSVolumeReadBlock(Volume, 0, Block) == ESUCCESS) {
  312. NSR_FSD UNALIGNED *FileSet = (NSR_FSD UNALIGNED *)Block;
  313. ULONG RootDirBlk = FileSet->IcbRoot.Start.Lbn;
  314. // get hold of root directory entry
  315. if (UDFSVolumeReadBlock(Volume, RootDirBlk, Block) == ESUCCESS) {
  316. ICBFILE UNALIGNED *RootDir = (ICBFILE UNALIGNED *)Block;
  317. if (RootDir->Destag.Ident == DESTAG_ID_NSR_FILE) {
  318. Volume->RootDirBlk = RootDirBlk;
  319. Status = ESUCCESS;
  320. break;
  321. }
  322. }
  323. }
  324. }
  325. }
  326. }
  327. }
  328. /*
  329. //
  330. // AVD should be at atleast two of the following locations
  331. // 256, N and N - 256
  332. //
  333. if (Status != ESUCCESS) {
  334. if (BlockIdx == 256) {
  335. FILE_INFORMATION FileInfo;
  336. Status = BlGetFileInformation(DeviceId, &FileInfo);
  337. if (Status == ESUCCESS) {
  338. LastBlock = (ULONG)((FileInfo.EndingAddress.QuadPart - FileInfo.StartingAddress.QuadPart) /
  339. UDF_BLOCK_SIZE);
  340. if (LastBlock) {
  341. LastBlock--;
  342. BlockIdx = LastBlock;
  343. Status = ESUCCESS;
  344. }
  345. }
  346. } else {
  347. if (LastBlock > 256) {
  348. BlockIdx = LastBlock - 256;
  349. Status = ESUCCESS;
  350. }
  351. }
  352. }
  353. */
  354. }
  355. return Status;
  356. }
  357. ARC_STATUS
  358. UDFSVolumeReadBlock(
  359. IN PUDF_VOLUME Volume,
  360. IN ULONG BlockIdx,
  361. OUT PUDF_BLOCK Block
  362. )
  363. /*++
  364. Routine Description:
  365. Reads a logical UDF block w.r.t to the given Volume
  366. Arguments:
  367. Volume - Pointer to UDF_VOLUME on which the block is to
  368. be read
  369. BlockIdx - Logical (zero based) index w.r.t to Volume start
  370. Block - Buffer to read the block into.
  371. Return Value:
  372. ESSUCESS if the block is read successfully otherwise appropriate
  373. error code.
  374. --*/
  375. {
  376. ARC_STATUS Result;
  377. // TBD : add range checking
  378. Result = UDFSReadDisk(
  379. Volume->DeviceId,
  380. Volume->StartBlk + BlockIdx,
  381. UDF_BLOCK_SIZE,
  382. Block,
  383. DONT_CACHE_NEW_DATA
  384. );
  385. return Result;
  386. }
  387. ARC_STATUS
  388. UDFSOpen (
  389. IN CHAR * FIRMWARE_PTR OpenPath,
  390. IN OPEN_MODE OpenMode,
  391. OUT ULONG * FIRMWARE_PTR FileId
  392. )
  393. /*++
  394. Routine Description:
  395. Opens the required file/directory on a UDF volume residing
  396. on the specified device.
  397. Arguments:
  398. OpenPath - Fully qualified path to the file/directory to open
  399. OpenMode - Required Open Mode
  400. FileId - File identifier as an index to BlFileTable which
  401. has to be updated for file/dir properties
  402. Return Value:
  403. ESUCCESS if successful otherwise appropriate error code.
  404. --*/
  405. {
  406. ARC_STATUS Status;
  407. PBL_FILE_TABLE FileEntry = BlFileTable + (*FileId);
  408. PUDF_VOLUME Volume = FILE_ENTRY_TO_VOLUME(FileEntry);
  409. PUDF_CACHE_ENTRY Cache = Volume->Cache;
  410. ULONG CacheIdx = UDFCacheGetEntryByName(Cache, OpenPath, TRUE);
  411. PUDFS_FILE_CONTEXT FileContext = FILE_ENTRY_TO_FILE_CONTEXT(FileEntry);
  412. #ifdef UDF_DEBUG
  413. BlClearScreen();
  414. BlPrint("UDFSOpen(%s)\r\n", OpenPath);
  415. #else
  416. #ifdef SHOW_UDF_USAGE
  417. BlPositionCursor(1, 22);
  418. BlPrint(" ", OpenPath);
  419. BlPositionCursor(1, 22);
  420. BlPrint("UDFSOpen( %s )", OpenPath);
  421. #endif // for SHOW_UDF_USAGE
  422. #endif // for UDF_DEBUG
  423. if (UDFSVerifyPathName(OpenPath)) {
  424. if (CacheIdx == -1) {
  425. //
  426. // create an entry and cache it
  427. //
  428. CacheIdx = UDFCacheGetBestEntryByName(Cache, OpenPath);
  429. if (CacheIdx != -1) {
  430. ULONG PathSize = strlen(OpenPath);
  431. ULONG BestSize = strlen(Cache[CacheIdx].Name);
  432. if (BestSize == 1) // root directory
  433. BestSize--;
  434. if ((BestSize < PathSize) && (OpenPath[BestSize] == '\\')) {
  435. CHAR FullPath[256];
  436. CHAR Component[256];
  437. PUDF_FILE_DIRECTORY Entry = &(Cache[CacheIdx].File);
  438. UDF_FILE_DIRECTORY NewId;
  439. if (BestSize > 1)
  440. strcpy(FullPath, Cache[CacheIdx].Name);
  441. else
  442. FullPath[0] = 0;
  443. BestSize++;
  444. UDFSGetPathComponent(OpenPath + BestSize, 0, Component);
  445. Status = Component[0] ? ESUCCESS : ENOENT;
  446. while ((CacheIdx != -1) && (Status == ESUCCESS) && Component[0]) {
  447. Status = UDFSDirGetFile(Entry, Component, &NewId);
  448. if (Status == ESUCCESS) {
  449. strcat(FullPath, "\\");
  450. strcat(FullPath, Component);
  451. // cache the directory entry
  452. CacheIdx = UDFCachePutEntry(Cache, FullPath, &NewId);
  453. BestSize += strlen(Component);
  454. if (OpenPath[BestSize] == '\\')
  455. BestSize++;
  456. UDFSGetPathComponent(OpenPath + BestSize, 0, Component);
  457. if (CacheIdx != -1) {
  458. Entry = &(Cache[CacheIdx].File);
  459. }
  460. }
  461. }
  462. if ((Status == ESUCCESS) && !Component[0] && (CacheIdx != -1)) {
  463. if (OpenMode != ArcOpenReadOnly)
  464. Status = EACCES;
  465. }
  466. else
  467. Status = ENOENT;
  468. }
  469. else
  470. Status = ENOENT;
  471. }
  472. else
  473. Status = EINVAL;
  474. } else {
  475. //
  476. // use the already cached entry
  477. //
  478. if (OpenMode == ArcOpenReadOnly) {
  479. Status = ESUCCESS;
  480. } else {
  481. Status = EACCES;
  482. }
  483. }
  484. } else {
  485. Status = EINVAL;
  486. }
  487. if (Status == ESUCCESS) {
  488. FileContext->CacheIdx = CacheIdx;
  489. FileEntry->Position.QuadPart = 0;
  490. FileEntry->Flags.Open = 1;
  491. FileEntry->Flags.Read = 1;
  492. FileEntry->Flags.Write = 0;
  493. FileEntry->Flags.Firmware = 0;
  494. }
  495. #ifdef UDF_DEBUG
  496. if (Status) {
  497. BlPrint("UDFSOpen() error : %d. Press any key to Continue.\r\n", Status);
  498. DBG_PAUSE;
  499. }
  500. #endif
  501. return Status;
  502. }
  503. ARC_STATUS
  504. UDFSClose (
  505. IN ULONG FileId
  506. )
  507. /*++
  508. Routine Description:
  509. Closes the given file/directory.
  510. Arguments:
  511. FileId - The file identifier, as an index into the BlFileTable
  512. Return Value:
  513. ESUCCESS if successful otherwise appropriate error code
  514. --*/
  515. {
  516. PBL_FILE_TABLE FileEntry = BlFileTable + FileId;
  517. PUDF_VOLUME Volume = FILE_ENTRY_TO_VOLUME(FileEntry);
  518. PUDF_CACHE_ENTRY Cache = Volume->Cache;
  519. PUDFS_FILE_CONTEXT FileContext = FILE_ENTRY_TO_FILE_CONTEXT(FileEntry);
  520. ULONG CacheIdx = FileContext->CacheIdx;
  521. // decrement usage from cache
  522. UDFCacheDecrementUsage(Cache, CacheIdx);
  523. FileEntry->Flags.Open = 0;
  524. return ESUCCESS;
  525. }
  526. ARC_STATUS
  527. UDFSRead (
  528. IN ULONG FileId,
  529. OUT VOID * FIRMWARE_PTR Buffer,
  530. IN ULONG Length,
  531. OUT ULONG * FIRMWARE_PTR Count
  532. )
  533. /*++
  534. Routine Description:
  535. Reads the contents of the specified file.
  536. Arguments:
  537. FileId - File identifier as an index into BlFileTable
  538. Buffer - The location where the data has to be read into
  539. Length - The amount of data to read
  540. Count - The amount of data read
  541. Return Value:
  542. ESUCCESS if successful otherwise appropriate error code
  543. --*/
  544. {
  545. ARC_STATUS Status = ESUCCESS;
  546. PBL_FILE_TABLE FileEntry = BlFileTable + FileId;
  547. PUDF_VOLUME Volume = FILE_ENTRY_TO_VOLUME(FileEntry);
  548. PUDF_CACHE_ENTRY Cache = Volume->Cache;
  549. PUDFS_FILE_CONTEXT FileContext = FILE_ENTRY_TO_FILE_CONTEXT(FileEntry);
  550. ULONG CacheIdx = FileContext->CacheIdx;
  551. PUDF_FILE_DIRECTORY File = &(Cache[CacheIdx].File);
  552. UCHAR UBlock[UDF_BLOCK_SIZE+256] = {0};
  553. PUCHAR Block = ALIGN_BUFFER(UBlock);
  554. ULONGLONG Position = FileEntry->Position.QuadPart;
  555. ULONG BytesRead = 0;
  556. ULONG BlkIdx;
  557. if (Buffer) {
  558. ULONG CopyCount = 0;
  559. while ((Status == ESUCCESS) && (BytesRead < Length) &&
  560. (Position < File->Size)) {
  561. BlkIdx = (ULONG)(Position / UDF_BLOCK_SIZE);
  562. Status = UDFSFileReadBlock(File, BlkIdx, UDF_BLOCK_SIZE, Block);
  563. if (Status == ESUCCESS) {
  564. // must be amount requested
  565. CopyCount = MIN(Length - BytesRead, UDF_BLOCK_SIZE);
  566. // provided data is there
  567. CopyCount = (ULONG) MIN(CopyCount, File->Size - Position);
  568. // in case the position is not aligned at block boundaries
  569. CopyCount = MIN(CopyCount, UDF_BLOCK_SIZE - (ULONG)(Position % UDF_BLOCK_SIZE));
  570. memcpy((PUCHAR)Buffer + BytesRead, (PUCHAR)Block + (Position % UDF_BLOCK_SIZE),
  571. CopyCount);
  572. BytesRead += CopyCount;
  573. Position += CopyCount;
  574. }
  575. }
  576. }
  577. else
  578. Status = EINVAL;
  579. if (Status == ESUCCESS) {
  580. FileEntry->Position.QuadPart = Position;
  581. *Count = BytesRead;
  582. }
  583. return Status;
  584. }
  585. ARC_STATUS
  586. UDFSSeek (
  587. IN ULONG FileId,
  588. IN LARGE_INTEGER * FIRMWARE_PTR Offset,
  589. IN SEEK_MODE SeekMode
  590. )
  591. /*++
  592. Routine Description:
  593. Changes the file's pointer (for random access)
  594. Arguments:
  595. FileId : File identifier as an index into the BlFileTable
  596. Offset : Seek amount
  597. SeekMode : Type of seek (absolute, relative, from end)
  598. Return Value:
  599. ESUCCESS if successful otherwise appropriate error code
  600. --*/
  601. {
  602. ARC_STATUS Status = ESUCCESS;
  603. PBL_FILE_TABLE FileEntry = BlFileTable + FileId;
  604. PUDF_VOLUME Volume = FILE_ENTRY_TO_VOLUME(FileEntry);
  605. PUDF_CACHE_ENTRY Cache = Volume->Cache;
  606. PUDFS_FILE_CONTEXT FileContext = FILE_ENTRY_TO_FILE_CONTEXT(FileEntry);
  607. ULONG CacheIdx = FileContext->CacheIdx;
  608. PUDF_FILE_DIRECTORY File = &(Cache[CacheIdx].File);
  609. ULONGLONG Position = FileEntry->Position.QuadPart;
  610. switch (SeekMode) {
  611. case SeekAbsolute:
  612. Position = Offset->QuadPart;
  613. break;
  614. case SeekRelative:
  615. Position += Offset->QuadPart;
  616. break;
  617. case SeekMaximum:
  618. Position = File->Size + Offset->QuadPart;
  619. break;
  620. default:
  621. Status = EINVAL;
  622. break;
  623. }
  624. if ((Status == ESUCCESS) && (Position < File->Size))
  625. FileEntry->Position.QuadPart = Position;
  626. else
  627. Status = EINVAL;
  628. return Status;
  629. }
  630. ARC_STATUS
  631. UDFSWrite (
  632. IN ULONG FileId,
  633. IN VOID * FIRMWARE_PTR Buffer,
  634. IN ULONG Length,
  635. OUT ULONG * FIRMWARE_PTR Count
  636. )
  637. /*++
  638. Routine Description:
  639. Write the specified data to the given file.
  640. Arguments:
  641. FileId : File identifier as an index into BlFileTable
  642. Buffer : Pointer to the data, which has to be written
  643. Length : The amount of data to be written
  644. Count : The amount of data written.
  645. Return Value:
  646. ESUCCESS if successful otherwise appropriate error code
  647. --*/
  648. {
  649. return EACCES;
  650. }
  651. ARC_STATUS
  652. UDFSGetFileInformation (
  653. IN ULONG FileId,
  654. OUT FILE_INFORMATION * FIRMWARE_PTR Buffer
  655. )
  656. /*++
  657. Routine Description:
  658. Gets the file information as required by FILE_INFORMATION
  659. fields.
  660. Arguments:
  661. FileId : File identifier as an index into BlFileTable
  662. Buffer : FILE_INFORMATION structure pointer, to be filled in.
  663. Return Value:
  664. ESUCCESS if successful otherwise appropriate error code
  665. --*/
  666. {
  667. PBL_FILE_TABLE FileEntry = BlFileTable + FileId;
  668. PUDF_VOLUME Volume = FILE_ENTRY_TO_VOLUME(FileEntry);
  669. PUDF_CACHE_ENTRY Cache = Volume->Cache;
  670. PUDFS_FILE_CONTEXT FileContext = FILE_ENTRY_TO_FILE_CONTEXT(FileEntry);
  671. ULONG CacheIdx = FileContext->CacheIdx;
  672. PUDF_FILE_DIRECTORY File = &(Cache[CacheIdx].File);
  673. PCHAR Name;
  674. PCHAR Component;
  675. memset(Buffer, 0, sizeof(FILE_INFORMATION));
  676. Buffer->EndingAddress.QuadPart = File->Size;
  677. Buffer->CurrentPosition = FileEntry->Position;
  678. if (File->IsDirectory)
  679. Buffer->Attributes |= ArcDirectoryFile;
  680. //
  681. // get hold of the last component in the path name
  682. //
  683. Name = Cache[CacheIdx].Name;
  684. Component = 0;
  685. while (Name) {
  686. Component = Name + 1; // skip '\\'
  687. Name = strchr(Component, '\\');
  688. }
  689. if (Component) {
  690. Buffer->FileNameLength = strlen(Component);
  691. strncpy(Buffer->FileName, Component, sizeof(Buffer->FileName) - 1);
  692. Buffer->FileName[sizeof(Buffer->FileName) - 1] = 0; // null terminate
  693. }
  694. return ESUCCESS;
  695. }
  696. ARC_STATUS
  697. UDFSSetFileInformation (
  698. IN ULONG FileId,
  699. IN ULONG AttributeFlags,
  700. IN ULONG AttributeMask
  701. )
  702. /*++
  703. Routine Description:
  704. Sets the given file information for the specified file.
  705. Arguments:
  706. FileId : File identifier as an index into BlFileTable
  707. AttributeFlags: The flags to be set for the file (like read only
  708. hidden, system etc.)
  709. AttributeMas : Mask to be used for the attributes
  710. Return Value:
  711. ESUCCESS if successful otherwise appropriate error code
  712. --*/
  713. {
  714. return EACCES;
  715. }
  716. //
  717. // file / directory method implementations
  718. //
  719. ARC_STATUS
  720. UDFSFileReadBlock(
  721. IN PUDF_FILE_DIRECTORY File,
  722. IN ULONG BlockIdx,
  723. IN ULONG Size,
  724. OUT PUDF_BLOCK Block
  725. )
  726. /*++
  727. Routine Description:
  728. Reads a file/directory data block relative to the start of
  729. the file/directory's data extent.
  730. Arguments:
  731. File - UDF_FILE_DIRECTORY pointer indicating the file to
  732. be operated upon.
  733. BlockIdx - Zero based block index (w.r.t. to file's data extent)
  734. Size - Size of the block in bytes
  735. Block - Buffer where the data has to be read in.
  736. Return Value:
  737. ESUCCESS if successful otherwise appropriate error code
  738. --*/
  739. {
  740. ARC_STATUS Status;
  741. if (File->NumExtents > 1) {
  742. //
  743. // map the logical file block to the acutal volume logical block
  744. //
  745. Status = UDFSVolumeReadBlock(File->Volume, File->IcbBlk, Block);
  746. if (Status == ESUCCESS) {
  747. ICBFILE UNALIGNED *Icb = (ICBFILE UNALIGNED *)Block;
  748. ULONG ExtentIdx = 0;
  749. SHORTAD UNALIGNED *Extent = UDF_ICB_GET_AD(Icb, ExtentIdx);
  750. ULONG ExtentLength = 0;
  751. ULONG NumBlocks = 0;
  752. while (ExtentIdx < File->NumExtents) {
  753. Extent = UDF_ICB_GET_AD(Icb, ExtentIdx);
  754. ExtentLength = (Extent->Length.Length / Size);
  755. NumBlocks += ExtentLength;
  756. if (NumBlocks > BlockIdx)
  757. break;
  758. ExtentIdx++;
  759. }
  760. if (Extent) {
  761. ULONG StartBlock = Extent->Start + (BlockIdx - (NumBlocks - ExtentLength));
  762. Status = UDFSVolumeReadBlock(File->Volume, StartBlock, Block);
  763. } else {
  764. Status = EIO;
  765. }
  766. }
  767. } else {
  768. Status = UDFSVolumeReadBlock(File->Volume, File->StartDataBlk + BlockIdx, Block);
  769. }
  770. return Status;
  771. }
  772. ARC_STATUS
  773. UDFSDirGetFirstFID(
  774. IN PUDF_FILE_DIRECTORY Dir,
  775. OUT PUDF_FILE_IDENTIFIER File,
  776. OUT PUDF_BLOCK Block
  777. )
  778. /*++
  779. Routine Description:
  780. Gets the first FID (file identifier descriptor) for the given
  781. directory.
  782. Arguments:
  783. Dir : The directory whose first FID is to be read.
  784. File : The file identifier descriptor which has to be update
  785. Block : The block in the actual UDF NSR_FID will reside
  786. Return Value:
  787. ESUCCESS if successful otherwise appropriate error code
  788. --*/
  789. {
  790. ARC_STATUS Status = ENOENT;
  791. UDF_FILE_IDENTIFIER Ident = {0};
  792. NSR_FID UNALIGNED *Fid;
  793. Status = UDFSFileReadBlock(Dir, 0, UDF_BLOCK_SIZE, Block);
  794. Fid = UDF_BLOCK_TO_FID(Block, &Ident);
  795. if ((Status == ESUCCESS) && (Fid->Destag.Ident == DESTAG_ID_NSR_FID)) {
  796. File->BlockIdx = 0; // relative to the file's data
  797. File->Offset = 0;
  798. }
  799. return Status;
  800. }
  801. #define UDF_NEXT_BLOCK(_Block) ((PUDF_BLOCK)((PUCHAR)_Block + UDF_BLOCK_SIZE))
  802. BOOLEAN
  803. UDFSCurrentFIDSpansBlock(
  804. IN NSR_FID UNALIGNED *Fid,
  805. IN PUDF_FILE_IDENTIFIER File
  806. )
  807. {
  808. BOOLEAN Result = ((File->Offset + UDF_FID_LEN(Fid)) > UDF_BLOCK_SIZE) ? TRUE : FALSE;
  809. #ifdef UDF_DEBUG
  810. if (Result)
  811. BlPrint("Current Fid Spans block\r\n");
  812. #endif
  813. return Result;
  814. }
  815. BOOLEAN
  816. UDFSNextFidSpansBlock(
  817. IN PUDF_FILE_IDENTIFIER CurrFile,
  818. IN PUDF_BLOCK Block
  819. )
  820. {
  821. BOOLEAN Result = FALSE;
  822. NSR_FID UNALIGNED *CurrFid = UDF_BLOCK_TO_FID(Block, CurrFile);
  823. if (!UDFSCurrentFIDSpansBlock(CurrFid, CurrFile)) {
  824. ULONG RemainingSize = UDF_BLOCK_SIZE - (CurrFile->Offset + UDF_FID_LEN(CurrFid));
  825. if (RemainingSize < 38)
  826. Result = TRUE;
  827. else {
  828. UDF_FILE_IDENTIFIER NextFile = *CurrFile;
  829. NSR_FID UNALIGNED *NextFid = 0;
  830. NextFile.Offset += UDF_FID_LEN(CurrFid);
  831. NextFid = UDF_BLOCK_TO_FID(Block, &NextFile);
  832. if (NextFile.Offset + UDF_FID_LEN(NextFid) > UDF_BLOCK_SIZE)
  833. Result = TRUE;
  834. }
  835. }
  836. #ifdef UDF_DEBUG
  837. if (Result)
  838. BlPrint("Next Fid Spans block\r\n");
  839. #endif
  840. return Result;
  841. }
  842. ARC_STATUS
  843. UDFSDirGetNextFID(
  844. IN PUDF_FILE_DIRECTORY Dir,
  845. OUT PUDF_FILE_IDENTIFIER File,
  846. IN OUT PUDF_BLOCK Block
  847. )
  848. /*++
  849. Routine Description:
  850. Reads the next FID, for the specified Directory. The next FID
  851. is based on contents of the "File" and "Block" arguments.
  852. Arguments:
  853. Dir : The directory whose next FID is to be found
  854. File : The FID returned from previous UDFSDirGetFirstFID() or
  855. UDFSDirGetNextFID() call.
  856. Block : The block returned from previous UDFSDirGetFirstFID() or
  857. UDFSDirGetNextFID() call.
  858. Return Value:
  859. Both File and Block arguments are updated as neccessary.
  860. ESUCCESS if successful otherwise appropriate error code
  861. --*/
  862. {
  863. ARC_STATUS Status = ESUCCESS;
  864. NSR_FID UNALIGNED *Fid = UDF_BLOCK_TO_FID(Block, File);
  865. USHORT FidLen = UDF_FID_LEN(Fid);
  866. UDF_FILE_IDENTIFIER FileId = *File;
  867. if (UDFSCurrentFIDSpansBlock(Fid, &FileId)) {
  868. FileId.BlockIdx++;
  869. FileId.Offset = (FileId.Offset + FidLen) % UDF_BLOCK_SIZE;
  870. memcpy(Block, (PUCHAR)Block + UDF_BLOCK_SIZE, UDF_BLOCK_SIZE);
  871. } else {
  872. if (UDFSNextFidSpansBlock(File, Block)) {
  873. Status = UDFSFileReadBlock(Dir, FileId.BlockIdx + 1, UDF_BLOCK_SIZE,
  874. UDF_NEXT_BLOCK(Block));
  875. }
  876. FileId.Offset += FidLen;
  877. }
  878. //
  879. // make sure that the FID is valid
  880. //
  881. if (Status == ESUCCESS) {
  882. Fid = UDF_BLOCK_TO_FID(Block, &FileId);
  883. Status = (Fid->Destag.Ident == DESTAG_ID_NSR_FID) ? ESUCCESS : ENOENT;
  884. }
  885. if (Status == ESUCCESS) {
  886. *File = FileId;
  887. }
  888. return Status;
  889. }
  890. ARC_STATUS
  891. UDFSDirGetFileByEntry(
  892. IN PUDF_FILE_DIRECTORY Dir,
  893. IN PUDF_FILE_IDENTIFIER Fid,
  894. IN PUDF_BLOCK Block,
  895. OUT PUDF_FILE_DIRECTORY File
  896. )
  897. {
  898. ARC_STATUS Status = ESUCCESS;
  899. NSR_FID UNALIGNED *FileId = UDF_BLOCK_TO_FID(Block, Fid);
  900. PUCHAR UBlock[UDF_BLOCK_SIZE+256] = {0};
  901. PUCHAR IcbBlock = ALIGN_BUFFER(UBlock);
  902. File->Volume = Dir->Volume;
  903. File->FileId = *Fid;
  904. File->IsDirectory = UDF_FID_IS_DIRECTORY(FileId);
  905. File->IcbBlk = FileId->Icb.Start.Lbn;
  906. //
  907. // Get Hold of the ICB block and find the starting extent
  908. //
  909. Status = UDFSVolumeReadBlock(Dir->Volume, File->IcbBlk, IcbBlock);
  910. if (Status == ESUCCESS) {
  911. ICBFILE UNALIGNED *Icb = (ICBFILE UNALIGNED *)(IcbBlock);
  912. File->StartDataBlk = (UDF_ICB_GET_AD(Icb, 0))->Start;
  913. File->Size = Icb->InfoLength;
  914. File->NumExtents = (UCHAR)UDF_ICB_NUM_ADS(Icb);
  915. }
  916. return Status;
  917. }
  918. ARC_STATUS
  919. UDFSDirGetFile(
  920. IN PUDF_FILE_DIRECTORY Dir,
  921. IN PCHAR Name,
  922. OUT PUDF_FILE_DIRECTORY File
  923. )
  924. /*++
  925. Routine Description:
  926. Given an UDF directory gets the file/directory with the
  927. specified name.
  928. Arguments:
  929. Dir : The directory which contains the required file/directory
  930. Name : The directory/file which has to be looked for.
  931. File : The directory or file which was requested.
  932. Return Value:
  933. ESUCCESS if successful otherwise an approriate error code.
  934. --*/
  935. {
  936. UCHAR UBlock[UDF_BLOCK_SIZE * 2 + 256] = {0};
  937. PUCHAR Block = ALIGN_BUFFER(UBlock);
  938. UDF_FILE_IDENTIFIER Fid;
  939. ARC_STATUS Status; //UDFSDirGetFirstFID(Dir, &Fid, Block);
  940. BOOLEAN Found = FALSE;
  941. NSR_FID UNALIGNED *FileId;
  942. WCHAR UUniBuffer[257];
  943. PWCHAR UniBuffer = UDFS_ALIGN_BUFFER(UUniBuffer, sizeof(WCHAR));
  944. UNICODE_STRING UniName;
  945. CSTRING AnsiName;
  946. Status = UDFSDirGetFirstFID(Dir, &Fid, Block);
  947. UniName.Buffer = UniBuffer;
  948. AnsiName.Buffer = Name;
  949. AnsiName.Length = (USHORT) strlen(Name);
  950. while(!Found && (Status == ESUCCESS)) {
  951. FileId = UDF_BLOCK_TO_FID(Block, &Fid);
  952. if (!UDF_FID_SKIP(FileId)) {
  953. UDFSInitUniStrFromDString(&UniName, UDF_FID_NAME(FileId), FileId->FileIDLen);
  954. Found = (UDFSCompareAnsiUniNames(AnsiName, UniName) == EqualTo);
  955. }
  956. if (!Found) {
  957. Status = UDFSDirGetNextFID(Dir, &Fid, Block);
  958. }
  959. }
  960. if (!Found)
  961. Status = ENOENT;
  962. else {
  963. Status = UDFSDirGetFileByEntry(Dir, &Fid, Block, File);
  964. }
  965. return Status;
  966. }
  967. //
  968. // Cache method implementations
  969. //
  970. ULONG
  971. UDFCachePutEntry(
  972. IN OUT PUDF_CACHE_ENTRY Cache,
  973. IN PCHAR Name,
  974. IN PUDF_FILE_DIRECTORY File
  975. )
  976. /*++
  977. Routine Description:
  978. Puts the given file entry into the specified cache,
  979. using the given name as key.
  980. Arguments:
  981. Cache - The cache to be operated upon
  982. Name - The key for the entry to be put in
  983. File - The file entry to be cached.
  984. Return Value:
  985. If successful, Index for the entry into the Cache table
  986. where the given entry was cached otherwise -1.
  987. --*/
  988. {
  989. ULONG Index;
  990. for (Index=0; Index < UDF_MAX_CACHE_ENTRIES; Index++) {
  991. if (Cache[Index].Usage == 0)
  992. break;
  993. }
  994. if (Index == UDF_MAX_CACHE_ENTRIES)
  995. Index = -1;
  996. else {
  997. strcpy(Cache[Index].Name, Name);
  998. Cache[Index].File = *File;
  999. Cache[Index].Usage = 1;
  1000. }
  1001. return Index;
  1002. }
  1003. ULONG
  1004. UDFCacheGetEntryByName(
  1005. IN OUT PUDF_CACHE_ENTRY Cache,
  1006. IN PCHAR Name,
  1007. IN BOOLEAN Increment
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. Searches for a given entry in the Cache and returns
  1012. the index to that entry if found.
  1013. Arguments:
  1014. Cache - The cache to the operated upon
  1015. Name - The key (name of file/directory) to be used
  1016. for searching
  1017. Increment - Indicates whether to increment the usage
  1018. of the entry if one is found
  1019. Return Value:
  1020. If successful, Index for the entry into the Cache table
  1021. where the given entry was cached otherwise -1.
  1022. --*/
  1023. {
  1024. ULONG Index;
  1025. for (Index=0; Index < UDF_MAX_CACHE_ENTRIES; Index++) {
  1026. if ((Cache[Index].Usage) &&
  1027. (UDFSCompareStrings(Name, Cache[Index].Name) == EqualTo)) {
  1028. //
  1029. // found the required entry
  1030. //
  1031. if (Increment)
  1032. Cache[Index].Usage++;
  1033. break;
  1034. }
  1035. }
  1036. if (Index == UDF_MAX_CACHE_ENTRIES)
  1037. Index = -1;
  1038. return Index;
  1039. }
  1040. ULONG
  1041. UDFCacheGetBestEntryByName(
  1042. IN PUDF_CACHE_ENTRY Cache,
  1043. IN PCHAR Name
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. Searches for a closest matching entry in the Cache
  1048. and returns the index to that entry if found.
  1049. For e.g. if the cache contains "\", "\a", "\a\b",
  1050. "\a\b\e\f\g" entries and "\a\b\c\d" is requested then
  1051. "\a\b" entry will be returned
  1052. Arguments:
  1053. Cache - The cache to the operated upon
  1054. Name - The key (name of file/directory) to be used
  1055. for searching
  1056. Return Value:
  1057. If successful, Index for the entry into the Cache table
  1058. where the matched entry was cached otherwise -1.
  1059. --*/
  1060. {
  1061. ULONG Index = -1;
  1062. CHAR NameBuff[256];
  1063. STRING Str;
  1064. if (Name)
  1065. strcpy(NameBuff, Name);
  1066. else
  1067. NameBuff[0] = 0;
  1068. Str.Buffer = NameBuff;
  1069. Str.Length = (USHORT) strlen(NameBuff);
  1070. while (Str.Length && (Index == -1)) {
  1071. Index = UDFCacheGetEntryByName(Cache, Str.Buffer, FALSE);
  1072. if (Index == -1) {
  1073. while (Str.Length && (Str.Buffer[Str.Length-1] != '\\'))
  1074. Str.Length--;
  1075. if (Str.Length) {
  1076. if (Str.Length != 1)
  1077. Str.Buffer[Str.Length-1] = 0;
  1078. else
  1079. Str.Buffer[Str.Length] = 0;
  1080. }
  1081. }
  1082. }
  1083. return Index;
  1084. }
  1085. VOID
  1086. UDFCacheFreeEntry(
  1087. IN OUT PUDF_CACHE_ENTRY Cache,
  1088. IN ULONG Idx
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. Decrements the usage count for an entry in the
  1093. Cache.
  1094. Note : All the traversed directories are always
  1095. cached permanently so this method as no effect on directories.
  1096. Arguments:
  1097. Cache - Cache to be operated upon
  1098. Idx - Index of the Cache entry which has to be freed
  1099. Return Value:
  1100. None.
  1101. --*/
  1102. {
  1103. if (!Cache[Idx].File.IsDirectory) {
  1104. if (Cache[Idx].Usage)
  1105. Cache[Idx].Usage--;
  1106. }
  1107. }
  1108. VOID
  1109. UDFCacheIncrementUsage(
  1110. IN OUT PUDF_CACHE_ENTRY Cache,
  1111. IN ULONG Idx
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. Increments the usage for the given entry in the cache.
  1116. Note: Multiple open calls for the same file will result
  1117. in the cache entry being resued and hence the usage will
  1118. also be incremented.
  1119. Arguments:
  1120. Cache - The Cache to the operated upon.
  1121. Idx - Index to the cache entry which has to incremented
  1122. Return Value:
  1123. None
  1124. --*/
  1125. {
  1126. if (!Cache[Idx].File.IsDirectory)
  1127. Cache[Idx].Usage++;
  1128. }
  1129. VOID
  1130. UDFCacheDecrementUsage(
  1131. IN OUT PUDF_CACHE_ENTRY Cache,
  1132. IN ULONG Idx
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. Decrements the usage for the given entry in the cache.
  1137. Note: Multiple open calls for the same file will result
  1138. in the cache entry being resued and hence the usage will
  1139. also be incremented. Each successive close call of the
  1140. same file will result in this usage count to be decremented
  1141. until it becomes 0, when the cache slot can be reused
  1142. for other file/directory.
  1143. Arguments:
  1144. Cache - Cache to be operated upon.
  1145. Idx - Index to the Cache entry, whose usage count is
  1146. to be decremented
  1147. Return Value:
  1148. None
  1149. --*/
  1150. {
  1151. if (!Cache[Idx].File.IsDirectory && Cache[Idx].Usage)
  1152. Cache[Idx].Usage--;
  1153. }
  1154. #ifdef UDF_TESTING
  1155. //
  1156. // These are the temporary functions needed for testing
  1157. // this code in the user mode
  1158. //
  1159. ARC_STATUS
  1160. W32DeviceReadDisk(
  1161. IN ULONG DeviceId,
  1162. IN ULONG Lbo,
  1163. IN ULONG ByteCount,
  1164. IN OUT PVOID Buffer
  1165. );
  1166. ARC_STATUS
  1167. UDFSReadDisk(
  1168. IN ULONG DeviceId,
  1169. IN ULONG Lbo,
  1170. IN ULONG ByteCount,
  1171. IN OUT PVOID Buffer,
  1172. IN BOOLEAN CacheNewData
  1173. )
  1174. {
  1175. return W32DeviceReadDisk(DeviceId, Lbo, ByteCount, Buffer);
  1176. }
  1177. #else
  1178. //
  1179. // Internal support routine
  1180. //
  1181. ARC_STATUS
  1182. UDFSReadDisk(
  1183. IN ULONG DeviceId,
  1184. IN ULONG Lbo,
  1185. IN ULONG ByteCount,
  1186. IN OUT PVOID Buffer,
  1187. IN BOOLEAN CacheNewData
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. This routine reads in zero or more sectors from the specified device.
  1192. Arguments:
  1193. DeviceId - Supplies the device id to use in the arc calls.
  1194. Lbo - Supplies the LBO to start reading from.
  1195. ByteCount - Supplies the number of bytes to read.
  1196. Buffer - Supplies a pointer to the buffer to read the bytes into.
  1197. CacheNewData - Whether to cache new data read from the disk.
  1198. Return Value:
  1199. ESUCCESS is returned if the read operation is successful. Otherwise,
  1200. an unsuccessful status is returned that describes the reason for failure.
  1201. --*/
  1202. {
  1203. LARGE_INTEGER LargeLbo;
  1204. ARC_STATUS Status;
  1205. ULONG i;
  1206. LONGLONG Offset = Lbo * UDF_BLOCK_SIZE;
  1207. #ifdef UDF_DEBUG
  1208. BlPrint("UDFSReadDisk(%d, %d, %d)\r\n", DeviceId, Lbo, ByteCount);
  1209. #endif
  1210. //
  1211. // Special case the zero byte read request
  1212. //
  1213. if (ByteCount == 0) {
  1214. return ESUCCESS;
  1215. }
  1216. //
  1217. // Issue the read through the cache.
  1218. //
  1219. LargeLbo.QuadPart = Offset;
  1220. Status = BlDiskCacheRead(DeviceId,
  1221. &LargeLbo,
  1222. Buffer,
  1223. ByteCount,
  1224. &i,
  1225. CacheNewData);
  1226. if (Status != ESUCCESS) {
  1227. return Status;
  1228. }
  1229. //
  1230. // Make sure we got back the amount requested
  1231. //
  1232. if (ByteCount != i) {
  1233. return EIO;
  1234. }
  1235. //
  1236. // Everything is fine so return success to our caller
  1237. //
  1238. return ESUCCESS;
  1239. }
  1240. #endif // for UDF_TESTING
  1241. COMPARISON_RESULTS
  1242. UDFSCompareStrings(
  1243. IN PCHAR Str1,
  1244. IN PCHAR Str2
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. Compares to single byte strings (pointers).
  1249. Arguments:
  1250. Str1 : first string
  1251. Str2 : second string
  1252. Return Value:
  1253. LessThan if Str1 is lexically less than Str2
  1254. EqualTo if Str1 is lexically equal to Str2
  1255. GreaterThan if Str1 is lexically greater than Str2
  1256. --*/
  1257. {
  1258. STRING Obj1, Obj2;
  1259. Obj1.Buffer = Str1;
  1260. Obj1.Length = Str1 ? strlen(Str1) : 0;
  1261. Obj2.Buffer = Str2;
  1262. Obj2.Length = Str2 ? strlen(Str2) : 0;
  1263. return UDFSCompareAnsiNames(&Obj1, &Obj2);
  1264. }
  1265. COMPARISON_RESULTS
  1266. UDFSCompareAnsiNames(
  1267. IN PSTRING Name1,
  1268. IN PSTRING Name2
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This routine takes two names and compare them ignoring case. This
  1273. routine does not do implied dot or dbcs processing.
  1274. Arguments:
  1275. Name1 - Supplies the first name to compare
  1276. Name2 - Supplies the second name to compare
  1277. Return Value:
  1278. LessThan if Name1 is lexically less than Name2
  1279. EqualTo if Name1 is lexically equal to Name2
  1280. GreaterThan if Name1 is lexically greater than Name2
  1281. --*/
  1282. {
  1283. ULONG i;
  1284. ULONG MinimumLength;
  1285. //
  1286. // Compute the smallest of the two name lengths
  1287. //
  1288. MinimumLength = (Name1->Length < Name2->Length ? Name1->Length : Name2->Length);
  1289. //
  1290. // Now compare each character in the names.
  1291. //
  1292. for (i = 0; i < MinimumLength; i += 1) {
  1293. if (TOUPPER(Name1->Buffer[i]) < TOUPPER(Name2->Buffer[i])) {
  1294. return LessThan;
  1295. }
  1296. if (TOUPPER(Name1->Buffer[i]) > TOUPPER(Name2->Buffer[i])) {
  1297. return GreaterThan;
  1298. }
  1299. }
  1300. //
  1301. // The names compared equal up to the smallest name length so
  1302. // now check the name lengths
  1303. //
  1304. if (Name1->Length < Name2->Length) {
  1305. return LessThan;
  1306. }
  1307. if (Name1->Length > Name2->Length) {
  1308. return GreaterThan;
  1309. }
  1310. return EqualTo;
  1311. }
  1312. BOOLEAN
  1313. UDFSVerifyPathName(
  1314. IN PCHAR Name
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. Checks to see if the given path name is valid.
  1319. Arguments:
  1320. Name : path name to the verified.
  1321. Return Value:
  1322. TRUE if the path name is valid otherwise false
  1323. --*/
  1324. {
  1325. BOOLEAN Result = Name ? TRUE : FALSE;
  1326. if (Result) {
  1327. USHORT Length = (USHORT) strlen(Name);
  1328. if (Length && (Length <= 256)) {
  1329. if (Length == 1) {
  1330. Result = (Name[0] == '\\');
  1331. } else {
  1332. Result = (Name[Length-1] != '\\') &&
  1333. (Name[0] == '\\');
  1334. }
  1335. }
  1336. else
  1337. Result = FALSE;
  1338. }
  1339. return Result;
  1340. }
  1341. USHORT
  1342. UDFSCountPathComponents(
  1343. IN PCHAR Name
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. Counts the number of the components making
  1348. up the path, separated by '\\' separator
  1349. Arguments:
  1350. Name : The path name whose components are to be
  1351. counted
  1352. Return Value:
  1353. The number of components which make up the
  1354. given path.
  1355. --*/
  1356. {
  1357. USHORT Result = -1;
  1358. if (Name && Name[0]) {
  1359. PCHAR Temp = strchr(Name + 1, '\\');
  1360. if (Temp) {
  1361. Result = 0;
  1362. while (Temp) {
  1363. Result++;
  1364. Temp = strchr(Temp + 1, '\\');
  1365. }
  1366. } else {
  1367. Result = 1; // no separators
  1368. }
  1369. }
  1370. return Result;
  1371. }
  1372. BOOLEAN
  1373. UDFSGetPathComponent(
  1374. IN PCHAR Name,
  1375. IN USHORT ComponentIdx,
  1376. OUT PCHAR ReqComponent
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Retrieves the requested component from the given
  1381. path name.
  1382. Arguments:
  1383. Name : The path name whose component is to be returned
  1384. ComponentIdx : The index (zero based) for the requested
  1385. component
  1386. RequiredComponent : The requested component, if found.
  1387. Return Value:
  1388. TRUE if the component was found other wise FALSE
  1389. --*/
  1390. {
  1391. PCHAR Component = 0;
  1392. USHORT Count = 0;
  1393. //
  1394. // get hold of the component starting position
  1395. //
  1396. if (Name && Name[0]) {
  1397. if (ComponentIdx) {
  1398. Component = Name;
  1399. while (Component && (Count < ComponentIdx)) {
  1400. Component = strchr(Component + 1, '\\');
  1401. Count++;
  1402. }
  1403. if (Component && (Component[0] == '\\'))
  1404. Component++;
  1405. } else {
  1406. Component = (Name[0] == '\\') ? Name + 1 : Name;
  1407. }
  1408. }
  1409. //
  1410. // get ending position of the component
  1411. //
  1412. if (Component && Component[0] && (Component[0] != '\\')) {
  1413. PCHAR Temp = strchr(Component, '\\');
  1414. ULONG Length = Temp ? (ULONG)(Temp - Component) : strlen(Component);
  1415. strncpy(ReqComponent, Component, Length);
  1416. ReqComponent[Length] = 0;
  1417. }
  1418. else {
  1419. ReqComponent[0] = 0;
  1420. }
  1421. return (ReqComponent[0] != 0);
  1422. }
  1423. VOID
  1424. UDFSInitUniStrFromDString(
  1425. OUT PUNICODE_STRING UniStr,
  1426. IN PUCHAR Buffer,
  1427. IN ULONG Length
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. Initializes a given unicode string.
  1432. Arguments:
  1433. UniStr - The unicode string to initialize
  1434. Buffer - The buffer pointing to the unicode string
  1435. Length - The length of the d-string as recorded
  1436. Return Value:
  1437. Initialized unicode string in "UniStr"
  1438. --*/
  1439. {
  1440. UCHAR Step = 0;
  1441. PUCHAR End = Buffer + Length;
  1442. PUCHAR Curr;
  1443. PWCHAR Dest = UniStr->Buffer;
  1444. ULONG DestLen = 0;
  1445. BOOLEAN Swap = FALSE;
  1446. if (Buffer && Length) {
  1447. if (*Buffer == 0x10) {
  1448. Step = 2;
  1449. Swap = (Buffer[1] == 0); // hack for ISO long file names + UDF bridge sessions
  1450. } else {
  1451. Step = 1;
  1452. }
  1453. for (Curr = Buffer + 1; Curr < End; Curr += Step, Dest++, DestLen += Step) {
  1454. if (Swap) {
  1455. // swap copy !!!
  1456. *((UCHAR *)(Dest)) = *((UCHAR *)(Curr) + 1);
  1457. *((UCHAR *)(Dest) + 1) = *((UCHAR *)(Curr));
  1458. } else {
  1459. if (Step == 1)
  1460. *Dest = *Curr;
  1461. else
  1462. *Dest = *(PWCHAR)Curr; // erroneous media ???
  1463. }
  1464. }
  1465. UniStr->Length = (USHORT)DestLen;
  1466. ((PWCHAR)UniStr->Buffer)[DestLen/2] = 0; // null terminate the string
  1467. }
  1468. }
  1469. VOID
  1470. UDFSToAnsiString(
  1471. OUT PSTRING AnsiStr,
  1472. IN PUNICODE_STRING UniStr
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. Converts an single byte string to unicode string.
  1477. Arguments:
  1478. AnsiStr - The convereted single byte string
  1479. UniStr - The unicode string which has to be converted
  1480. Note : Each most significant byte of the Unicode characters
  1481. is simply discarded.
  1482. Return Value:
  1483. None
  1484. --*/
  1485. {
  1486. ULONG Index;
  1487. AnsiStr->Length = UniStr->Length / sizeof(WCHAR);
  1488. for (Index=0; Index < AnsiStr->Length; Index++)
  1489. AnsiStr->Buffer[Index] = (CHAR)(UniStr->Buffer[Index]);
  1490. AnsiStr->Buffer[Index] = 0;
  1491. }
  1492. VOID
  1493. UDFSToUniString(
  1494. OUT PUNICODE_STRING UniStr,
  1495. OUT PSTRING AnsiStr
  1496. )
  1497. /*++
  1498. Routine Description:
  1499. Converts a given single byte string to an Unicode string.
  1500. Arguments:
  1501. AnsiStr : The single byte string which has to be converted
  1502. UniStr : The converted unicode string.
  1503. Return Value:
  1504. None
  1505. --*/
  1506. {
  1507. ULONG Index;
  1508. UniStr->Length = AnsiStr->Length * sizeof(WCHAR);
  1509. for (Index=0; Index < AnsiStr->Length; Index++)
  1510. UniStr->Buffer[Index] = (WCHAR)(AnsiStr->Buffer[Index]);
  1511. UniStr->Buffer[Index] = 0; // unicode null
  1512. }
  1513. int
  1514. UDFSCompareAnsiUniNames(
  1515. IN CSTRING AnsiString,
  1516. IN UNICODE_STRING UnicodeString
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. This routine compares two names (one ansi and one unicode) for equality.
  1521. Arguments:
  1522. AnsiString - Supplies the ansi string to compare
  1523. UnicodeString - Supplies the unicode string to compare
  1524. Return Value:
  1525. < 0 if AnsiString is approximately < than UnicodeString
  1526. = 0 if AnsiString is approximately == UnicodeString
  1527. > 0 otherwise
  1528. --*/
  1529. {
  1530. ULONG i;
  1531. ULONG Length;
  1532. #ifdef UDF_DEBUG
  1533. {
  1534. char TempBuff[256] = {0};
  1535. STRING TempStr;
  1536. TempStr.Buffer = TempBuff;
  1537. UDFSToAnsiString(&TempStr, &UnicodeString);
  1538. BlPrint("Comparing %s - %s\r\n", AnsiString.Buffer, TempStr.Buffer);
  1539. }
  1540. #endif
  1541. //
  1542. // Determine length for compare
  1543. //
  1544. if (AnsiString.Length * sizeof( WCHAR ) < UnicodeString.Length) {
  1545. Length = AnsiString.Length;
  1546. } else {
  1547. Length = UnicodeString.Length / sizeof( WCHAR );
  1548. }
  1549. i = 0;
  1550. while (i < Length) {
  1551. //
  1552. // If the current char is a mismatch, return the difference
  1553. //
  1554. if (TOUPPER( (USHORT)AnsiString.Buffer[i] ) != TOUPPER( UnicodeString.Buffer[i] )) {
  1555. return TOUPPER( (USHORT)AnsiString.Buffer[i] ) - TOUPPER( UnicodeString.Buffer[i] );
  1556. }
  1557. i++;
  1558. }
  1559. //
  1560. // We've compared equal up to the length of the shortest string. Return
  1561. // based on length comparison now.
  1562. //
  1563. return AnsiString.Length - UnicodeString.Length / sizeof( WCHAR );
  1564. }