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.

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