fileio.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. fileio.c
  9. Abstract:
  10. This module implements support for file I/O in the setup program.
  11. Author:
  12. Evan Green 11-Apr-2014
  13. Environment:
  14. User
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <assert.h>
  20. #include <errno.h>
  21. #include <fcntl.h>
  22. #include <getopt.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/stat.h>
  27. #include <time.h>
  28. #include "setup.h"
  29. #include <minoca/lib/fat/fat.h>
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. #define SETUP_DIRECTORY_ENTRY_SIZE 300
  34. //
  35. // ------------------------------------------------------ Data Type Definitions
  36. //
  37. /*++
  38. Structure Description:
  39. This structure describes a file handle in the setup app.
  40. Members:
  41. Volume - Stores a pointer to the volume this file belongs to.
  42. Handle - Stores the handle returned from the layer below.
  43. Properties - Stores the file properties.
  44. SeekInformation - Stores the seek information for the file.
  45. CurrentOffset - Stores the current file offset.
  46. FatFile - Stores a pointer to the file systems internal context for the
  47. open file.
  48. IsDirty - Stores a boolean indicating if the file is dirty or not.
  49. --*/
  50. typedef struct _SETUP_FILE {
  51. PSETUP_VOLUME Volume;
  52. PVOID Handle;
  53. FILE_PROPERTIES Properties;
  54. FAT_SEEK_INFORMATION SeekInformation;
  55. ULONGLONG CurrentOffset;
  56. PVOID FatFile;
  57. ULONGLONG DirectoryFileId;
  58. BOOL IsDirty;
  59. } SETUP_FILE, *PSETUP_FILE;
  60. //
  61. // ----------------------------------------------- Internal Function Prototypes
  62. //
  63. INT
  64. SetupFatOpen (
  65. PSETUP_VOLUME Volume,
  66. PSETUP_FILE NewFile,
  67. PCSTR Path,
  68. INT Flags,
  69. INT CreatePermissions,
  70. BOOL Directory
  71. );
  72. PSTR
  73. SetupFatCopyPath (
  74. PCSTR InputPath
  75. );
  76. //
  77. // -------------------------------------------------------------------- Globals
  78. //
  79. //
  80. // ------------------------------------------------------------------ Functions
  81. //
  82. PVOID
  83. SetupVolumeOpen (
  84. PSETUP_CONTEXT Context,
  85. PSETUP_DESTINATION Destination,
  86. SETUP_VOLUME_FORMAT_CHOICE Format,
  87. BOOL CompatibilityMode
  88. )
  89. /*++
  90. Routine Description:
  91. This routine opens a handle to a given volume.
  92. Arguments:
  93. Context - Supplies a pointer to the application context.
  94. Destination - Supplies a pointer to the destination to open.
  95. Format - Supplies the disposition for formatting the volume.
  96. CompatibilityMode - Supplies a boolean indicating whether to run the
  97. file system in the most compatible way possible.
  98. Return Value:
  99. Returns a pointer to an opaque context on success.
  100. NULL on failure.
  101. --*/
  102. {
  103. BLOCK_DEVICE_PARAMETERS BlockParameters;
  104. ULONG MountFlags;
  105. INT Result;
  106. KSTATUS Status;
  107. PSETUP_VOLUME Volume;
  108. memset(&BlockParameters, 0, sizeof(BLOCK_DEVICE_PARAMETERS));
  109. Volume = malloc(sizeof(SETUP_VOLUME));
  110. if (Volume == NULL) {
  111. Result = ENOMEM;
  112. goto OpenVolumeEnd;
  113. }
  114. memset(Volume, 0, sizeof(SETUP_VOLUME));
  115. Volume->Context = Context;
  116. Volume->DestinationType = Destination->Type;
  117. //
  118. // If this is an image, disk, or partition, open the native interface.
  119. //
  120. if ((Destination->Type == SetupDestinationDisk) ||
  121. (Destination->Type == SetupDestinationPartition) ||
  122. (Destination->Type == SetupDestinationImage)) {
  123. if ((Destination->Type == SetupDestinationPartition) ||
  124. (Destination->Type == SetupDestinationDisk)) {
  125. Volume->BlockHandle = Context->Disk;
  126. assert((Context->Disk != NULL) &&
  127. (Context->CurrentPartitionSize != 0));
  128. } else {
  129. Volume->BlockHandle = SetupOpenDestination(Destination, O_RDWR, 0);
  130. }
  131. if (Volume->BlockHandle == NULL) {
  132. printf("Error: Failed to open: ");
  133. SetupPrintDestination(Destination);
  134. Result = errno;
  135. if (Result > 0) {
  136. printf(": %s\n", strerror(errno));
  137. } else {
  138. Result = -1;
  139. printf("\n");
  140. }
  141. goto OpenVolumeEnd;
  142. }
  143. //
  144. // Fill out the block device parameters.
  145. //
  146. BlockParameters.DeviceToken = Volume;
  147. BlockParameters.BlockSize = SETUP_BLOCK_SIZE;
  148. if ((Destination->Type == SetupDestinationPartition) ||
  149. (Destination->Type == SetupDestinationDisk)) {
  150. BlockParameters.BlockCount = Context->CurrentPartitionSize;
  151. } else {
  152. Result = SetupFstat(Volume->BlockHandle,
  153. &(BlockParameters.BlockCount),
  154. NULL,
  155. NULL);
  156. if (Result != 0) {
  157. goto OpenVolumeEnd;
  158. }
  159. BlockParameters.BlockCount /= SETUP_BLOCK_SIZE;
  160. }
  161. MountFlags = 0;
  162. if (CompatibilityMode != FALSE) {
  163. MountFlags |= FAT_MOUNT_FLAG_COMPATIBILITY_MODE;
  164. }
  165. //
  166. // Potentially try to mount the volume without formatting it.
  167. //
  168. Status = STATUS_NOT_STARTED;
  169. if (Format == SetupVolumeFormatIfIncompatible) {
  170. Status = FatMount(&BlockParameters,
  171. MountFlags,
  172. &(Volume->VolumeToken));
  173. }
  174. //
  175. // Format the volume if needed.
  176. //
  177. if ((Format == SetupVolumeFormatAlways) ||
  178. ((Format == SetupVolumeFormatIfIncompatible) &&
  179. (!KSUCCESS(Status)))) {
  180. Status = FatFormat(&BlockParameters, 0, 0);
  181. if (!KSUCCESS(Status)) {
  182. printf("Error: Failed to format ");
  183. SetupPrintDestination(Destination);
  184. printf(": %d\n", Status);
  185. Result = -1;
  186. goto OpenVolumeEnd;
  187. }
  188. }
  189. Status = FatMount(&BlockParameters, MountFlags, &(Volume->VolumeToken));
  190. if (!KSUCCESS(Status)) {
  191. printf("Error: Failed to mount ");
  192. SetupPrintDestination(Destination);
  193. printf(": %d\n", Status);
  194. Result = -1;
  195. goto OpenVolumeEnd;
  196. }
  197. //
  198. // This is a directory, just copy the prefix over.
  199. //
  200. } else {
  201. assert(Destination->Type == SetupDestinationDirectory);
  202. if (Destination->Path == NULL) {
  203. fprintf(stderr,
  204. "Error: Installations to a directory need a path-based "
  205. "destination.\n");
  206. Result = -1;
  207. goto OpenVolumeEnd;
  208. }
  209. Volume->PathPrefix = strdup(Destination->Path);
  210. if (Volume->PathPrefix == NULL) {
  211. Result = ENOMEM;
  212. goto OpenVolumeEnd;
  213. }
  214. }
  215. Result = 0;
  216. OpenVolumeEnd:
  217. if (Result != 0) {
  218. if (Volume != NULL) {
  219. SetupVolumeClose(Context, Volume);
  220. Volume = NULL;
  221. }
  222. }
  223. return Volume;
  224. }
  225. VOID
  226. SetupVolumeClose (
  227. PSETUP_CONTEXT Context,
  228. PVOID Handle
  229. )
  230. /*++
  231. Routine Description:
  232. This routine closes a volume.
  233. Arguments:
  234. Context - Supplies a pointer to the application context.
  235. Handle - Supplies a pointer to the open volume handle.
  236. Return Value:
  237. None.
  238. --*/
  239. {
  240. PSETUP_VOLUME Volume;
  241. Volume = Handle;
  242. if (Volume->VolumeToken != NULL) {
  243. FatUnmount(Volume->VolumeToken);
  244. }
  245. if ((Volume->BlockHandle != NULL) &&
  246. (Volume->BlockHandle != Context->Disk)) {
  247. SetupClose(Volume->BlockHandle);
  248. }
  249. if (Volume->PathPrefix != NULL) {
  250. free(Volume->PathPrefix);
  251. }
  252. free(Volume);
  253. return;
  254. }
  255. INT
  256. SetupFileReadLink (
  257. PVOID Handle,
  258. PCSTR Path,
  259. PSTR *LinkTarget,
  260. INT *LinkTargetSize
  261. )
  262. /*++
  263. Routine Description:
  264. This routine attempts to read a symbolic link.
  265. Arguments:
  266. Handle - Supplies the volume handle.
  267. Path - Supplies a pointer to the path to open.
  268. LinkTarget - Supplies a pointer where an allocated link target will be
  269. returned on success. The caller is responsible for freeing this memory.
  270. LinkTargetSize - Supplies a pointer where the size of the link target will
  271. be returned on success.
  272. Return Value:
  273. Returns the link size on success.
  274. -1 on failure.
  275. --*/
  276. {
  277. PVOID File;
  278. PSTR FinalPath;
  279. mode_t Mode;
  280. INT Result;
  281. ULONGLONG Size;
  282. PSETUP_VOLUME Volume;
  283. File = NULL;
  284. *LinkTarget = NULL;
  285. Volume = Handle;
  286. FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
  287. if (FinalPath == NULL) {
  288. Result = ENOMEM;
  289. goto FileReadLinkEnd;
  290. }
  291. Result = -1;
  292. //
  293. // If it's the native interface, append the path and send the request
  294. // down directly.
  295. //
  296. if (Volume->DestinationType == SetupDestinationDirectory) {
  297. Result = SetupOsReadLink(FinalPath, LinkTarget, LinkTargetSize);
  298. //
  299. // Route this through the file system code.
  300. //
  301. } else {
  302. File = SetupFileOpen(Handle, Path, O_RDONLY, 0);
  303. if (File == NULL) {
  304. goto FileReadLinkEnd;
  305. }
  306. Result = SetupFileFileStat(File, &Size, NULL, &Mode);
  307. if ((Result != 0) || (S_ISLNK(Mode) == 0)) {
  308. Result = -1;
  309. goto FileReadLinkEnd;
  310. }
  311. *LinkTarget = malloc(Size + 1);
  312. if (*LinkTarget == NULL) {
  313. Result = -1;
  314. goto FileReadLinkEnd;
  315. }
  316. Result = SetupFileRead(File, *LinkTarget, Size);
  317. if (Result != Size) {
  318. Result = -1;
  319. goto FileReadLinkEnd;
  320. }
  321. (*LinkTarget)[Size] = '\0';
  322. *LinkTargetSize = Size;
  323. Result = 0;
  324. }
  325. FileReadLinkEnd:
  326. if (Result != 0) {
  327. if (*LinkTarget != NULL) {
  328. free(*LinkTarget);
  329. *LinkTarget = NULL;
  330. }
  331. }
  332. if (File != NULL) {
  333. SetupFileClose(File);
  334. File = NULL;
  335. }
  336. if (FinalPath != NULL) {
  337. free(FinalPath);
  338. }
  339. return Result;
  340. }
  341. INT
  342. SetupFileSymlink (
  343. PVOID Handle,
  344. PCSTR Path,
  345. PSTR LinkTarget,
  346. INT LinkTargetSize
  347. )
  348. /*++
  349. Routine Description:
  350. This routine creates a symbolic link.
  351. Arguments:
  352. Handle - Supplies the volume handle.
  353. Path - Supplies a pointer to the path of the symbolic link to create.
  354. LinkTarget - Supplies a pointer to the target of the link.
  355. LinkTargetSize - Supplies a the size of the link target buffer in bytes.
  356. Return Value:
  357. Returns the link size on success.
  358. -1 on failure.
  359. --*/
  360. {
  361. PSETUP_FILE File;
  362. PSTR FinalPath;
  363. INT Result;
  364. PSETUP_VOLUME Volume;
  365. File = NULL;
  366. Volume = Handle;
  367. FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
  368. if (FinalPath == NULL) {
  369. Result = ENOMEM;
  370. goto FileSymlinkEnd;
  371. }
  372. Result = -1;
  373. //
  374. // If it's the native interface, append the path and send the request
  375. // down directly.
  376. //
  377. if (Volume->DestinationType == SetupDestinationDirectory) {
  378. Result = SetupOsSymlink(FinalPath, LinkTarget, LinkTargetSize);
  379. //
  380. // Route this through the file system code.
  381. //
  382. } else {
  383. File = SetupFileOpen(Handle,
  384. Path,
  385. O_WRONLY | O_CREAT | O_TRUNC,
  386. FILE_PERMISSION_ALL);
  387. if (File == NULL) {
  388. goto FileSymlinkEnd;
  389. }
  390. Result = SetupFileWrite(File, LinkTarget, LinkTargetSize);
  391. if (Result != LinkTargetSize) {
  392. Result = -1;
  393. goto FileSymlinkEnd;
  394. }
  395. File->Properties.Permissions |= FILE_PERMISSION_ALL;
  396. File->Properties.Type = IoObjectSymbolicLink;
  397. File->IsDirty = TRUE;
  398. Result = 0;
  399. }
  400. FileSymlinkEnd:
  401. if (File != NULL) {
  402. SetupFileClose(File);
  403. File = NULL;
  404. }
  405. if (FinalPath != NULL) {
  406. free(FinalPath);
  407. }
  408. return Result;
  409. }
  410. PVOID
  411. SetupFileOpen (
  412. PVOID Handle,
  413. PCSTR Path,
  414. INT Flags,
  415. INT CreatePermissions
  416. )
  417. /*++
  418. Routine Description:
  419. This routine opens a handle to a file in a volume.
  420. Arguments:
  421. Handle - Supplies the volume handle.
  422. Path - Supplies a pointer to the path to open.
  423. Flags - Supplies open flags. See O_* definitions.
  424. CreatePermissions - Supplies optional create permissions.
  425. Return Value:
  426. Returns a pointer to an opaque context on success.
  427. NULL on failure.
  428. --*/
  429. {
  430. PSETUP_DESTINATION Destination;
  431. PSETUP_FILE File;
  432. PSTR FinalPath;
  433. INT Result;
  434. PSETUP_VOLUME Volume;
  435. File = NULL;
  436. Volume = Handle;
  437. FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
  438. if (FinalPath == NULL) {
  439. Result = ENOMEM;
  440. goto OpenFileEnd;
  441. }
  442. File = malloc(sizeof(SETUP_FILE));
  443. if (File == NULL) {
  444. Result = ENOMEM;
  445. goto OpenFileEnd;
  446. }
  447. memset(File, 0, sizeof(SETUP_FILE));
  448. File->Volume = Volume;
  449. //
  450. // If it's the native interface, append the path and send the request
  451. // down directly.
  452. //
  453. if (Volume->DestinationType == SetupDestinationDirectory) {
  454. Destination = SetupCreateDestination(SetupDestinationFile,
  455. FinalPath,
  456. 0);
  457. if (Destination == NULL) {
  458. Result = ENOMEM;
  459. goto OpenFileEnd;
  460. }
  461. File->Handle = SetupOpenDestination(Destination,
  462. Flags,
  463. CreatePermissions);
  464. SetupDestroyDestination(Destination);
  465. if (File->Handle == NULL) {
  466. Result = errno;
  467. goto OpenFileEnd;
  468. }
  469. //
  470. // Route this through the file system code.
  471. //
  472. } else {
  473. assert((Volume->DestinationType == SetupDestinationDisk) ||
  474. (Volume->DestinationType == SetupDestinationPartition) ||
  475. (Volume->DestinationType == SetupDestinationImage));
  476. Result = SetupFatOpen(Volume,
  477. File,
  478. FinalPath,
  479. Flags,
  480. CreatePermissions,
  481. FALSE);
  482. if (Result != 0) {
  483. goto OpenFileEnd;
  484. }
  485. }
  486. Result = 0;
  487. OpenFileEnd:
  488. if (Result != 0) {
  489. if (File != NULL) {
  490. SetupFileClose(File);
  491. File = NULL;
  492. }
  493. }
  494. if (FinalPath != NULL) {
  495. free(FinalPath);
  496. }
  497. return File;
  498. }
  499. VOID
  500. SetupFileClose (
  501. PVOID Handle
  502. )
  503. /*++
  504. Routine Description:
  505. This routine closes a file.
  506. Arguments:
  507. Handle - Supplies the handle to close.
  508. Return Value:
  509. None.
  510. --*/
  511. {
  512. PSETUP_FILE File;
  513. File = Handle;
  514. if (File->FatFile != NULL) {
  515. FatCloseFile(File->FatFile);
  516. }
  517. if (File->IsDirty != FALSE) {
  518. FatWriteFileProperties(File->Volume->VolumeToken,
  519. &(File->Properties),
  520. 0);
  521. }
  522. if (File->Handle != NULL) {
  523. SetupClose(File->Handle);
  524. }
  525. File->Volume->OpenFiles -= 1;
  526. free(File);
  527. return;
  528. }
  529. ssize_t
  530. SetupFileRead (
  531. PVOID Handle,
  532. void *Buffer,
  533. size_t ByteCount
  534. )
  535. /*++
  536. Routine Description:
  537. This routine reads from a file.
  538. Arguments:
  539. Handle - Supplies the handle.
  540. Buffer - Supplies a pointer where the read bytes will be returned.
  541. ByteCount - Supplies the number of bytes to read.
  542. Return Value:
  543. Returns the number of bytes read on success.
  544. --*/
  545. {
  546. UINTN BytesComplete;
  547. PSETUP_FILE File;
  548. PFAT_IO_BUFFER IoBuffer;
  549. KSTATUS Status;
  550. File = Handle;
  551. //
  552. // Pass directly to the native OS interface if the destination is native.
  553. //
  554. if (File->Volume->DestinationType == SetupDestinationDirectory) {
  555. return SetupRead(File->Handle, Buffer, ByteCount);
  556. }
  557. assert((File->Volume->DestinationType == SetupDestinationDisk) ||
  558. (File->Volume->DestinationType == SetupDestinationPartition) ||
  559. (File->Volume->DestinationType == SetupDestinationImage));
  560. if ((File->Properties.Type != IoObjectRegularFile) &&
  561. (File->Properties.Type != IoObjectSymbolicLink)) {
  562. return -1;
  563. }
  564. IoBuffer = FatCreateIoBuffer(Buffer, ByteCount);
  565. if (IoBuffer == NULL) {
  566. return -1;
  567. }
  568. BytesComplete = 0;
  569. Status = FatReadFile(File->FatFile,
  570. &(File->SeekInformation),
  571. IoBuffer,
  572. ByteCount,
  573. 0,
  574. NULL,
  575. &BytesComplete);
  576. ASSERT(BytesComplete <= ByteCount);
  577. File->CurrentOffset += BytesComplete;
  578. if ((!KSUCCESS(Status)) && (Status != STATUS_END_OF_FILE)) {
  579. fprintf(stderr, "FatReadFile Error: %d\n", Status);
  580. BytesComplete = 0;
  581. }
  582. if (IoBuffer != NULL) {
  583. FatFreeIoBuffer(IoBuffer);
  584. }
  585. return (ssize_t)BytesComplete;
  586. }
  587. ssize_t
  588. SetupFileWrite (
  589. PVOID Handle,
  590. void *Buffer,
  591. size_t ByteCount
  592. )
  593. /*++
  594. Routine Description:
  595. This routine writes data to an open file handle.
  596. Arguments:
  597. Handle - Supplies the handle.
  598. Buffer - Supplies a pointer to the bytes to write.
  599. ByteCount - Supplies the number of bytes to read.
  600. Return Value:
  601. Returns the number of bytes written.
  602. -1 on failure.
  603. --*/
  604. {
  605. UINTN BytesComplete;
  606. PSETUP_FILE File;
  607. ULONGLONG FileSize;
  608. PFAT_IO_BUFFER IoBuffer;
  609. KSTATUS Status;
  610. File = Handle;
  611. //
  612. // Pass directly to the native OS interface if the destination is native.
  613. //
  614. if (File->Volume->DestinationType == SetupDestinationDirectory) {
  615. return SetupWrite(File->Handle, Buffer, ByteCount);
  616. }
  617. assert((File->Volume->DestinationType == SetupDestinationDisk) ||
  618. (File->Volume->DestinationType == SetupDestinationPartition) ||
  619. (File->Volume->DestinationType == SetupDestinationImage));
  620. if ((File->Properties.Type != IoObjectRegularFile) &&
  621. (File->Properties.Type != IoObjectSymbolicLink)) {
  622. errno = EISDIR;
  623. return -1;
  624. }
  625. IoBuffer = FatCreateIoBuffer(Buffer, ByteCount);
  626. if (IoBuffer == NULL) {
  627. return -1;
  628. }
  629. BytesComplete = 0;
  630. FileSize = File->Properties.Size;
  631. Status = FatWriteFile(File->FatFile,
  632. &(File->SeekInformation),
  633. IoBuffer,
  634. ByteCount,
  635. 0,
  636. NULL,
  637. &BytesComplete);
  638. ASSERT(BytesComplete <= ByteCount);
  639. //
  640. // Advance the current position. Mark the file dirty and update the size
  641. // if the write made the file bigger.
  642. //
  643. File->CurrentOffset += BytesComplete;
  644. if (File->CurrentOffset > FileSize) {
  645. FileSize = File->CurrentOffset;
  646. File->Properties.Size = FileSize;
  647. File->IsDirty = TRUE;
  648. }
  649. if (!KSUCCESS(Status)) {
  650. fprintf(stderr, "FatWriteFile Error: %d\n", Status);
  651. if (Status == STATUS_VOLUME_FULL) {
  652. errno = ENOSPC;
  653. }
  654. BytesComplete = 0;
  655. }
  656. if (IoBuffer != NULL) {
  657. FatFreeIoBuffer(IoBuffer);
  658. }
  659. return (ssize_t)BytesComplete;
  660. }
  661. LONGLONG
  662. SetupFileSeek (
  663. PVOID Handle,
  664. LONGLONG Offset
  665. )
  666. /*++
  667. Routine Description:
  668. This routine seeks in the given file.
  669. Arguments:
  670. Handle - Supplies the handle.
  671. Offset - Supplies the new offset to set.
  672. Return Value:
  673. Returns the resulting file offset after the operation.
  674. -1 on failure, and errno will contain more information. The file offset
  675. will remain unchanged.
  676. --*/
  677. {
  678. PSETUP_FILE File;
  679. KSTATUS Status;
  680. File = Handle;
  681. //
  682. // Pass directly to the native OS interface if the destination is native.
  683. //
  684. if (File->Volume->DestinationType == SetupDestinationDirectory) {
  685. return SetupSeek(File->Handle, Offset);
  686. }
  687. assert((File->Volume->DestinationType == SetupDestinationDisk) ||
  688. (File->Volume->DestinationType == SetupDestinationPartition) ||
  689. (File->Volume->DestinationType == SetupDestinationImage));
  690. if (File->Properties.Type != IoObjectRegularFile) {
  691. return -1;
  692. }
  693. Status = FatFileSeek(File->FatFile,
  694. NULL,
  695. 0,
  696. SeekCommandFromBeginning,
  697. Offset,
  698. &(File->SeekInformation));
  699. if (!KSUCCESS(Status)) {
  700. fprintf(stderr, "FatFileSeek Error: %d\n", Status);
  701. Offset = -1;
  702. } else {
  703. File->CurrentOffset = Offset;
  704. }
  705. return Offset;
  706. }
  707. INT
  708. SetupFileFileStat (
  709. PVOID Handle,
  710. PULONGLONG FileSize,
  711. time_t *ModificationDate,
  712. mode_t *Mode
  713. )
  714. /*++
  715. Routine Description:
  716. This routine gets details for the given open file.
  717. Arguments:
  718. Handle - Supplies the handle.
  719. FileSize - Supplies an optional pointer where the file size will be
  720. returned on success.
  721. ModificationDate - Supplies an optional pointer where the file's
  722. modification date will be returned on success.
  723. Mode - Supplies an optional pointer where the file's mode information will
  724. be returned on success.
  725. Return Value:
  726. 0 on success.
  727. Non-zero on failure.
  728. --*/
  729. {
  730. PSETUP_FILE File;
  731. File = Handle;
  732. if (File->Volume->DestinationType == SetupDestinationDirectory) {
  733. return SetupFstat(File->Handle, FileSize, ModificationDate, Mode);
  734. }
  735. if (FileSize != NULL) {
  736. *FileSize = File->Properties.Size;
  737. }
  738. if (ModificationDate != NULL) {
  739. *ModificationDate = File->Properties.ModifiedTime.Seconds +
  740. SYSTEM_TIME_TO_EPOCH_DELTA;
  741. }
  742. if (Mode != NULL) {
  743. *Mode = 0;
  744. if (File->Properties.Type == IoObjectRegularDirectory) {
  745. *Mode |= S_IFDIR;
  746. } else if (File->Properties.Type == IoObjectSymbolicLink) {
  747. *Mode |= S_IFLNK;
  748. } else {
  749. *Mode |= S_IFREG;
  750. }
  751. *Mode |= File->Properties.Permissions;
  752. }
  753. return 0;
  754. }
  755. INT
  756. SetupFileFileTruncate (
  757. PVOID Handle,
  758. ULONGLONG NewSize
  759. )
  760. /*++
  761. Routine Description:
  762. This routine sets the file size of the given file.
  763. Arguments:
  764. Handle - Supplies the handle.
  765. NewSize - Supplies the new file size.
  766. Return Value:
  767. 0 on success.
  768. Non-zero on failure.
  769. --*/
  770. {
  771. ULONGLONG CurrentSize;
  772. PSETUP_FILE File;
  773. KSTATUS Status;
  774. File = Handle;
  775. if (File->Volume->DestinationType == SetupDestinationDirectory) {
  776. return SetupFtruncate(File->Handle, NewSize);
  777. }
  778. CurrentSize = File->Properties.Size;
  779. if (CurrentSize == NewSize) {
  780. return 0;
  781. } else if (NewSize < CurrentSize) {
  782. Status = FatDeleteFileBlocks(File->Volume->VolumeToken,
  783. File->Handle,
  784. File->Properties.FileId,
  785. NewSize,
  786. TRUE);
  787. } else {
  788. Status = FatAllocateFileClusters(File->Volume->VolumeToken,
  789. File->Properties.FileId,
  790. NewSize);
  791. }
  792. if (!KSUCCESS(Status)) {
  793. fprintf(stderr, "FatTruncate Error: %d\n", Status);
  794. return -1;
  795. }
  796. File->Properties.Size = NewSize;
  797. File->IsDirty = TRUE;
  798. return 0;
  799. }
  800. INT
  801. SetupFileEnumerateDirectory (
  802. PVOID VolumeHandle,
  803. PCSTR DirectoryPath,
  804. PSTR *Enumeration
  805. )
  806. /*++
  807. Routine Description:
  808. This routine enumerates the contents of a given directory.
  809. Arguments:
  810. VolumeHandle - Supplies the open volume handle.
  811. DirectoryPath - Supplies a pointer to a string containing the path to the
  812. directory to enumerate.
  813. Enumeration - Supplies a pointer where a pointer to a sequence of
  814. strings will be returned containing the files in the directory. The
  815. sequence will be terminated by an empty string. The caller is
  816. responsible for freeing this memory when done.
  817. Return Value:
  818. 0 on success.
  819. Non-zero on failure.
  820. --*/
  821. {
  822. PSTR Array;
  823. size_t ArrayCapacity;
  824. UINTN BytesRead;
  825. PDIRECTORY_ENTRY DirectoryEntry;
  826. ULONG ElementsRead;
  827. ULONGLONG EntryOffset;
  828. SETUP_FILE File;
  829. PSTR FinalPath;
  830. PFAT_IO_BUFFER IoBuffer;
  831. PSTR Name;
  832. size_t NameSize;
  833. PVOID NewBuffer;
  834. size_t NewCapacity;
  835. INT Result;
  836. KSTATUS Status;
  837. size_t UsedSize;
  838. PSETUP_VOLUME Volume;
  839. DirectoryEntry = NULL;
  840. IoBuffer = NULL;
  841. Name = NULL;
  842. Volume = VolumeHandle;
  843. memset(&File, 0, sizeof(SETUP_FILE));
  844. File.Volume = VolumeHandle;
  845. if (Volume->DestinationType == SetupDestinationDirectory) {
  846. FinalPath = SetupAppendPaths(Volume->PathPrefix, DirectoryPath);
  847. if (FinalPath == NULL) {
  848. Result = ENOMEM;
  849. goto EnumerateFileDirectoryEnd;
  850. }
  851. Result = SetupEnumerateDirectory(File.Volume,
  852. FinalPath,
  853. Enumeration);
  854. free(FinalPath);
  855. return Result;
  856. }
  857. Result = SetupFatOpen(VolumeHandle,
  858. &File,
  859. DirectoryPath,
  860. 0,
  861. 0,
  862. TRUE);
  863. if (Result != 0) {
  864. return Result;
  865. }
  866. Array = NULL;
  867. ArrayCapacity = 0;
  868. UsedSize = 0;
  869. EntryOffset = DIRECTORY_CONTENTS_OFFSET;
  870. DirectoryEntry = malloc(SETUP_DIRECTORY_ENTRY_SIZE);
  871. if (DirectoryEntry == NULL) {
  872. goto EnumerateFileDirectoryEnd;
  873. }
  874. IoBuffer = FatCreateIoBuffer(DirectoryEntry, SETUP_DIRECTORY_ENTRY_SIZE);
  875. if (IoBuffer == NULL) {
  876. goto EnumerateFileDirectoryEnd;
  877. }
  878. //
  879. // Loop reading directory entries.
  880. //
  881. while (TRUE) {
  882. BytesRead = 0;
  883. Status = FatEnumerateDirectory(File.FatFile,
  884. EntryOffset,
  885. IoBuffer,
  886. SETUP_DIRECTORY_ENTRY_SIZE,
  887. TRUE,
  888. FALSE,
  889. NULL,
  890. &BytesRead,
  891. &ElementsRead);
  892. if ((!KSUCCESS(Status)) && (Status != STATUS_END_OF_FILE)) {
  893. fprintf(stderr, "FatEnumerateDirectory Error: %d\n", Status);
  894. Result = -1;
  895. goto EnumerateFileDirectoryEnd;
  896. }
  897. NameSize = 1;
  898. if (Status != STATUS_END_OF_FILE) {
  899. Name = (PVOID)(DirectoryEntry + 1);
  900. NameSize = strlen(Name) + 1;
  901. }
  902. //
  903. // Reallocate the array if needed.
  904. //
  905. if (ArrayCapacity - UsedSize < NameSize) {
  906. NewCapacity = ArrayCapacity;
  907. if (NewCapacity == 0) {
  908. NewCapacity = 2;
  909. }
  910. while (NewCapacity - UsedSize < NameSize) {
  911. NewCapacity *= 2;
  912. }
  913. NewBuffer = realloc(Array, NewCapacity);
  914. if (NewBuffer == NULL) {
  915. Result = ENOMEM;
  916. goto EnumerateFileDirectoryEnd;
  917. }
  918. Array = NewBuffer;
  919. ArrayCapacity = NewCapacity;
  920. }
  921. //
  922. // Copy the entry (or an empty file if this is the end).
  923. //
  924. if (Status == STATUS_END_OF_FILE) {
  925. strcpy(Array + UsedSize, "");
  926. UsedSize += 1;
  927. Status = STATUS_SUCCESS;
  928. break;
  929. } else {
  930. strcpy(Array + UsedSize, Name);
  931. UsedSize += NameSize;
  932. }
  933. assert(ElementsRead != 0);
  934. EntryOffset += ElementsRead;
  935. }
  936. Result = 0;
  937. EnumerateFileDirectoryEnd:
  938. if (DirectoryEntry != NULL) {
  939. free(DirectoryEntry);
  940. }
  941. if (IoBuffer != NULL) {
  942. FatFreeIoBuffer(IoBuffer);
  943. }
  944. if (File.FatFile != NULL) {
  945. FatCloseFile(File.FatFile);
  946. }
  947. if (Result != 0) {
  948. if (Array != NULL) {
  949. free(Array);
  950. Array = NULL;
  951. }
  952. }
  953. *Enumeration = Array;
  954. return Result;
  955. }
  956. INT
  957. SetupFileCreateDirectory (
  958. PVOID VolumeHandle,
  959. PCSTR Path,
  960. mode_t Permissions
  961. )
  962. /*++
  963. Routine Description:
  964. This routine creates a new directory.
  965. Arguments:
  966. VolumeHandle - Supplies a pointer to the volume handle.
  967. Path - Supplies the path string of the directory to create.
  968. Permissions - Supplies the permission bits to create the file with.
  969. Return Value:
  970. 0 on success.
  971. Non-zero on failure.
  972. --*/
  973. {
  974. SETUP_FILE File;
  975. PSTR FinalPath;
  976. INT Result;
  977. PSETUP_VOLUME Volume;
  978. Volume = VolumeHandle;
  979. if (Volume->DestinationType == SetupDestinationDirectory) {
  980. FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
  981. if (FinalPath == NULL) {
  982. Result = ENOMEM;
  983. return Result;
  984. }
  985. Result = SetupOsCreateDirectory(FinalPath, Permissions);
  986. if (Result == EEXIST) {
  987. Result = 0;
  988. }
  989. free(FinalPath);
  990. return Result;
  991. }
  992. memset(&File, 0, sizeof(SETUP_FILE));
  993. File.Volume = VolumeHandle;
  994. Result = SetupFatOpen(VolumeHandle,
  995. &File,
  996. Path,
  997. O_CREAT,
  998. Permissions,
  999. TRUE);
  1000. if (Result != 0) {
  1001. return Result;
  1002. }
  1003. if (File.FatFile != NULL) {
  1004. FatCloseFile(File.FatFile);
  1005. }
  1006. return Result;
  1007. }
  1008. INT
  1009. SetupFileSetAttributes (
  1010. PVOID VolumeHandle,
  1011. PCSTR Path,
  1012. time_t ModificationDate,
  1013. mode_t Permissions
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. This routine sets attributes on a given path.
  1018. Arguments:
  1019. VolumeHandle - Supplies a pointer to the volume handle.
  1020. Path - Supplies the path string of the file to modify.
  1021. ModificationDate - Supplies the new modification date to set.
  1022. Permissions - Supplies the new permissions to set.
  1023. Return Value:
  1024. 0 on success.
  1025. Non-zero on failure.
  1026. --*/
  1027. {
  1028. SETUP_FILE File;
  1029. PSTR FinalPath;
  1030. BOOL IsDirectory;
  1031. INT Result;
  1032. PSETUP_VOLUME Volume;
  1033. Volume = VolumeHandle;
  1034. if (Volume->DestinationType == SetupDestinationDirectory) {
  1035. FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
  1036. if (FinalPath == NULL) {
  1037. return ENOMEM;
  1038. }
  1039. Result = SetupOsSetAttributes(FinalPath, ModificationDate, Permissions);
  1040. free(FinalPath);
  1041. return Result;
  1042. }
  1043. memset(&File, 0, sizeof(SETUP_FILE));
  1044. File.Volume = VolumeHandle;
  1045. IsDirectory = FALSE;
  1046. if (S_ISDIR(Permissions) != 0) {
  1047. IsDirectory = TRUE;
  1048. }
  1049. Result = SetupFatOpen(VolumeHandle,
  1050. &File,
  1051. Path,
  1052. 0,
  1053. 0,
  1054. IsDirectory);
  1055. if (Result != 0) {
  1056. return Result;
  1057. }
  1058. File.Properties.AccessTime.Seconds =
  1059. time(NULL) - SYSTEM_TIME_TO_EPOCH_DELTA;
  1060. File.Properties.AccessTime.Nanoseconds = 0;
  1061. File.Properties.ModifiedTime.Seconds = ModificationDate -
  1062. SYSTEM_TIME_TO_EPOCH_DELTA;
  1063. File.Properties.ModifiedTime.Nanoseconds = 0;
  1064. File.Properties.Permissions = Permissions & FILE_PERMISSION_MASK;
  1065. if (S_ISDIR(Permissions)) {
  1066. File.Properties.Type = IoObjectRegularDirectory;
  1067. } else if (S_ISLNK(Permissions)) {
  1068. File.Properties.Type = IoObjectSymbolicLink;
  1069. } else {
  1070. File.Properties.Type = IoObjectRegularFile;
  1071. }
  1072. FatCloseFile(File.FatFile);
  1073. FatWriteFileProperties(Volume->VolumeToken, &(File.Properties), 0);
  1074. return 0;
  1075. }
  1076. VOID
  1077. SetupFileDetermineExecuteBit (
  1078. PVOID Handle,
  1079. PCSTR Path,
  1080. mode_t *Mode
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. This routine determines whether the open file is executable.
  1085. Arguments:
  1086. Handle - Supplies the open file handle.
  1087. Path - Supplies the path the file was opened from (sometimes the file name
  1088. is used as a hint).
  1089. Mode - Supplies a pointer to the current mode bits. This routine may add
  1090. the executable bit to user/group/other if it determines this file is
  1091. executable.
  1092. Return Value:
  1093. None.
  1094. --*/
  1095. {
  1096. PSETUP_FILE File;
  1097. File = Handle;
  1098. //
  1099. // Pass directly to the native OS interface if the destination is native.
  1100. //
  1101. if (File->Volume->DestinationType == SetupDestinationDirectory) {
  1102. return SetupDetermineExecuteBit(File->Handle, Path, Mode);
  1103. }
  1104. assert((File->Volume->DestinationType == SetupDestinationDisk) ||
  1105. (File->Volume->DestinationType == SetupDestinationPartition) ||
  1106. (File->Volume->DestinationType == SetupDestinationImage));
  1107. return;
  1108. }
  1109. //
  1110. // --------------------------------------------------------- Internal Functions
  1111. //
  1112. INT
  1113. SetupFatOpen (
  1114. PSETUP_VOLUME Volume,
  1115. PSETUP_FILE NewFile,
  1116. PCSTR Path,
  1117. INT Flags,
  1118. INT CreatePermissions,
  1119. BOOL Directory
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. This routine opens a file in a FAT image.
  1124. Arguments:
  1125. Volume - Supplies a pointer to the volume.
  1126. NewFile - Supplies a pointer to the new file being opened.
  1127. Path - Supplies a pointer to the path to open.
  1128. Flags - Supplies open flags. See O_* definitions.
  1129. CreatePermissions - Supplies optional create permissions.
  1130. Directory - Supplies a boolean indicating if this is a directory open or
  1131. file open.
  1132. Return Value:
  1133. 0 on success.
  1134. Non-zero on failure.
  1135. --*/
  1136. {
  1137. PSTR CurrentPath;
  1138. size_t CurrentPathLength;
  1139. ULONG DesiredAccess;
  1140. FILE_ID DirectoryFileId;
  1141. ULONG FatOpenFlags;
  1142. ULONGLONG NewDirectorySize;
  1143. FILE_PROPERTIES NewProperties;
  1144. PSTR OpenedFileName;
  1145. size_t OpenedFileNameLength;
  1146. PSTR PathCopy;
  1147. FILE_PROPERTIES Properties;
  1148. KSTATUS Status;
  1149. DirectoryFileId = 0;
  1150. PathCopy = NULL;
  1151. //
  1152. // Start at the root.
  1153. //
  1154. Status = FatLookup(Volume->VolumeToken, TRUE, 0, NULL, 0, &Properties);
  1155. if (!KSUCCESS(Status)) {
  1156. goto FatOpenEnd;
  1157. }
  1158. PathCopy = SetupFatCopyPath(Path);
  1159. if (PathCopy == NULL) {
  1160. Status = STATUS_INSUFFICIENT_RESOURCES;
  1161. goto FatOpenEnd;
  1162. }
  1163. if (*PathCopy == '\0') {
  1164. Status = STATUS_NOT_FOUND;
  1165. goto FatOpenEnd;
  1166. }
  1167. //
  1168. // Loop opening the next component in the path.
  1169. //
  1170. CurrentPath = PathCopy;
  1171. CurrentPathLength = strlen(CurrentPath);
  1172. Status = STATUS_SUCCESS;
  1173. while (TRUE) {
  1174. if (CurrentPathLength == 0) {
  1175. break;
  1176. }
  1177. DirectoryFileId = Properties.FileId;
  1178. OpenedFileName = CurrentPath;
  1179. OpenedFileNameLength = CurrentPathLength;
  1180. Status = FatLookup(Volume->VolumeToken,
  1181. FALSE,
  1182. Properties.FileId,
  1183. CurrentPath,
  1184. CurrentPathLength + 1,
  1185. &Properties);
  1186. //
  1187. // If the file was not found, stop.
  1188. //
  1189. if ((Status == STATUS_NO_SUCH_FILE) ||
  1190. (Status == STATUS_NOT_FOUND) ||
  1191. (Status == STATUS_PATH_NOT_FOUND)) {
  1192. Status = STATUS_NOT_FOUND;
  1193. break;
  1194. //
  1195. // If some wackier error occured, fail the whole function.
  1196. //
  1197. } else if (!KSUCCESS(Status)) {
  1198. goto FatOpenEnd;
  1199. }
  1200. //
  1201. // This file was found, move to the next path component.
  1202. //
  1203. CurrentPath += CurrentPathLength + 1;
  1204. CurrentPathLength = strlen(CurrentPath);
  1205. //
  1206. // If the file was not a directory, nothing more can be looked up
  1207. // underneath this, so stop.
  1208. //
  1209. if (Properties.Type != IoObjectRegularDirectory) {
  1210. break;
  1211. }
  1212. }
  1213. ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_NOT_FOUND));
  1214. //
  1215. // Okay, either the path ended, the file was not found, or the file was
  1216. // not a directory. If the file was found, but an exclusive open was
  1217. // requested, fail.
  1218. //
  1219. if (Status == STATUS_SUCCESS) {
  1220. if ((CurrentPathLength == 0) &&
  1221. ((Flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
  1222. Status = STATUS_FILE_EXISTS;
  1223. goto FatOpenEnd;
  1224. }
  1225. //
  1226. // If the file was not found, maybe create it.
  1227. //
  1228. } else if (Status == STATUS_NOT_FOUND) {
  1229. //
  1230. // If the file doesn't exist and the caller doesn't want to create it,
  1231. // then return not found.
  1232. //
  1233. if ((Flags & O_CREAT) == 0) {
  1234. goto FatOpenEnd;
  1235. }
  1236. //
  1237. // Fail if the volume is read-only.
  1238. //
  1239. if (Volume->DestinationType == SetupDestinationImage) {
  1240. Status = STATUS_ACCESS_DENIED;
  1241. goto FatOpenEnd;
  1242. }
  1243. //
  1244. // The caller wants to create a file or directory. If the last
  1245. // successful lookup wasn't a directory, fail.
  1246. //
  1247. if (Properties.Type != IoObjectRegularDirectory) {
  1248. goto FatOpenEnd;
  1249. }
  1250. //
  1251. // If this isn't the last component, also fail.
  1252. //
  1253. if (CurrentPath[CurrentPathLength + 1] != '\0') {
  1254. goto FatOpenEnd;
  1255. }
  1256. //
  1257. // Create the new file or directory.
  1258. //
  1259. memcpy(&NewProperties, &Properties, sizeof(FILE_PROPERTIES));
  1260. NewProperties.Type = IoObjectRegularFile;
  1261. if (Directory != FALSE) {
  1262. NewProperties.Type = IoObjectRegularDirectory;
  1263. }
  1264. NewProperties.Permissions = CreatePermissions;
  1265. NewProperties.FileId = 0;
  1266. NewProperties.Size = 0;
  1267. FatGetCurrentSystemTime(&(NewProperties.StatusChangeTime));
  1268. OpenedFileName = CurrentPath;
  1269. OpenedFileNameLength = CurrentPathLength;
  1270. Status = FatCreate(Volume->VolumeToken,
  1271. Properties.FileId,
  1272. OpenedFileName,
  1273. OpenedFileNameLength + 1,
  1274. &NewDirectorySize,
  1275. &NewProperties);
  1276. if (!KSUCCESS(Status)) {
  1277. goto FatOpenEnd;
  1278. }
  1279. //
  1280. // Update the directory properties, as that new file may have made the
  1281. // directory bigger.
  1282. //
  1283. Properties.Size = NewDirectorySize;
  1284. Status = FatWriteFileProperties(Volume->VolumeToken, &Properties, 0);
  1285. if (!KSUCCESS(Status)) {
  1286. goto FatOpenEnd;
  1287. }
  1288. //
  1289. // Make it look like this new file was successfully looked up by the
  1290. // above loop.
  1291. //
  1292. CurrentPathLength = 0;
  1293. memcpy(&Properties, &NewProperties, sizeof(FILE_PROPERTIES));
  1294. }
  1295. //
  1296. // If there are more components to the path, then this lookup failed.
  1297. //
  1298. if (CurrentPathLength != 0) {
  1299. Status = STATUS_PATH_NOT_FOUND;
  1300. goto FatOpenEnd;
  1301. }
  1302. //
  1303. // If the file is a symbolic link, don't open it if the caller specified
  1304. // the "no follow" flag.
  1305. //
  1306. if ((Properties.Type == IoObjectSymbolicLink) &&
  1307. ((Flags & O_NOFOLLOW) != 0)) {
  1308. Status = STATUS_UNEXPECTED_TYPE;
  1309. goto FatOpenEnd;
  1310. }
  1311. memcpy(&(NewFile->Properties), &Properties, sizeof(FILE_PROPERTIES));
  1312. memset(&(NewFile->SeekInformation), 0, sizeof(FAT_SEEK_INFORMATION));
  1313. NewFile->CurrentOffset = 0;
  1314. NewFile->FatFile = NULL;
  1315. NewFile->DirectoryFileId = DirectoryFileId;
  1316. DesiredAccess = 0;
  1317. switch (Flags & O_ACCMODE) {
  1318. case O_RDONLY:
  1319. DesiredAccess = IO_ACCESS_READ;
  1320. break;
  1321. case O_WRONLY:
  1322. DesiredAccess = IO_ACCESS_WRITE;
  1323. break;
  1324. case O_RDWR:
  1325. DesiredAccess = IO_ACCESS_READ | IO_ACCESS_WRITE;
  1326. break;
  1327. }
  1328. //
  1329. // Truncate the file if desired.
  1330. //
  1331. if ((Flags & O_TRUNC) != 0) {
  1332. assert(Directory == FALSE);
  1333. Status = FatDeleteFileBlocks(Volume->VolumeToken,
  1334. NULL,
  1335. Properties.FileId,
  1336. 0,
  1337. TRUE);
  1338. if (!KSUCCESS(Status)) {
  1339. goto FatOpenEnd;
  1340. }
  1341. NewFile->Properties.Size = 0;
  1342. }
  1343. FatOpenFlags = 0;
  1344. if (Directory != FALSE) {
  1345. FatOpenFlags |= OPEN_FLAG_DIRECTORY;
  1346. }
  1347. Status = FatOpenFileId(Volume->VolumeToken,
  1348. Properties.FileId,
  1349. DesiredAccess,
  1350. FatOpenFlags,
  1351. &(NewFile->FatFile));
  1352. if (!KSUCCESS(Status)) {
  1353. goto FatOpenEnd;
  1354. }
  1355. Volume->OpenFiles += 1;
  1356. Status = STATUS_SUCCESS;
  1357. FatOpenEnd:
  1358. if (PathCopy != NULL) {
  1359. free(PathCopy);
  1360. }
  1361. if (!KSUCCESS(Status)) {
  1362. if ((Status == STATUS_NOT_FOUND) || (Status == STATUS_PATH_NOT_FOUND)) {
  1363. errno = ENOENT;
  1364. } else if (Status == STATUS_VOLUME_FULL) {
  1365. errno = ENOSPC;
  1366. }
  1367. if ((Status != STATUS_NOT_FOUND) &&
  1368. (Status != STATUS_UNEXPECTED_TYPE)) {
  1369. fprintf(stderr, "FatOpenFile Error %s: %d\n", Path, Status);
  1370. errno = EINVAL;
  1371. }
  1372. return -1;
  1373. }
  1374. return 0;
  1375. }
  1376. PSTR
  1377. SetupFatCopyPath (
  1378. PCSTR InputPath
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. This routine creates a copy of the given path, separating slashes with
  1383. terminators along the way.
  1384. Arguments:
  1385. InputPath - Supplies a pointer to the input path.
  1386. Return Value:
  1387. Returns a pointer to the separated path, terminated with an additional
  1388. NULL terminator.
  1389. NULL on allocation failure.
  1390. --*/
  1391. {
  1392. PCSTR CurrentInput;
  1393. PSTR CurrentOutput;
  1394. UINTN Length;
  1395. PSTR NewPath;
  1396. while (*InputPath == '/') {
  1397. InputPath += 1;
  1398. }
  1399. CurrentInput = InputPath;
  1400. Length = 2;
  1401. while (*CurrentInput != '\0') {
  1402. Length += 1;
  1403. CurrentInput += 1;
  1404. }
  1405. NewPath = malloc(Length);
  1406. if (NewPath == NULL) {
  1407. return NULL;
  1408. }
  1409. CurrentInput = InputPath;
  1410. CurrentOutput = NewPath;
  1411. while (*CurrentInput != '\0') {
  1412. //
  1413. // If it's a slash, then terminate the current output and get past
  1414. // the backslash (and any additional consecutive ones).
  1415. //
  1416. if (*CurrentInput == '/') {
  1417. *CurrentOutput = '\0';
  1418. CurrentOutput += 1;
  1419. while (*CurrentInput == '/') {
  1420. CurrentInput += 1;
  1421. }
  1422. continue;
  1423. }
  1424. *CurrentOutput = *CurrentInput;
  1425. CurrentOutput += 1;
  1426. CurrentInput += 1;
  1427. }
  1428. //
  1429. // Double terminate the string.
  1430. //
  1431. *CurrentOutput = '\0';
  1432. CurrentOutput += 1;
  1433. *CurrentOutput = '\0';
  1434. return NewPath;
  1435. }