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.

969 lines
22 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. blio.c
  5. Abstract:
  6. This module contains the code that implements the switch function for
  7. I/O operations between then operating system loader, the target file
  8. system, and the target device.
  9. Author:
  10. David N. Cutler (davec) 10-May-1991
  11. Revision History:
  12. --*/
  13. #include "bootlib.h"
  14. #include "stdio.h"
  15. //
  16. // Define file table.
  17. //
  18. BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
  19. #if DBG
  20. ULONG BlFilesOpened = 0;
  21. #endif
  22. #ifdef CACHE_DEVINFO
  23. //
  24. // Device close notification routines, are registered by the file system
  25. // which are interested in device close events. This is primarily used for
  26. // invalidating the internal cache, which the file system maintains
  27. // using DeviceId as one of the keys
  28. //
  29. PARC_DEVICE_CLOSE_NOTIFICATION DeviceCloseNotify[MAX_DEVICE_CLOSE_NOTIFICATION_SIZE] = {0};
  30. //
  31. // Device to filesystem cache table
  32. //
  33. DEVICE_TO_FILESYS DeviceFSCache[BL_FILE_TABLE_SIZE];
  34. ARC_STATUS
  35. ArcCacheClose(
  36. IN ULONG DeviceId
  37. )
  38. /*++
  39. Routine Description:
  40. This routine invalidates the file system information
  41. cached for the given device ID.
  42. Arguments:
  43. DeviceId : Device to close
  44. Return Value:
  45. ESUCCESS is returned if the close is successful. Otherwise,
  46. return an unsuccessful status.
  47. --*/
  48. {
  49. ULONG Index;
  50. //
  51. // Notify all the registered file system about the device close
  52. //
  53. for (Index = 0; Index < MAX_DEVICE_CLOSE_NOTIFICATION_SIZE; Index++) {
  54. if (DeviceCloseNotify[Index]) {
  55. (DeviceCloseNotify[Index])(DeviceId);
  56. }
  57. }
  58. //
  59. // Update device to file system cache
  60. //
  61. for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index++) {
  62. if (DeviceFSCache[Index].DeviceId == DeviceId){
  63. DeviceFSCache[Index].DeviceId = -1;
  64. }
  65. }
  66. return ((PARC_CLOSE_ROUTINE)
  67. (SYSTEM_BLOCK->FirmwareVector[CloseRoutine]))(DeviceId);
  68. }
  69. ARC_STATUS
  70. ArcRegisterForDeviceClose(
  71. PARC_DEVICE_CLOSE_NOTIFICATION FlushRoutine
  72. )
  73. {
  74. ARC_STATUS Status = EINVAL;
  75. if (FlushRoutine) {
  76. ULONG Index;
  77. Status = ENOENT;
  78. for (Index=0; Index < MAX_DEVICE_CLOSE_NOTIFICATION_SIZE; Index++) {
  79. if (!DeviceCloseNotify[Index]) {
  80. DeviceCloseNotify[Index] = FlushRoutine;
  81. Status = ESUCCESS;
  82. break;
  83. }
  84. }
  85. }
  86. return Status;
  87. }
  88. ARC_STATUS
  89. ArcDeRegisterForDeviceClose(
  90. PARC_DEVICE_CLOSE_NOTIFICATION FlushRoutine
  91. )
  92. {
  93. ARC_STATUS Status = EINVAL;
  94. if (FlushRoutine) {
  95. ULONG Index;
  96. Status = ENOENT;
  97. for (Index=0; Index < MAX_DEVICE_CLOSE_NOTIFICATION_SIZE; Index++) {
  98. if (DeviceCloseNotify[Index] == FlushRoutine) {
  99. DeviceCloseNotify[Index] = NULL;
  100. Status = ESUCCESS;
  101. break;
  102. }
  103. }
  104. }
  105. return Status;
  106. }
  107. #endif // CACHE_DEVINFO
  108. ARC_STATUS
  109. BlIoInitialize (
  110. VOID
  111. )
  112. /*++
  113. Routine Description:
  114. This routine initializes the file table used by the OS loader and
  115. initializes the boot loader filesystems.
  116. Arguments:
  117. None.
  118. Return Value:
  119. ESUCCESS is returned if the initialization is successful. Otherwise,
  120. return an unsuccessful status.
  121. --*/
  122. {
  123. ULONG Index;
  124. ARC_STATUS Status;
  125. #ifdef CACHE_DEVINFO
  126. RtlZeroMemory(DeviceCloseNotify, sizeof(DeviceCloseNotify));
  127. #endif
  128. //
  129. // Initialize the file table.
  130. //
  131. for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
  132. BlFileTable[Index].Flags.Open = 0;
  133. BlFileTable[Index].StructureContext = NULL;
  134. #ifdef CACHE_DEVINFO
  135. DeviceFSCache[Index].DeviceId = -1;
  136. DeviceFSCache[Index].Context = NULL;
  137. DeviceFSCache[Index].DevMethods = NULL;
  138. #endif // for CACHE_DEVINFO
  139. }
  140. if((Status = NetInitialize()) != ESUCCESS) {
  141. return Status;
  142. }
  143. if((Status = FatInitialize()) != ESUCCESS) {
  144. return Status;
  145. }
  146. if((Status = NtfsInitialize()) != ESUCCESS) {
  147. return Status;
  148. }
  149. #ifndef DONT_USE_UDF
  150. if((Status = UDFSInitialize()) != ESUCCESS) {
  151. return Status;
  152. }
  153. #endif
  154. if((Status = CdfsInitialize()) != ESUCCESS) {
  155. return Status;
  156. }
  157. return ESUCCESS;
  158. }
  159. PBOOTFS_INFO
  160. BlGetFsInfo(
  161. IN ULONG DeviceId
  162. )
  163. /*++
  164. Routine Description:
  165. Returns filesystem information for the filesystem on the specified device
  166. Arguments:
  167. FileId - Supplies the file table index of the device
  168. Return Value:
  169. PBOOTFS_INFO - Pointer to the BOOTFS_INFO structure for the filesystem
  170. NULL - unknown filesystem
  171. --*/
  172. {
  173. FS_STRUCTURE_CONTEXT FsStructure;
  174. PBL_DEVICE_ENTRY_TABLE Table;
  175. if ((Table = IsNetFileStructure(DeviceId, &FsStructure)) != NULL) {
  176. return(Table->BootFsInfo);
  177. }
  178. if ((Table = IsFatFileStructure(DeviceId, &FsStructure)) != NULL) {
  179. return(Table->BootFsInfo);
  180. }
  181. if ((Table = IsNtfsFileStructure(DeviceId, &FsStructure)) != NULL) {
  182. return(Table->BootFsInfo);
  183. }
  184. if ((Table = IsCdfsFileStructure(DeviceId, &FsStructure)) != NULL) {
  185. return(Table->BootFsInfo);
  186. }
  187. return(NULL);
  188. }
  189. ARC_STATUS
  190. BlClose (
  191. IN ULONG FileId
  192. )
  193. /*++
  194. Routine Description:
  195. This function closes a file or a device that is open.
  196. Arguments:
  197. FileId - Supplies the file table index.
  198. Return Value:
  199. If the specified file is open, then a close is attempted and
  200. the status of the operation is returned. Otherwise, return an
  201. unsuccessful status.
  202. --*/
  203. {
  204. //
  205. // If the file is open, then attempt to close it. Otherwise return an
  206. // access error.
  207. //
  208. if (BlFileTable[FileId].Flags.Open == 1) {
  209. return (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
  210. } else {
  211. return EACCES;
  212. }
  213. }
  214. ARC_STATUS
  215. BlMount (
  216. IN PCHAR MountPath,
  217. IN MOUNT_OPERATION Operation
  218. )
  219. /*++
  220. Routine Description:
  221. Arguments:
  222. Return Value:
  223. --*/
  224. {
  225. UNREFERENCED_PARAMETER(MountPath);
  226. UNREFERENCED_PARAMETER(Operation);
  227. return ESUCCESS;
  228. }
  229. ARC_STATUS
  230. _BlOpen (
  231. IN ULONG DeviceId,
  232. IN PCHAR OpenPath,
  233. IN OPEN_MODE OpenMode,
  234. OUT PULONG FileId
  235. )
  236. /*++
  237. Routine Description:
  238. This function opens a file on the specified device. The type of file
  239. system is automatically recognized.
  240. Arguments:
  241. DeviceId - Supplies the file table index of the device.
  242. OpenPath - Supplies a pointer to the name of the file to be opened.
  243. OpenMode - Supplies the mode of the open.
  244. FileId - Supplies a pointer to a variable that receives the file
  245. table index of the open file.
  246. Return Value:
  247. If a free file table entry is available and the file structure on
  248. the specified device is recognized, then an open is attempted and
  249. the status of the operation is returned. Otherwise, return an
  250. unsuccessful status.
  251. --*/
  252. {
  253. ULONG Index;
  254. FS_STRUCTURE_CONTEXT FsStructureTemp;
  255. PFS_STRUCTURE_CONTEXT FsStructure;
  256. ULONG ContextSize;
  257. ARC_STATUS Status;
  258. #ifdef CACHE_DEVINFO
  259. ULONG CacheIndex;
  260. for (CacheIndex = 0; CacheIndex < BL_FILE_TABLE_SIZE; CacheIndex++) {
  261. if (DeviceFSCache[CacheIndex].DeviceId == DeviceId){
  262. break;
  263. }
  264. }
  265. #endif // for CACHE_DEVINFO
  266. //
  267. // Search for a free file table entry.
  268. //
  269. for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
  270. if (BlFileTable[Index].Flags.Open == 0) {
  271. #ifdef CACHE_DEVINFO
  272. if (CacheIndex >= BL_FILE_TABLE_SIZE) {
  273. #endif // for CACHE_DEVINFO
  274. //
  275. // Attempt to recognize the file system on the specified
  276. // device. If no one recognizes it then return an unsuccessful
  277. // status.
  278. //
  279. if ((BlFileTable[Index].DeviceEntryTable =
  280. IsNetFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
  281. ContextSize = sizeof(NET_STRUCTURE_CONTEXT);
  282. } else if ((BlFileTable[Index].DeviceEntryTable =
  283. IsFatFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
  284. ContextSize = sizeof(FAT_STRUCTURE_CONTEXT);
  285. } else if ((BlFileTable[Index].DeviceEntryTable =
  286. IsNtfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
  287. ContextSize = sizeof(NTFS_STRUCTURE_CONTEXT);
  288. #ifndef DONT_USE_UDF
  289. } else if ((BlFileTable[Index].DeviceEntryTable =
  290. IsUDFSFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
  291. ContextSize = sizeof(UDFS_STRUCTURE_CONTEXT);
  292. #endif
  293. #if defined(ELTORITO)
  294. //
  295. // This must go before the check for Cdfs; otherwise Cdfs will be detected.
  296. // Since BIOS calls already set up to use EDDS, reads will succeed, and checks
  297. // against ISO will succeed. We check El Torito-specific fields here as well as ISO
  298. //
  299. } else if ((BlFileTable[Index].DeviceEntryTable =
  300. IsEtfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
  301. ContextSize = sizeof(ETFS_STRUCTURE_CONTEXT);
  302. #endif
  303. } else if ((BlFileTable[Index].DeviceEntryTable =
  304. IsCdfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
  305. ContextSize = sizeof(CDFS_STRUCTURE_CONTEXT);
  306. } else {
  307. return EACCES;
  308. }
  309. #ifndef CACHE_DEVINFO
  310. //
  311. // Cut down on the amount of heap we use by attempting to reuse
  312. // the fs structure context instead of always allocating a
  313. // new one. The NTFS structure context is over 4K; the FAT one
  314. // is almost 2K. In the setup case we're loading dozens of files.
  315. // Add in compression, where diamond may open each file multiple
  316. // times, and we waste a lot of heap.
  317. //
  318. if(BlFileTable[Index].StructureContext == NULL) {
  319. BlFileTable[Index].StructureContext = BlAllocateHeap(sizeof(FS_STRUCTURE_CONTEXT));
  320. if(BlFileTable[Index].StructureContext == NULL) {
  321. return ENOMEM;
  322. }
  323. RtlZeroMemory(BlFileTable[Index].StructureContext, sizeof(FS_STRUCTURE_CONTEXT));
  324. }
  325. RtlCopyMemory(
  326. BlFileTable[Index].StructureContext,
  327. &FsStructureTemp,
  328. ContextSize
  329. );
  330. #else
  331. //
  332. // save the collected info in cache for future use
  333. //
  334. for (CacheIndex = 0; CacheIndex < BL_FILE_TABLE_SIZE; CacheIndex++) {
  335. if (DeviceFSCache[CacheIndex].DeviceId == -1){
  336. PVOID Context = DeviceFSCache[CacheIndex].Context;
  337. DeviceFSCache[CacheIndex].DeviceId = DeviceId;
  338. //
  339. // Cut down on the amount of heap we use by attempting to reuse
  340. // the fs structure context instead of always allocating a
  341. // new one. The NTFS structure context is over 4K; the FAT one
  342. // is almost 2K. In the setup case we're loading dozens of files.
  343. // Add in compression, where diamond may open each file multiple
  344. // times, and we waste a lot of heap.
  345. //
  346. if(Context == NULL) {
  347. Context = BlAllocateHeap(sizeof(FS_STRUCTURE_CONTEXT));
  348. if(Context == NULL) {
  349. DeviceFSCache[CacheIndex].DeviceId = -1;
  350. return ENOMEM;
  351. }
  352. RtlZeroMemory(Context, sizeof(FS_STRUCTURE_CONTEXT));
  353. DeviceFSCache[CacheIndex].Context = Context;
  354. }
  355. RtlCopyMemory(Context,
  356. &FsStructureTemp,
  357. ContextSize);
  358. BlFileTable[Index].StructureContext = Context;
  359. //
  360. // save the device table from the filetable entry
  361. //
  362. DeviceFSCache[CacheIndex].DevMethods = BlFileTable[Index].DeviceEntryTable;
  363. break;
  364. }
  365. }
  366. if (CacheIndex >= BL_FILE_TABLE_SIZE)
  367. return ENOSPC;
  368. } else {
  369. #if 0
  370. {
  371. char Msg[128] = {0};
  372. BlPositionCursor(1, 5);
  373. sprintf(Msg,
  374. "Using %d cached info %p, %p for device %d, %s",
  375. CacheIndex,
  376. DeviceFSCache[CacheIndex].Context,
  377. DeviceFSCache[CacheIndex].DevMethods,
  378. DeviceFSCache[CacheIndex].DeviceId,
  379. OpenPath);
  380. BlPrint(" ");
  381. BlPositionCursor(1, 5);
  382. BlPrint(Msg);
  383. }
  384. #endif
  385. //
  386. // Reuse the already cached entry
  387. //
  388. BlFileTable[Index].DeviceEntryTable = DeviceFSCache[CacheIndex].DevMethods;
  389. BlFileTable[Index].StructureContext = DeviceFSCache[CacheIndex].Context;
  390. }
  391. #endif // for ! CACHE_DEVINFO
  392. //
  393. // Someone has mounted the volume so now attempt to open the file.
  394. //
  395. *FileId = Index;
  396. BlFileTable[Index].DeviceId = DeviceId;
  397. Status = EBADF;
  398. #if DBG
  399. //
  400. // Check and see if a user wants to replace this binary
  401. // via a transfer through the kernel debugger. If this
  402. // fails just continue on with the existing file.
  403. //
  404. if( BdDebuggerEnabled ) {
  405. Status = BdPullRemoteFile( OpenPath,
  406. FILE_ATTRIBUTE_NORMAL,
  407. FILE_OVERWRITE_IF,
  408. FILE_SYNCHRONOUS_IO_NONALERT,
  409. *FileId );
  410. if( Status == ESUCCESS ) {
  411. DbgPrint( "BlLoadImageEx: Pulled %s from Kernel Debugger\r\n", OpenPath );
  412. }
  413. }
  414. #endif
  415. if( Status != ESUCCESS ) {
  416. Status = (BlFileTable[Index].DeviceEntryTable->Open)(OpenPath,
  417. OpenMode,
  418. FileId);
  419. }
  420. return(Status);
  421. }
  422. }
  423. //
  424. // No free file table entry could be found.
  425. //
  426. return EACCES;
  427. }
  428. ARC_STATUS
  429. BlOpen (
  430. IN ULONG DeviceId,
  431. IN PCHAR OpenPath,
  432. IN OPEN_MODE OpenMode,
  433. OUT PULONG FileId
  434. )
  435. /*++
  436. Routine Description:
  437. Wrapper routine for BlOpen that attempts to locate the compressed
  438. form of a filename before trying to locate the filename itself.
  439. Callers need not know or care that a file x.exe actually exists
  440. as a compressed file x.ex_. If the file is being opened for
  441. read-only access and the decompressor indicates that it wants
  442. to try locating the compressed form of the file, we transparently
  443. locate that one instead of the one requested.
  444. Arguments:
  445. Same as _BlOpen().
  446. Return Value:
  447. Same as _BlOpen().
  448. --*/
  449. {
  450. CHAR CompressedName[256];
  451. ARC_STATUS Status;
  452. if((OpenMode == ArcOpenReadOnly) && DecompGenerateCompressedName(OpenPath,CompressedName)) {
  453. //
  454. // Attempt to locate the compressed form of the filename.
  455. //
  456. Status = _BlOpen(DeviceId,CompressedName,OpenMode,FileId);
  457. if(Status == ESUCCESS) {
  458. Status = DecompPrepareToReadCompressedFile(CompressedName,*FileId);
  459. if(Status == (ARC_STATUS)(-1)) {
  460. //
  461. // This is a special status indicating that the file is not
  462. // to be processed for decompression. This typically happens
  463. // when the decompressor opens the file to read the compressed
  464. // data out of it.
  465. //
  466. Status = ESUCCESS;
  467. #if DBG
  468. BlFilesOpened++;
  469. #endif
  470. }
  471. return(Status);
  472. }
  473. }
  474. Status = (_BlOpen(DeviceId,OpenPath,OpenMode,FileId));
  475. #if DBG
  476. if (Status == ESUCCESS)
  477. BlFilesOpened++;
  478. #endif
  479. return Status;
  480. }
  481. ARC_STATUS
  482. BlRead (
  483. IN ULONG FileId,
  484. OUT PVOID Buffer,
  485. IN ULONG Length,
  486. OUT PULONG Count
  487. )
  488. /*++
  489. Routine Description:
  490. This function reads from a file or a device that is open.
  491. Arguments:
  492. FileId - Supplies the file table index.
  493. Buffer - Supplies a pointer to the buffer that receives the data
  494. read.
  495. Length - Supplies the number of bytes that are to be read.
  496. Count - Supplies a pointer to a variable that receives the number of
  497. bytes actually transfered.
  498. Return Value:
  499. If the specified file is open for read, then a read is attempted
  500. and the status of the operation is returned. Otherwise, return an
  501. unsuccessful status.
  502. --*/
  503. {
  504. //
  505. // If the file is open for read, then attempt to read from it. Otherwise
  506. // return an access error.
  507. //
  508. if ((BlFileTable[FileId].Flags.Open == 1) &&
  509. (BlFileTable[FileId].Flags.Read == 1)) {
  510. return (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
  511. Buffer,
  512. Length,
  513. Count);
  514. } else {
  515. return EACCES;
  516. }
  517. }
  518. ARC_STATUS
  519. BlReadAtOffset(
  520. IN ULONG FileId,
  521. IN ULONG Offset,
  522. IN ULONG Length,
  523. OUT PVOID Data
  524. )
  525. /*++
  526. Routine Description:
  527. This routine seeks to the proper place in FileId and extracts Length bytes of data into
  528. Data.
  529. Arguments:
  530. FileId - Supplies the file id where read operations are to be performed.
  531. Offset - The absolute byte offset to start reading at.
  532. Length - The number of bytes to read.
  533. Data - Buffer to hold the read results.
  534. --*/
  535. {
  536. ARC_STATUS Status;
  537. LARGE_INTEGER LargeOffset;
  538. ULONG Count;
  539. LargeOffset.HighPart = 0;
  540. LargeOffset.LowPart = Offset;
  541. Status = BlSeek(FileId, &LargeOffset, SeekAbsolute);
  542. if (Status != ESUCCESS) {
  543. return Status;
  544. }
  545. Status = BlRead(FileId, Data, Length, &Count);
  546. if ((Status == ESUCCESS) && (Count != Length)) {
  547. return EINVAL;
  548. }
  549. return Status;
  550. }
  551. ARC_STATUS
  552. BlGetReadStatus (
  553. IN ULONG FileId
  554. )
  555. /*++
  556. Routine Description:
  557. Arguments:
  558. Return Value:
  559. --*/
  560. {
  561. return ESUCCESS;
  562. }
  563. ARC_STATUS
  564. BlSeek (
  565. IN ULONG FileId,
  566. IN PLARGE_INTEGER Offset,
  567. IN SEEK_MODE SeekMode
  568. )
  569. /*++
  570. Routine Description:
  571. Arguments:
  572. Return Value:
  573. If the specified file is open, then a seek is attempted and
  574. the status of the operation is returned. Otherwise, return an
  575. unsuccessful status.
  576. --*/
  577. {
  578. //
  579. // If the file is open, then attempt to seek on it. Otherwise return an
  580. // access error.
  581. //
  582. if (BlFileTable[FileId].Flags.Open == 1) {
  583. return (BlFileTable[FileId].DeviceEntryTable->Seek)(FileId,
  584. Offset,
  585. SeekMode);
  586. } else {
  587. return EACCES;
  588. }
  589. }
  590. ARC_STATUS
  591. BlWrite (
  592. IN ULONG FileId,
  593. IN PVOID Buffer,
  594. IN ULONG Length,
  595. OUT PULONG Count
  596. )
  597. /*++
  598. Routine Description:
  599. Arguments:
  600. Return Value:
  601. --*/
  602. {
  603. //
  604. // If the file is open for write, then attempt to write to it. Otherwise
  605. // return an access error.
  606. //
  607. if ((BlFileTable[FileId].Flags.Open == 1) &&
  608. (BlFileTable[FileId].Flags.Write == 1)) {
  609. return (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
  610. Buffer,
  611. Length,
  612. Count);
  613. } else {
  614. return EACCES;
  615. }
  616. }
  617. ARC_STATUS
  618. BlGetFileInformation (
  619. IN ULONG FileId,
  620. IN PFILE_INFORMATION FileInformation
  621. )
  622. /*++
  623. Routine Description:
  624. Arguments:
  625. Return Value:
  626. --*/
  627. {
  628. //
  629. // If the file is open, then attempt to get file information. Otherwise
  630. // return an access error.
  631. //
  632. if (BlFileTable[FileId].Flags.Open == 1) {
  633. return (BlFileTable[FileId].DeviceEntryTable->GetFileInformation)(FileId,
  634. FileInformation);
  635. } else {
  636. return EACCES;
  637. }
  638. }
  639. ARC_STATUS
  640. BlSetFileInformation (
  641. IN ULONG FileId,
  642. IN ULONG AttributeFlags,
  643. IN ULONG AttributeMask
  644. )
  645. /*++
  646. Routine Description:
  647. Arguments:
  648. Return Value:
  649. --*/
  650. {
  651. //
  652. // If the file is open, then attempt to Set file information. Otherwise
  653. // return an access error.
  654. //
  655. if (BlFileTable[FileId].Flags.Open == 1) {
  656. return (BlFileTable[FileId].DeviceEntryTable->SetFileInformation)(FileId,
  657. AttributeFlags,
  658. AttributeMask);
  659. } else {
  660. return EACCES;
  661. }
  662. }
  663. ARC_STATUS
  664. BlRename(
  665. IN ULONG FileId,
  666. IN PCHAR NewName
  667. )
  668. /*++
  669. Routine Description:
  670. Rename an open file or directory.
  671. Arguments:
  672. FileId - supplies a handle to an open file or directory. The file
  673. need not be open for write access.
  674. NewName - New name to give the file or directory (filename part only).
  675. Return Value:
  676. Status indicating result of the operation.
  677. --*/
  678. {
  679. if(BlFileTable[FileId].Flags.Open == 1) {
  680. return(BlFileTable[FileId].DeviceEntryTable->Rename(FileId,
  681. NewName
  682. )
  683. );
  684. } else {
  685. return(EACCES);
  686. }
  687. }