12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967 |
- /*++
- Copyright (c) 2014 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- fileio.c
- Abstract:
- This module implements support for file I/O in the setup program.
- Author:
- Evan Green 11-Apr-2014
- Environment:
- User
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <time.h>
- #include "setup.h"
- #include <minoca/lib/fat/fat.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define SETUP_DIRECTORY_ENTRY_SIZE 300
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure describes a file handle in the setup app.
- Members:
- Volume - Stores a pointer to the volume this file belongs to.
- Handle - Stores the handle returned from the layer below.
- Properties - Stores the file properties.
- SeekInformation - Stores the seek information for the file.
- CurrentOffset - Stores the current file offset.
- FatFile - Stores a pointer to the file systems internal context for the
- open file.
- IsDirty - Stores a boolean indicating if the file is dirty or not.
- --*/
- typedef struct _SETUP_FILE {
- PSETUP_VOLUME Volume;
- PVOID Handle;
- FILE_PROPERTIES Properties;
- FAT_SEEK_INFORMATION SeekInformation;
- ULONGLONG CurrentOffset;
- PVOID FatFile;
- ULONGLONG DirectoryFileId;
- BOOL IsDirty;
- } SETUP_FILE, *PSETUP_FILE;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- INT
- SetupFatOpen (
- PSETUP_VOLUME Volume,
- PSETUP_FILE NewFile,
- PCSTR Path,
- INT Flags,
- INT CreatePermissions,
- BOOL Directory
- );
- PSTR
- SetupFatCopyPath (
- PCSTR InputPath
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- PVOID
- SetupVolumeOpen (
- PSETUP_CONTEXT Context,
- PSETUP_DESTINATION Destination,
- SETUP_VOLUME_FORMAT_CHOICE Format,
- BOOL CompatibilityMode
- )
- /*++
- Routine Description:
- This routine opens a handle to a given volume.
- Arguments:
- Context - Supplies a pointer to the application context.
- Destination - Supplies a pointer to the destination to open.
- Format - Supplies the disposition for formatting the volume.
- CompatibilityMode - Supplies a boolean indicating whether to run the
- file system in the most compatible way possible.
- Return Value:
- Returns a pointer to an opaque context on success.
- NULL on failure.
- --*/
- {
- BLOCK_DEVICE_PARAMETERS BlockParameters;
- ULONG MountFlags;
- INT Result;
- KSTATUS Status;
- PSETUP_VOLUME Volume;
- memset(&BlockParameters, 0, sizeof(BLOCK_DEVICE_PARAMETERS));
- Volume = malloc(sizeof(SETUP_VOLUME));
- if (Volume == NULL) {
- Result = ENOMEM;
- goto OpenVolumeEnd;
- }
- memset(Volume, 0, sizeof(SETUP_VOLUME));
- Volume->Context = Context;
- Volume->DestinationType = Destination->Type;
- //
- // If this is an image, disk, or partition, open the native interface.
- //
- if ((Destination->Type == SetupDestinationDisk) ||
- (Destination->Type == SetupDestinationPartition) ||
- (Destination->Type == SetupDestinationImage)) {
- if ((Destination->Type == SetupDestinationPartition) ||
- (Destination->Type == SetupDestinationDisk)) {
- Volume->BlockHandle = Context->Disk;
- assert((Context->Disk != NULL) &&
- (Context->CurrentPartitionSize != 0));
- } else {
- Volume->BlockHandle = SetupOpenDestination(Destination, O_RDWR, 0);
- }
- if (Volume->BlockHandle == NULL) {
- printf("Error: Failed to open: ");
- SetupPrintDestination(Destination);
- Result = errno;
- if (Result > 0) {
- printf(": %s\n", strerror(errno));
- } else {
- Result = -1;
- printf("\n");
- }
- goto OpenVolumeEnd;
- }
- //
- // Fill out the block device parameters.
- //
- BlockParameters.DeviceToken = Volume;
- BlockParameters.BlockSize = SETUP_BLOCK_SIZE;
- if ((Destination->Type == SetupDestinationPartition) ||
- (Destination->Type == SetupDestinationDisk)) {
- BlockParameters.BlockCount = Context->CurrentPartitionSize;
- } else {
- Result = SetupFstat(Volume->BlockHandle,
- &(BlockParameters.BlockCount),
- NULL,
- NULL);
- if (Result != 0) {
- goto OpenVolumeEnd;
- }
- BlockParameters.BlockCount /= SETUP_BLOCK_SIZE;
- }
- MountFlags = 0;
- if (CompatibilityMode != FALSE) {
- MountFlags |= FAT_MOUNT_FLAG_COMPATIBILITY_MODE;
- }
- //
- // Potentially try to mount the volume without formatting it.
- //
- Status = STATUS_NOT_STARTED;
- if (Format == SetupVolumeFormatIfIncompatible) {
- Status = FatMount(&BlockParameters,
- MountFlags,
- &(Volume->VolumeToken));
- }
- //
- // Format the volume if needed.
- //
- if ((Format == SetupVolumeFormatAlways) ||
- ((Format == SetupVolumeFormatIfIncompatible) &&
- (!KSUCCESS(Status)))) {
- Status = FatFormat(&BlockParameters, 0, 0);
- if (!KSUCCESS(Status)) {
- printf("Error: Failed to format ");
- SetupPrintDestination(Destination);
- printf(": %d\n", Status);
- Result = -1;
- goto OpenVolumeEnd;
- }
- }
- Status = FatMount(&BlockParameters, MountFlags, &(Volume->VolumeToken));
- if (!KSUCCESS(Status)) {
- printf("Error: Failed to mount ");
- SetupPrintDestination(Destination);
- printf(": %d\n", Status);
- Result = -1;
- goto OpenVolumeEnd;
- }
- //
- // This is a directory, just copy the prefix over.
- //
- } else {
- assert(Destination->Type == SetupDestinationDirectory);
- if (Destination->Path == NULL) {
- fprintf(stderr,
- "Error: Installations to a directory need a path-based "
- "destination.\n");
- Result = -1;
- goto OpenVolumeEnd;
- }
- Volume->PathPrefix = strdup(Destination->Path);
- if (Volume->PathPrefix == NULL) {
- Result = ENOMEM;
- goto OpenVolumeEnd;
- }
- }
- Result = 0;
- OpenVolumeEnd:
- if (Result != 0) {
- if (Volume != NULL) {
- SetupVolumeClose(Context, Volume);
- Volume = NULL;
- }
- }
- return Volume;
- }
- VOID
- SetupVolumeClose (
- PSETUP_CONTEXT Context,
- PVOID Handle
- )
- /*++
- Routine Description:
- This routine closes a volume.
- Arguments:
- Context - Supplies a pointer to the application context.
- Handle - Supplies a pointer to the open volume handle.
- Return Value:
- None.
- --*/
- {
- PSETUP_VOLUME Volume;
- Volume = Handle;
- if (Volume->VolumeToken != NULL) {
- FatUnmount(Volume->VolumeToken);
- }
- if ((Volume->BlockHandle != NULL) &&
- (Volume->BlockHandle != Context->Disk)) {
- SetupClose(Volume->BlockHandle);
- }
- if (Volume->PathPrefix != NULL) {
- free(Volume->PathPrefix);
- }
- free(Volume);
- return;
- }
- INT
- SetupFileReadLink (
- PVOID Handle,
- PCSTR Path,
- PSTR *LinkTarget,
- INT *LinkTargetSize
- )
- /*++
- Routine Description:
- This routine attempts to read a symbolic link.
- Arguments:
- Handle - Supplies the volume handle.
- Path - Supplies a pointer to the path to open.
- LinkTarget - Supplies a pointer where an allocated link target will be
- returned on success. The caller is responsible for freeing this memory.
- LinkTargetSize - Supplies a pointer where the size of the link target will
- be returned on success.
- Return Value:
- Returns the link size on success.
- -1 on failure.
- --*/
- {
- PVOID File;
- PSTR FinalPath;
- mode_t Mode;
- INT Result;
- ULONGLONG Size;
- PSETUP_VOLUME Volume;
- File = NULL;
- *LinkTarget = NULL;
- Volume = Handle;
- FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
- if (FinalPath == NULL) {
- Result = ENOMEM;
- goto FileReadLinkEnd;
- }
- Result = -1;
- //
- // If it's the native interface, append the path and send the request
- // down directly.
- //
- if (Volume->DestinationType == SetupDestinationDirectory) {
- Result = SetupOsReadLink(FinalPath, LinkTarget, LinkTargetSize);
- //
- // Route this through the file system code.
- //
- } else {
- File = SetupFileOpen(Handle, Path, O_RDONLY, 0);
- if (File == NULL) {
- goto FileReadLinkEnd;
- }
- Result = SetupFileFileStat(File, &Size, NULL, &Mode);
- if ((Result != 0) || (S_ISLNK(Mode) == 0)) {
- Result = -1;
- goto FileReadLinkEnd;
- }
- *LinkTarget = malloc(Size + 1);
- if (*LinkTarget == NULL) {
- Result = -1;
- goto FileReadLinkEnd;
- }
- Result = SetupFileRead(File, *LinkTarget, Size);
- if (Result != Size) {
- Result = -1;
- goto FileReadLinkEnd;
- }
- (*LinkTarget)[Size] = '\0';
- *LinkTargetSize = Size;
- Result = 0;
- }
- FileReadLinkEnd:
- if (Result != 0) {
- if (*LinkTarget != NULL) {
- free(*LinkTarget);
- *LinkTarget = NULL;
- }
- }
- if (File != NULL) {
- SetupFileClose(File);
- File = NULL;
- }
- if (FinalPath != NULL) {
- free(FinalPath);
- }
- return Result;
- }
- INT
- SetupFileSymlink (
- PVOID Handle,
- PCSTR Path,
- PSTR LinkTarget,
- INT LinkTargetSize
- )
- /*++
- Routine Description:
- This routine creates a symbolic link.
- Arguments:
- Handle - Supplies the volume handle.
- Path - Supplies a pointer to the path of the symbolic link to create.
- LinkTarget - Supplies a pointer to the target of the link.
- LinkTargetSize - Supplies a the size of the link target buffer in bytes.
- Return Value:
- Returns the link size on success.
- -1 on failure.
- --*/
- {
- PSETUP_FILE File;
- PSTR FinalPath;
- INT Result;
- PSETUP_VOLUME Volume;
- File = NULL;
- Volume = Handle;
- FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
- if (FinalPath == NULL) {
- Result = ENOMEM;
- goto FileSymlinkEnd;
- }
- Result = -1;
- //
- // If it's the native interface, append the path and send the request
- // down directly.
- //
- if (Volume->DestinationType == SetupDestinationDirectory) {
- Result = SetupOsSymlink(FinalPath, LinkTarget, LinkTargetSize);
- //
- // Route this through the file system code.
- //
- } else {
- File = SetupFileOpen(Handle,
- Path,
- O_WRONLY | O_CREAT | O_TRUNC,
- FILE_PERMISSION_ALL);
- if (File == NULL) {
- goto FileSymlinkEnd;
- }
- Result = SetupFileWrite(File, LinkTarget, LinkTargetSize);
- if (Result != LinkTargetSize) {
- Result = -1;
- goto FileSymlinkEnd;
- }
- File->Properties.Permissions |= FILE_PERMISSION_ALL;
- File->Properties.Type = IoObjectSymbolicLink;
- File->IsDirty = TRUE;
- Result = 0;
- }
- FileSymlinkEnd:
- if (File != NULL) {
- SetupFileClose(File);
- File = NULL;
- }
- if (FinalPath != NULL) {
- free(FinalPath);
- }
- return Result;
- }
- PVOID
- SetupFileOpen (
- PVOID Handle,
- PCSTR Path,
- INT Flags,
- INT CreatePermissions
- )
- /*++
- Routine Description:
- This routine opens a handle to a file in a volume.
- Arguments:
- Handle - Supplies the volume handle.
- Path - Supplies a pointer to the path to open.
- Flags - Supplies open flags. See O_* definitions.
- CreatePermissions - Supplies optional create permissions.
- Return Value:
- Returns a pointer to an opaque context on success.
- NULL on failure.
- --*/
- {
- PSETUP_DESTINATION Destination;
- PSETUP_FILE File;
- PSTR FinalPath;
- INT Result;
- PSETUP_VOLUME Volume;
- File = NULL;
- Volume = Handle;
- FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
- if (FinalPath == NULL) {
- Result = ENOMEM;
- goto OpenFileEnd;
- }
- File = malloc(sizeof(SETUP_FILE));
- if (File == NULL) {
- Result = ENOMEM;
- goto OpenFileEnd;
- }
- memset(File, 0, sizeof(SETUP_FILE));
- File->Volume = Volume;
- //
- // If it's the native interface, append the path and send the request
- // down directly.
- //
- if (Volume->DestinationType == SetupDestinationDirectory) {
- Destination = SetupCreateDestination(SetupDestinationFile,
- FinalPath,
- 0);
- if (Destination == NULL) {
- Result = ENOMEM;
- goto OpenFileEnd;
- }
- File->Handle = SetupOpenDestination(Destination,
- Flags,
- CreatePermissions);
- SetupDestroyDestination(Destination);
- if (File->Handle == NULL) {
- Result = errno;
- goto OpenFileEnd;
- }
- //
- // Route this through the file system code.
- //
- } else {
- assert((Volume->DestinationType == SetupDestinationDisk) ||
- (Volume->DestinationType == SetupDestinationPartition) ||
- (Volume->DestinationType == SetupDestinationImage));
- Result = SetupFatOpen(Volume,
- File,
- FinalPath,
- Flags,
- CreatePermissions,
- FALSE);
- if (Result != 0) {
- goto OpenFileEnd;
- }
- }
- Result = 0;
- OpenFileEnd:
- if (Result != 0) {
- if (File != NULL) {
- SetupFileClose(File);
- File = NULL;
- }
- }
- if (FinalPath != NULL) {
- free(FinalPath);
- }
- return File;
- }
- VOID
- SetupFileClose (
- PVOID Handle
- )
- /*++
- Routine Description:
- This routine closes a file.
- Arguments:
- Handle - Supplies the handle to close.
- Return Value:
- None.
- --*/
- {
- PSETUP_FILE File;
- File = Handle;
- if (File->FatFile != NULL) {
- FatCloseFile(File->FatFile);
- }
- if (File->IsDirty != FALSE) {
- FatWriteFileProperties(File->Volume->VolumeToken,
- &(File->Properties),
- 0);
- }
- if (File->Handle != NULL) {
- SetupClose(File->Handle);
- }
- File->Volume->OpenFiles -= 1;
- free(File);
- return;
- }
- ssize_t
- SetupFileRead (
- PVOID Handle,
- void *Buffer,
- size_t ByteCount
- )
- /*++
- Routine Description:
- This routine reads from a file.
- Arguments:
- Handle - Supplies the handle.
- Buffer - Supplies a pointer where the read bytes will be returned.
- ByteCount - Supplies the number of bytes to read.
- Return Value:
- Returns the number of bytes read on success.
- --*/
- {
- UINTN BytesComplete;
- PSETUP_FILE File;
- PFAT_IO_BUFFER IoBuffer;
- KSTATUS Status;
- File = Handle;
- //
- // Pass directly to the native OS interface if the destination is native.
- //
- if (File->Volume->DestinationType == SetupDestinationDirectory) {
- return SetupRead(File->Handle, Buffer, ByteCount);
- }
- assert((File->Volume->DestinationType == SetupDestinationDisk) ||
- (File->Volume->DestinationType == SetupDestinationPartition) ||
- (File->Volume->DestinationType == SetupDestinationImage));
- if ((File->Properties.Type != IoObjectRegularFile) &&
- (File->Properties.Type != IoObjectSymbolicLink)) {
- return -1;
- }
- IoBuffer = FatCreateIoBuffer(Buffer, ByteCount);
- if (IoBuffer == NULL) {
- return -1;
- }
- BytesComplete = 0;
- Status = FatReadFile(File->FatFile,
- &(File->SeekInformation),
- IoBuffer,
- ByteCount,
- 0,
- NULL,
- &BytesComplete);
- ASSERT(BytesComplete <= ByteCount);
- File->CurrentOffset += BytesComplete;
- if ((!KSUCCESS(Status)) && (Status != STATUS_END_OF_FILE)) {
- fprintf(stderr, "FatReadFile Error: %d\n", Status);
- BytesComplete = 0;
- }
- if (IoBuffer != NULL) {
- FatFreeIoBuffer(IoBuffer);
- }
- return (ssize_t)BytesComplete;
- }
- ssize_t
- SetupFileWrite (
- PVOID Handle,
- void *Buffer,
- size_t ByteCount
- )
- /*++
- Routine Description:
- This routine writes data to an open file handle.
- Arguments:
- Handle - Supplies the handle.
- Buffer - Supplies a pointer to the bytes to write.
- ByteCount - Supplies the number of bytes to read.
- Return Value:
- Returns the number of bytes written.
- -1 on failure.
- --*/
- {
- UINTN BytesComplete;
- PSETUP_FILE File;
- ULONGLONG FileSize;
- PFAT_IO_BUFFER IoBuffer;
- KSTATUS Status;
- File = Handle;
- //
- // Pass directly to the native OS interface if the destination is native.
- //
- if (File->Volume->DestinationType == SetupDestinationDirectory) {
- return SetupWrite(File->Handle, Buffer, ByteCount);
- }
- assert((File->Volume->DestinationType == SetupDestinationDisk) ||
- (File->Volume->DestinationType == SetupDestinationPartition) ||
- (File->Volume->DestinationType == SetupDestinationImage));
- if ((File->Properties.Type != IoObjectRegularFile) &&
- (File->Properties.Type != IoObjectSymbolicLink)) {
- errno = EISDIR;
- return -1;
- }
- IoBuffer = FatCreateIoBuffer(Buffer, ByteCount);
- if (IoBuffer == NULL) {
- return -1;
- }
- BytesComplete = 0;
- FileSize = File->Properties.Size;
- Status = FatWriteFile(File->FatFile,
- &(File->SeekInformation),
- IoBuffer,
- ByteCount,
- 0,
- NULL,
- &BytesComplete);
- ASSERT(BytesComplete <= ByteCount);
- //
- // Advance the current position. Mark the file dirty and update the size
- // if the write made the file bigger.
- //
- File->CurrentOffset += BytesComplete;
- if (File->CurrentOffset > FileSize) {
- FileSize = File->CurrentOffset;
- File->Properties.Size = FileSize;
- File->IsDirty = TRUE;
- }
- if (!KSUCCESS(Status)) {
- fprintf(stderr, "FatWriteFile Error: %d\n", Status);
- if (Status == STATUS_VOLUME_FULL) {
- errno = ENOSPC;
- }
- BytesComplete = 0;
- }
- if (IoBuffer != NULL) {
- FatFreeIoBuffer(IoBuffer);
- }
- return (ssize_t)BytesComplete;
- }
- LONGLONG
- SetupFileSeek (
- PVOID Handle,
- LONGLONG Offset
- )
- /*++
- Routine Description:
- This routine seeks in the given file.
- Arguments:
- Handle - Supplies the handle.
- Offset - Supplies the new offset to set.
- Return Value:
- Returns the resulting file offset after the operation.
- -1 on failure, and errno will contain more information. The file offset
- will remain unchanged.
- --*/
- {
- PSETUP_FILE File;
- KSTATUS Status;
- File = Handle;
- //
- // Pass directly to the native OS interface if the destination is native.
- //
- if (File->Volume->DestinationType == SetupDestinationDirectory) {
- return SetupSeek(File->Handle, Offset);
- }
- assert((File->Volume->DestinationType == SetupDestinationDisk) ||
- (File->Volume->DestinationType == SetupDestinationPartition) ||
- (File->Volume->DestinationType == SetupDestinationImage));
- if (File->Properties.Type != IoObjectRegularFile) {
- return -1;
- }
- Status = FatFileSeek(File->FatFile,
- NULL,
- 0,
- SeekCommandFromBeginning,
- Offset,
- &(File->SeekInformation));
- if (!KSUCCESS(Status)) {
- fprintf(stderr, "FatFileSeek Error: %d\n", Status);
- Offset = -1;
- } else {
- File->CurrentOffset = Offset;
- }
- return Offset;
- }
- INT
- SetupFileFileStat (
- PVOID Handle,
- PULONGLONG FileSize,
- time_t *ModificationDate,
- mode_t *Mode
- )
- /*++
- Routine Description:
- This routine gets details for the given open file.
- Arguments:
- Handle - Supplies the handle.
- FileSize - Supplies an optional pointer where the file size will be
- returned on success.
- ModificationDate - Supplies an optional pointer where the file's
- modification date will be returned on success.
- Mode - Supplies an optional pointer where the file's mode information will
- be returned on success.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSETUP_FILE File;
- File = Handle;
- if (File->Volume->DestinationType == SetupDestinationDirectory) {
- return SetupFstat(File->Handle, FileSize, ModificationDate, Mode);
- }
- if (FileSize != NULL) {
- *FileSize = File->Properties.Size;
- }
- if (ModificationDate != NULL) {
- *ModificationDate = File->Properties.ModifiedTime.Seconds +
- SYSTEM_TIME_TO_EPOCH_DELTA;
- }
- if (Mode != NULL) {
- *Mode = 0;
- if (File->Properties.Type == IoObjectRegularDirectory) {
- *Mode |= S_IFDIR;
- } else if (File->Properties.Type == IoObjectSymbolicLink) {
- *Mode |= S_IFLNK;
- } else {
- *Mode |= S_IFREG;
- }
- *Mode |= File->Properties.Permissions;
- }
- return 0;
- }
- INT
- SetupFileFileTruncate (
- PVOID Handle,
- ULONGLONG NewSize
- )
- /*++
- Routine Description:
- This routine sets the file size of the given file.
- Arguments:
- Handle - Supplies the handle.
- NewSize - Supplies the new file size.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- ULONGLONG CurrentSize;
- PSETUP_FILE File;
- KSTATUS Status;
- File = Handle;
- if (File->Volume->DestinationType == SetupDestinationDirectory) {
- return SetupFtruncate(File->Handle, NewSize);
- }
- CurrentSize = File->Properties.Size;
- if (CurrentSize == NewSize) {
- return 0;
- } else if (NewSize < CurrentSize) {
- Status = FatDeleteFileBlocks(File->Volume->VolumeToken,
- File->Handle,
- File->Properties.FileId,
- NewSize,
- TRUE);
- } else {
- Status = FatAllocateFileClusters(File->Volume->VolumeToken,
- File->Properties.FileId,
- NewSize);
- }
- if (!KSUCCESS(Status)) {
- fprintf(stderr, "FatTruncate Error: %d\n", Status);
- return -1;
- }
- File->Properties.Size = NewSize;
- File->IsDirty = TRUE;
- return 0;
- }
- INT
- SetupFileEnumerateDirectory (
- PVOID VolumeHandle,
- PCSTR DirectoryPath,
- PSTR *Enumeration
- )
- /*++
- Routine Description:
- This routine enumerates the contents of a given directory.
- Arguments:
- VolumeHandle - Supplies the open volume handle.
- DirectoryPath - Supplies a pointer to a string containing the path to the
- directory to enumerate.
- Enumeration - Supplies a pointer where a pointer to a sequence of
- strings will be returned containing the files in the directory. The
- sequence will be terminated by an empty string. The caller is
- responsible for freeing this memory when done.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR Array;
- size_t ArrayCapacity;
- UINTN BytesRead;
- PDIRECTORY_ENTRY DirectoryEntry;
- ULONG ElementsRead;
- ULONGLONG EntryOffset;
- SETUP_FILE File;
- PSTR FinalPath;
- PFAT_IO_BUFFER IoBuffer;
- PSTR Name;
- size_t NameSize;
- PVOID NewBuffer;
- size_t NewCapacity;
- INT Result;
- KSTATUS Status;
- size_t UsedSize;
- PSETUP_VOLUME Volume;
- DirectoryEntry = NULL;
- IoBuffer = NULL;
- Name = NULL;
- Volume = VolumeHandle;
- memset(&File, 0, sizeof(SETUP_FILE));
- File.Volume = VolumeHandle;
- if (Volume->DestinationType == SetupDestinationDirectory) {
- FinalPath = SetupAppendPaths(Volume->PathPrefix, DirectoryPath);
- if (FinalPath == NULL) {
- Result = ENOMEM;
- goto EnumerateFileDirectoryEnd;
- }
- Result = SetupEnumerateDirectory(File.Volume,
- FinalPath,
- Enumeration);
- free(FinalPath);
- return Result;
- }
- Result = SetupFatOpen(VolumeHandle,
- &File,
- DirectoryPath,
- 0,
- 0,
- TRUE);
- if (Result != 0) {
- return Result;
- }
- Array = NULL;
- ArrayCapacity = 0;
- UsedSize = 0;
- EntryOffset = DIRECTORY_CONTENTS_OFFSET;
- DirectoryEntry = malloc(SETUP_DIRECTORY_ENTRY_SIZE);
- if (DirectoryEntry == NULL) {
- goto EnumerateFileDirectoryEnd;
- }
- IoBuffer = FatCreateIoBuffer(DirectoryEntry, SETUP_DIRECTORY_ENTRY_SIZE);
- if (IoBuffer == NULL) {
- goto EnumerateFileDirectoryEnd;
- }
- //
- // Loop reading directory entries.
- //
- while (TRUE) {
- BytesRead = 0;
- Status = FatEnumerateDirectory(File.FatFile,
- EntryOffset,
- IoBuffer,
- SETUP_DIRECTORY_ENTRY_SIZE,
- TRUE,
- FALSE,
- NULL,
- &BytesRead,
- &ElementsRead);
- if ((!KSUCCESS(Status)) && (Status != STATUS_END_OF_FILE)) {
- fprintf(stderr, "FatEnumerateDirectory Error: %d\n", Status);
- Result = -1;
- goto EnumerateFileDirectoryEnd;
- }
- NameSize = 1;
- if (Status != STATUS_END_OF_FILE) {
- Name = (PVOID)(DirectoryEntry + 1);
- NameSize = strlen(Name) + 1;
- }
- //
- // Reallocate the array if needed.
- //
- if (ArrayCapacity - UsedSize < NameSize) {
- NewCapacity = ArrayCapacity;
- if (NewCapacity == 0) {
- NewCapacity = 2;
- }
- while (NewCapacity - UsedSize < NameSize) {
- NewCapacity *= 2;
- }
- NewBuffer = realloc(Array, NewCapacity);
- if (NewBuffer == NULL) {
- Result = ENOMEM;
- goto EnumerateFileDirectoryEnd;
- }
- Array = NewBuffer;
- ArrayCapacity = NewCapacity;
- }
- //
- // Copy the entry (or an empty file if this is the end).
- //
- if (Status == STATUS_END_OF_FILE) {
- strcpy(Array + UsedSize, "");
- UsedSize += 1;
- Status = STATUS_SUCCESS;
- break;
- } else {
- strcpy(Array + UsedSize, Name);
- UsedSize += NameSize;
- }
- assert(ElementsRead != 0);
- EntryOffset += ElementsRead;
- }
- Result = 0;
- EnumerateFileDirectoryEnd:
- if (DirectoryEntry != NULL) {
- free(DirectoryEntry);
- }
- if (IoBuffer != NULL) {
- FatFreeIoBuffer(IoBuffer);
- }
- if (File.FatFile != NULL) {
- FatCloseFile(File.FatFile);
- }
- if (Result != 0) {
- if (Array != NULL) {
- free(Array);
- Array = NULL;
- }
- }
- *Enumeration = Array;
- return Result;
- }
- INT
- SetupFileCreateDirectory (
- PVOID VolumeHandle,
- PCSTR Path,
- mode_t Permissions
- )
- /*++
- Routine Description:
- This routine creates a new directory.
- Arguments:
- VolumeHandle - Supplies a pointer to the volume handle.
- Path - Supplies the path string of the directory to create.
- Permissions - Supplies the permission bits to create the file with.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- SETUP_FILE File;
- PSTR FinalPath;
- INT Result;
- PSETUP_VOLUME Volume;
- Volume = VolumeHandle;
- if (Volume->DestinationType == SetupDestinationDirectory) {
- FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
- if (FinalPath == NULL) {
- Result = ENOMEM;
- return Result;
- }
- Result = SetupOsCreateDirectory(FinalPath, Permissions);
- if (Result == EEXIST) {
- Result = 0;
- }
- free(FinalPath);
- return Result;
- }
- memset(&File, 0, sizeof(SETUP_FILE));
- File.Volume = VolumeHandle;
- Result = SetupFatOpen(VolumeHandle,
- &File,
- Path,
- O_CREAT,
- Permissions,
- TRUE);
- if (Result != 0) {
- return Result;
- }
- if (File.FatFile != NULL) {
- FatCloseFile(File.FatFile);
- }
- return Result;
- }
- INT
- SetupFileSetAttributes (
- PVOID VolumeHandle,
- PCSTR Path,
- time_t ModificationDate,
- mode_t Permissions
- )
- /*++
- Routine Description:
- This routine sets attributes on a given path.
- Arguments:
- VolumeHandle - Supplies a pointer to the volume handle.
- Path - Supplies the path string of the file to modify.
- ModificationDate - Supplies the new modification date to set.
- Permissions - Supplies the new permissions to set.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- SETUP_FILE File;
- PSTR FinalPath;
- BOOL IsDirectory;
- INT Result;
- PSETUP_VOLUME Volume;
- Volume = VolumeHandle;
- if (Volume->DestinationType == SetupDestinationDirectory) {
- FinalPath = SetupAppendPaths(Volume->PathPrefix, Path);
- if (FinalPath == NULL) {
- return ENOMEM;
- }
- Result = SetupOsSetAttributes(FinalPath, ModificationDate, Permissions);
- free(FinalPath);
- return Result;
- }
- memset(&File, 0, sizeof(SETUP_FILE));
- File.Volume = VolumeHandle;
- IsDirectory = FALSE;
- if (S_ISDIR(Permissions) != 0) {
- IsDirectory = TRUE;
- }
- Result = SetupFatOpen(VolumeHandle,
- &File,
- Path,
- 0,
- 0,
- IsDirectory);
- if (Result != 0) {
- return Result;
- }
- File.Properties.AccessTime.Seconds =
- time(NULL) - SYSTEM_TIME_TO_EPOCH_DELTA;
- File.Properties.AccessTime.Nanoseconds = 0;
- File.Properties.ModifiedTime.Seconds = ModificationDate -
- SYSTEM_TIME_TO_EPOCH_DELTA;
- File.Properties.ModifiedTime.Nanoseconds = 0;
- File.Properties.Permissions = Permissions & FILE_PERMISSION_MASK;
- if (S_ISDIR(Permissions)) {
- File.Properties.Type = IoObjectRegularDirectory;
- } else if (S_ISLNK(Permissions)) {
- File.Properties.Type = IoObjectSymbolicLink;
- } else {
- File.Properties.Type = IoObjectRegularFile;
- }
- FatCloseFile(File.FatFile);
- FatWriteFileProperties(Volume->VolumeToken, &(File.Properties), 0);
- return 0;
- }
- VOID
- SetupFileDetermineExecuteBit (
- PVOID Handle,
- PCSTR Path,
- mode_t *Mode
- )
- /*++
- Routine Description:
- This routine determines whether the open file is executable.
- Arguments:
- Handle - Supplies the open file handle.
- Path - Supplies the path the file was opened from (sometimes the file name
- is used as a hint).
- Mode - Supplies a pointer to the current mode bits. This routine may add
- the executable bit to user/group/other if it determines this file is
- executable.
- Return Value:
- None.
- --*/
- {
- PSETUP_FILE File;
- File = Handle;
- //
- // Pass directly to the native OS interface if the destination is native.
- //
- if (File->Volume->DestinationType == SetupDestinationDirectory) {
- return SetupDetermineExecuteBit(File->Handle, Path, Mode);
- }
- assert((File->Volume->DestinationType == SetupDestinationDisk) ||
- (File->Volume->DestinationType == SetupDestinationPartition) ||
- (File->Volume->DestinationType == SetupDestinationImage));
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- INT
- SetupFatOpen (
- PSETUP_VOLUME Volume,
- PSETUP_FILE NewFile,
- PCSTR Path,
- INT Flags,
- INT CreatePermissions,
- BOOL Directory
- )
- /*++
- Routine Description:
- This routine opens a file in a FAT image.
- Arguments:
- Volume - Supplies a pointer to the volume.
- NewFile - Supplies a pointer to the new file being opened.
- Path - Supplies a pointer to the path to open.
- Flags - Supplies open flags. See O_* definitions.
- CreatePermissions - Supplies optional create permissions.
- Directory - Supplies a boolean indicating if this is a directory open or
- file open.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR CurrentPath;
- size_t CurrentPathLength;
- ULONG DesiredAccess;
- FILE_ID DirectoryFileId;
- ULONG FatOpenFlags;
- ULONGLONG NewDirectorySize;
- FILE_PROPERTIES NewProperties;
- PSTR OpenedFileName;
- size_t OpenedFileNameLength;
- PSTR PathCopy;
- FILE_PROPERTIES Properties;
- KSTATUS Status;
- DirectoryFileId = 0;
- PathCopy = NULL;
- //
- // Start at the root.
- //
- Status = FatLookup(Volume->VolumeToken, TRUE, 0, NULL, 0, &Properties);
- if (!KSUCCESS(Status)) {
- goto FatOpenEnd;
- }
- PathCopy = SetupFatCopyPath(Path);
- if (PathCopy == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto FatOpenEnd;
- }
- if (*PathCopy == '\0') {
- Status = STATUS_NOT_FOUND;
- goto FatOpenEnd;
- }
- //
- // Loop opening the next component in the path.
- //
- CurrentPath = PathCopy;
- CurrentPathLength = strlen(CurrentPath);
- Status = STATUS_SUCCESS;
- while (TRUE) {
- if (CurrentPathLength == 0) {
- break;
- }
- DirectoryFileId = Properties.FileId;
- OpenedFileName = CurrentPath;
- OpenedFileNameLength = CurrentPathLength;
- Status = FatLookup(Volume->VolumeToken,
- FALSE,
- Properties.FileId,
- CurrentPath,
- CurrentPathLength + 1,
- &Properties);
- //
- // If the file was not found, stop.
- //
- if ((Status == STATUS_NO_SUCH_FILE) ||
- (Status == STATUS_NOT_FOUND) ||
- (Status == STATUS_PATH_NOT_FOUND)) {
- Status = STATUS_NOT_FOUND;
- break;
- //
- // If some wackier error occured, fail the whole function.
- //
- } else if (!KSUCCESS(Status)) {
- goto FatOpenEnd;
- }
- //
- // This file was found, move to the next path component.
- //
- CurrentPath += CurrentPathLength + 1;
- CurrentPathLength = strlen(CurrentPath);
- //
- // If the file was not a directory, nothing more can be looked up
- // underneath this, so stop.
- //
- if (Properties.Type != IoObjectRegularDirectory) {
- break;
- }
- }
- ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_NOT_FOUND));
- //
- // Okay, either the path ended, the file was not found, or the file was
- // not a directory. If the file was found, but an exclusive open was
- // requested, fail.
- //
- if (Status == STATUS_SUCCESS) {
- if ((CurrentPathLength == 0) &&
- ((Flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
- Status = STATUS_FILE_EXISTS;
- goto FatOpenEnd;
- }
- //
- // If the file was not found, maybe create it.
- //
- } else if (Status == STATUS_NOT_FOUND) {
- //
- // If the file doesn't exist and the caller doesn't want to create it,
- // then return not found.
- //
- if ((Flags & O_CREAT) == 0) {
- goto FatOpenEnd;
- }
- //
- // Fail if the volume is read-only.
- //
- if (Volume->DestinationType == SetupDestinationImage) {
- Status = STATUS_ACCESS_DENIED;
- goto FatOpenEnd;
- }
- //
- // The caller wants to create a file or directory. If the last
- // successful lookup wasn't a directory, fail.
- //
- if (Properties.Type != IoObjectRegularDirectory) {
- goto FatOpenEnd;
- }
- //
- // If this isn't the last component, also fail.
- //
- if (CurrentPath[CurrentPathLength + 1] != '\0') {
- goto FatOpenEnd;
- }
- //
- // Create the new file or directory.
- //
- memcpy(&NewProperties, &Properties, sizeof(FILE_PROPERTIES));
- NewProperties.Type = IoObjectRegularFile;
- if (Directory != FALSE) {
- NewProperties.Type = IoObjectRegularDirectory;
- }
- NewProperties.Permissions = CreatePermissions;
- NewProperties.FileId = 0;
- NewProperties.Size = 0;
- FatGetCurrentSystemTime(&(NewProperties.StatusChangeTime));
- OpenedFileName = CurrentPath;
- OpenedFileNameLength = CurrentPathLength;
- Status = FatCreate(Volume->VolumeToken,
- Properties.FileId,
- OpenedFileName,
- OpenedFileNameLength + 1,
- &NewDirectorySize,
- &NewProperties);
- if (!KSUCCESS(Status)) {
- goto FatOpenEnd;
- }
- //
- // Update the directory properties, as that new file may have made the
- // directory bigger.
- //
- Properties.Size = NewDirectorySize;
- Status = FatWriteFileProperties(Volume->VolumeToken, &Properties, 0);
- if (!KSUCCESS(Status)) {
- goto FatOpenEnd;
- }
- //
- // Make it look like this new file was successfully looked up by the
- // above loop.
- //
- CurrentPathLength = 0;
- memcpy(&Properties, &NewProperties, sizeof(FILE_PROPERTIES));
- }
- //
- // If there are more components to the path, then this lookup failed.
- //
- if (CurrentPathLength != 0) {
- Status = STATUS_PATH_NOT_FOUND;
- goto FatOpenEnd;
- }
- //
- // If the file is a symbolic link, don't open it if the caller specified
- // the "no follow" flag.
- //
- if ((Properties.Type == IoObjectSymbolicLink) &&
- ((Flags & O_NOFOLLOW) != 0)) {
- Status = STATUS_UNEXPECTED_TYPE;
- goto FatOpenEnd;
- }
- memcpy(&(NewFile->Properties), &Properties, sizeof(FILE_PROPERTIES));
- memset(&(NewFile->SeekInformation), 0, sizeof(FAT_SEEK_INFORMATION));
- NewFile->CurrentOffset = 0;
- NewFile->FatFile = NULL;
- NewFile->DirectoryFileId = DirectoryFileId;
- DesiredAccess = 0;
- switch (Flags & O_ACCMODE) {
- case O_RDONLY:
- DesiredAccess = IO_ACCESS_READ;
- break;
- case O_WRONLY:
- DesiredAccess = IO_ACCESS_WRITE;
- break;
- case O_RDWR:
- DesiredAccess = IO_ACCESS_READ | IO_ACCESS_WRITE;
- break;
- }
- //
- // Truncate the file if desired.
- //
- if ((Flags & O_TRUNC) != 0) {
- assert(Directory == FALSE);
- Status = FatDeleteFileBlocks(Volume->VolumeToken,
- NULL,
- Properties.FileId,
- 0,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto FatOpenEnd;
- }
- NewFile->Properties.Size = 0;
- }
- FatOpenFlags = 0;
- if (Directory != FALSE) {
- FatOpenFlags |= OPEN_FLAG_DIRECTORY;
- }
- Status = FatOpenFileId(Volume->VolumeToken,
- Properties.FileId,
- DesiredAccess,
- FatOpenFlags,
- &(NewFile->FatFile));
- if (!KSUCCESS(Status)) {
- goto FatOpenEnd;
- }
- Volume->OpenFiles += 1;
- Status = STATUS_SUCCESS;
- FatOpenEnd:
- if (PathCopy != NULL) {
- free(PathCopy);
- }
- if (!KSUCCESS(Status)) {
- if ((Status == STATUS_NOT_FOUND) || (Status == STATUS_PATH_NOT_FOUND)) {
- errno = ENOENT;
- } else if (Status == STATUS_VOLUME_FULL) {
- errno = ENOSPC;
- }
- if ((Status != STATUS_NOT_FOUND) &&
- (Status != STATUS_UNEXPECTED_TYPE)) {
- fprintf(stderr, "FatOpenFile Error %s: %d\n", Path, Status);
- errno = EINVAL;
- }
- return -1;
- }
- return 0;
- }
- PSTR
- SetupFatCopyPath (
- PCSTR InputPath
- )
- /*++
- Routine Description:
- This routine creates a copy of the given path, separating slashes with
- terminators along the way.
- Arguments:
- InputPath - Supplies a pointer to the input path.
- Return Value:
- Returns a pointer to the separated path, terminated with an additional
- NULL terminator.
- NULL on allocation failure.
- --*/
- {
- PCSTR CurrentInput;
- PSTR CurrentOutput;
- UINTN Length;
- PSTR NewPath;
- while (*InputPath == '/') {
- InputPath += 1;
- }
- CurrentInput = InputPath;
- Length = 2;
- while (*CurrentInput != '\0') {
- Length += 1;
- CurrentInput += 1;
- }
- NewPath = malloc(Length);
- if (NewPath == NULL) {
- return NULL;
- }
- CurrentInput = InputPath;
- CurrentOutput = NewPath;
- while (*CurrentInput != '\0') {
- //
- // If it's a slash, then terminate the current output and get past
- // the backslash (and any additional consecutive ones).
- //
- if (*CurrentInput == '/') {
- *CurrentOutput = '\0';
- CurrentOutput += 1;
- while (*CurrentInput == '/') {
- CurrentInput += 1;
- }
- continue;
- }
- *CurrentOutput = *CurrentInput;
- CurrentOutput += 1;
- CurrentInput += 1;
- }
- //
- // Double terminate the string.
- //
- *CurrentOutput = '\0';
- CurrentOutput += 1;
- *CurrentOutput = '\0';
- return NewPath;
- }
|