123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305 |
- /*++
- 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:
- util.c
- Abstract:
- This module implements utility functions for the setup program.
- Author:
- Evan Green 10-Apr-2014
- Environment:
- User
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <time.h>
- #include "setup.h"
- #include "sconf.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define SETUP_FILE_BUFFER_SIZE (1024 * 512)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- PSTR SetupPartitionDescriptions[] = {
- "Invalid",
- "",
- "Unknown",
- "Empty",
- "FAT12",
- "FAT16",
- "Extended",
- "NTFS",
- "FAT32",
- "FAT32L",
- "FAT16",
- "ExtendedLba",
- "WinRE",
- "Plan9",
- "Hurd",
- "Minoca",
- "Minix",
- "Minix",
- "Linux Swap",
- "Linux",
- "LinuxExtended",
- "LinuxLVM",
- "BSD",
- "FreeBSD",
- "OpenBSD",
- "NeXTStep",
- "MacOSX",
- "NetBSD",
- "MacOSXBoot",
- "HFS",
- "EFIGPT",
- "EFISystem",
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- PSETUP_DESTINATION
- SetupCreateDestination (
- SETUP_DESTINATION_TYPE Type,
- PSTR Path,
- DEVICE_ID DeviceId
- )
- /*++
- Routine Description:
- This routine creates a setup destination structure.
- Arguments:
- Type - Supplies the destination type.
- Path - Supplies an optional pointer to the path. A copy of this string will
- be made.
- DeviceId - Supplies an optional device ID.
- Return Value:
- Returns a pointer to the newly created destination on success.
- NULL on allocation failure.
- --*/
- {
- PSETUP_DESTINATION Destination;
- Destination = malloc(sizeof(SETUP_DESTINATION));
- if (Destination == NULL) {
- return NULL;
- }
- memset(Destination, 0, sizeof(SETUP_DESTINATION));
- Destination->Type = Type;
- Destination->DeviceId = DeviceId;
- if (Path != NULL) {
- Destination->Path = strdup(Path);
- if (Destination->Path == NULL) {
- free(Destination);
- return NULL;
- }
- }
- return Destination;
- }
- VOID
- SetupDestroyDestination (
- PSETUP_DESTINATION Destination
- )
- /*++
- Routine Description:
- This routine destroys a setup destination structure.
- Arguments:
- Destination - Supplies a pointer to the destination structure to free.
- Return Value:
- None.
- --*/
- {
- if (Destination->Path != NULL) {
- free(Destination->Path);
- }
- free(Destination);
- return;
- }
- VOID
- SetupDestroyDeviceDescriptions (
- PSETUP_PARTITION_DESCRIPTION Devices,
- ULONG DeviceCount
- )
- /*++
- Routine Description:
- This routine destroys an array of device descriptions.
- Arguments:
- Devices - Supplies a pointer to the array to destroy.
- DeviceCount - Supplies the number of elements in the array.
- Return Value:
- None.
- --*/
- {
- ULONG Index;
- for (Index = 0; Index < DeviceCount; Index += 1) {
- if (Devices[Index].Destination != NULL) {
- SetupDestroyDestination(Devices[Index].Destination);
- }
- }
- free(Devices);
- return;
- }
- VOID
- SetupPrintDeviceDescription (
- PSETUP_PARTITION_DESCRIPTION Device,
- BOOL PrintHeader
- )
- /*++
- Routine Description:
- This routine prints a device description.
- Arguments:
- Device - Supplies a pointer to the device description.
- PrintHeader - Supplies a boolean indicating if the column descriptions
- should be printed.
- Return Value:
- None.
- --*/
- {
- PSTR DeviceType;
- ULONG DiskId;
- ULONGLONG Offset;
- CHAR OffsetString[20];
- CHAR PartitionFlavor;
- ULONG PartitionId;
- PSTR PartitionScheme;
- PSTR PartitionTypeString;
- ULONGLONG Size;
- CHAR SizeString[20];
- CHAR System;
- DeviceType = "Partition";
- PartitionFlavor = ' ';
- System = ' ';
- PartitionScheme = "";
- if (Device->Partition.PartitionFormat == PartitionFormatGpt) {
- PartitionScheme = "GPT";
- } else if (Device->Partition.PartitionFormat == PartitionFormatMbr) {
- PartitionScheme = "MBR";
- }
- if ((Device->Partition.Flags & PARTITION_FLAG_RAW_DISK) != 0) {
- DeviceType = "Disk";
- } else if ((Device->Partition.Flags & PARTITION_FLAG_BOOT) != 0) {
- PartitionFlavor = 'B';
- } else if ((Device->Partition.Flags & PARTITION_FLAG_EXTENDED) != 0) {
- PartitionFlavor = 'E';
- } else if ((Device->Partition.Flags & PARTITION_FLAG_LOGICAL) != 0) {
- PartitionFlavor = 'L';
- }
- if ((Device->Flags & SETUP_DEVICE_FLAG_SYSTEM) != 0) {
- System = 'S';
- }
- RtlCopyMemory(&DiskId, &(Device->Partition.DiskId[0]), sizeof(ULONG));
- if (Device->Partition.PartitionFormat == PartitionFormatMbr) {
- RtlCopyMemory(&PartitionId,
- &(Device->Partition.PartitionId[sizeof(ULONG)]),
- sizeof(ULONG));
- } else {
- RtlCopyMemory(&PartitionId,
- &(Device->Partition.PartitionId[0]),
- sizeof(ULONG));
- }
- PartitionTypeString = "";
- if (Device->Partition.PartitionType <
- sizeof(SetupPartitionDescriptions) /
- sizeof(SetupPartitionDescriptions[0])) {
- PartitionTypeString =
- SetupPartitionDescriptions[Device->Partition.PartitionType];
- }
- Offset = Device->Partition.FirstBlock * Device->Partition.BlockSize;
- SetupPrintSize(OffsetString, sizeof(OffsetString), Offset);
- Size = ((Device->Partition.LastBlock + 1) * Device->Partition.BlockSize) -
- Offset;
- SetupPrintSize(SizeString, sizeof(SizeString), Size);
- if (PrintHeader != FALSE) {
- printf(" DiskId PartID DevType Fmt Type Offset "
- "Size Path\n");
- printf(" --------------------------------------------------------"
- "--------------------\n");
- }
- printf(" %08X %08X %-9s %3s %c%c %-13s %-6s %-6s ",
- DiskId,
- PartitionId,
- DeviceType,
- PartitionScheme,
- PartitionFlavor,
- System,
- PartitionTypeString,
- OffsetString,
- SizeString);
- SetupPrintDestination(Device->Destination);
- printf("\n");
- return;
- }
- ULONG
- SetupPrintSize (
- PCHAR String,
- ULONG StringSize,
- ULONGLONG Value
- )
- /*++
- Routine Description:
- This routine prints a formatted size a la 5.8M (M for megabytes).
- Arguments:
- String - Supplies a pointer to the string buffer to print to.
- StringSize - Supplies the total size of the string buffer in bytes.
- Value - Supplies the value in bytes to print.
- Return Value:
- Returns the number of bytes successfully converted.
- --*/
- {
- ULONG Size;
- CHAR Suffix;
- Suffix = 'B';
- if (Value > 1024) {
- Suffix = 'K';
- Value = (Value * 10) / 1024;
- if (Value / 10 >= 1024) {
- Suffix = 'M';
- Value /= 1024;
- if (Value / 10 >= 1024) {
- Suffix = 'G';
- Value /= 1024;
- if (Value / 10 >= 1024) {
- Suffix = 'T';
- Value /= 1024;
- }
- }
- }
- }
- if (Suffix == 'B') {
- Size = snprintf(String, StringSize, "%d", (ULONG)Value);
- } else {
- if (Value < 100) {
- Size = snprintf(String,
- StringSize,
- "%d.%d%c",
- (ULONG)Value / 10,
- (ULONG)Value % 10,
- Suffix);
- } else {
- Size = snprintf(String,
- StringSize,
- "%d%c",
- (ULONG)Value / 10,
- Suffix);
- }
- }
- return Size;
- }
- VOID
- SetupPrintDestination (
- PSETUP_DESTINATION Destination
- )
- /*++
- Routine Description:
- This routine prints a destination structure.
- Arguments:
- Destination - Supplies a pointer to the destination.
- Return Value:
- None.
- --*/
- {
- if (Destination->Path != NULL) {
- printf("%s", Destination->Path);
- } else {
- printf("Device 0x%llX", Destination->DeviceId);
- }
- return;
- }
- PSETUP_DESTINATION
- SetupParseDestination (
- SETUP_DESTINATION_TYPE DestinationType,
- PSTR Argument
- )
- /*++
- Routine Description:
- This routine converts a string argument into a destination. Device ID
- destinations can start with "0x", and everything else is treated as a
- path. An empty string is not valid.
- Arguments:
- DestinationType - Supplies the destination type.
- Argument - Supplies the string argument.
- Return Value:
- Returns a pointer to a newly created destination on success. The caller
- is responsible for destroying this structure.
- NULL if the argument is not valid.
- --*/
- {
- PSTR AfterScan;
- ULONGLONG DeviceId;
- if (*Argument == '\0') {
- return NULL;
- }
- if ((Argument[0] == '0') &&
- ((Argument[1] == 'x') || (Argument[1] == 'X'))) {
- DeviceId = strtoull(Argument, &AfterScan, 16);
- if (*AfterScan != '\0') {
- return NULL;
- }
- return SetupCreateDestination(DestinationType, NULL, DeviceId);
- }
- return SetupCreateDestination(DestinationType, Argument, 0);
- }
- PSTR
- SetupAppendPaths (
- PCSTR Path1,
- PCSTR Path2
- )
- /*++
- Routine Description:
- This routine appends two paths to one another.
- Arguments:
- Path1 - Supplies a pointer to the first path.
- Path2 - Supplies a pointer to the second path.
- Return Value:
- Returns a pointer to a newly created combined path on success. The caller
- is responsible for freeing this new path.
- NULL on allocation failure.
- --*/
- {
- size_t Length1;
- size_t Length2;
- PSTR NewPath;
- if (Path1 == NULL) {
- return strdup(Path2);
- }
- Length1 = strlen(Path1);
- Length2 = strlen(Path2);
- NewPath = malloc(Length1 + Length2 + 2);
- if (NewPath == NULL) {
- return NULL;
- }
- strcpy(NewPath, Path1);
- if ((Length1 != 0) && (Path1[Length1 - 1] != '/')) {
- NewPath[Length1] = '/';
- Length1 += 1;
- }
- strcpy(NewPath + Length1, Path2);
- return NewPath;
- }
- INT
- SetupConvertStringArrayToLines (
- PCSTR *StringArray,
- PSTR *ResultBuffer,
- PUINTN ResultBufferSize
- )
- /*++
- Routine Description:
- This routine converts a null-terminated array of strings into a single
- buffer where each element is separated by a newline.
- Arguments:
- StringArray - Supplies a pointer to the array of strings. The array must be
- terminated by a NULL entry.
- ResultBuffer - Supplies a pointer where a string will be returned
- containing all the lines. The caller is responsible for freeing this
- buffer.
- ResultBufferSize - Supplies a pointer where size of the buffer in bytes
- will be returned, including the null terminator.
- Return Value:
- 0 on success.
- ENOMEM on allocation failure.
- --*/
- {
- UINTN AllocationSize;
- PCSTR *Array;
- PSTR Buffer;
- PSTR Current;
- size_t Length;
- AllocationSize = 1;
- Array = StringArray;
- while (*Array != NULL) {
- AllocationSize += strlen(*Array) + 1;
- Array += 1;
- }
- Buffer = malloc(AllocationSize);
- if (Buffer == NULL) {
- return ENOMEM;
- }
- Current = Buffer;
- Array = StringArray;
- while (*Array != NULL) {
- Length = strlen(*Array);
- memcpy(Current, *Array, Length);
- Current[Length] = '\n';
- Current += Length + 1;
- Array += 1;
- }
- *Current = '\0';
- *ResultBuffer = Buffer;
- *ResultBufferSize = AllocationSize;
- return 0;
- }
- INT
- SetupCopyFile (
- PSETUP_CONTEXT Context,
- PVOID Destination,
- PVOID Source,
- PCSTR DestinationPath,
- PCSTR SourcePath,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine copies the given path from the source to the destination. If
- the source is a directory, the contents of that directory are recursively
- copied to the destination.
- Arguments:
- Context - Supplies a pointer to the applicaton context.
- Destination - Supplies a pointer to the open destination volume
- handle.
- Source - Supplies a pointer to the open source volume handle.
- DestinationPath - Supplies a pointer to the path of the file to create at
- the destination.
- SourcePath - Supplies the source path of the copy.
- Flags - Supplies a bitfield of flags governing the operation. See
- SETUP_COPY_FLAG_* definitions.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR AppendedDestinationPath;
- PSTR AppendedSourcePath;
- PVOID Buffer;
- PVOID DestinationFile;
- PSTR DirectoryEntry;
- PSTR Enumeration;
- mode_t ExistingMode;
- time_t ExistingModificationDate;
- ULONGLONG FileSize;
- PSTR LinkTarget;
- INT LinkTargetSize;
- mode_t Mode;
- time_t ModificationDate;
- INT Result;
- ssize_t Size;
- ssize_t SizeWritten;
- PVOID SourceFile;
- AppendedDestinationPath = NULL;
- AppendedSourcePath = NULL;
- Buffer = NULL;
- DestinationFile = NULL;
- FileSize = 0;
- Enumeration = NULL;
- LinkTarget = NULL;
- Mode = 0;
- ModificationDate = 0;
- Result = -1;
- SourceFile = SetupFileOpen(Source, SourcePath, O_RDONLY | O_NOFOLLOW, 0);
- //
- // Some OSes don't allow opening of directories. If the source open failed
- // and the error is that it's a directory, then handle that.
- //
- if ((SourceFile == NULL) && (errno == EISDIR)) {
- Mode = S_IFDIR | FILE_PERMISSION_USER_ALL | FILE_PERMISSION_GROUP_ALL |
- FILE_PERMISSION_OTHER_READ |
- FILE_PERMISSION_OTHER_EXECUTE;
- ModificationDate = time(NULL);
- } else if (SourceFile == NULL) {
- //
- // If the file could not be opened, maybe it's a symbolic link. Try to
- // read that.
- //
- Result = SetupFileReadLink(Source,
- SourcePath,
- &LinkTarget,
- &LinkTargetSize);
- if (Result != 0) {
- Result = errno;
- //
- // Forgive optional copies if they don't exist.
- //
- if ((Result == ENOENT) &&
- ((Flags & SETUP_COPY_FLAG_OPTIONAL) != 0)) {
- Result = 0;
- } else {
- fprintf(stderr,
- "Failed to open source file %s: %s\n",
- SourcePath,
- strerror(Result));
- if (Result == 0) {
- Result = -1;
- }
- }
- goto CopyFileEnd;
- }
- //
- // Try to create a link in the target.
- //
- Result = SetupFileSymlink(Destination,
- DestinationPath,
- LinkTarget,
- LinkTargetSize);
- //
- // If not possible, fall back to copying the file.
- //
- if (Result == 0) {
- goto CopyFileEnd;
- }
- fprintf(stderr,
- "Failed to create symbolic link at %s, copying instead.\n",
- DestinationPath);
- SourceFile = SetupFileOpen(Source, LinkTarget, O_RDONLY, 0);
- if (SourceFile == NULL) {
- fprintf(stderr,
- "Failed to open source file link %s.\n",
- LinkTarget);
- Result = errno;
- if (Result == 0) {
- Result = -1;
- }
- goto CopyFileEnd;
- }
- }
- if (SourceFile != NULL) {
- Result = SetupFileFileStat(SourceFile,
- &FileSize,
- &ModificationDate,
- &Mode);
- if (Result != 0) {
- goto CopyFileEnd;
- }
- }
- //
- // If this is a directory, create a directory in the destination.
- //
- if (S_ISDIR(Mode) != 0) {
- if (S_IRGRP == 0) {
- if ((Mode & S_IRUSR) != 0) {
- Mode |= FILE_PERMISSION_GROUP_READ |
- FILE_PERMISSION_OTHER_READ |
- FILE_PERMISSION_USER_EXECUTE |
- FILE_PERMISSION_GROUP_EXECUTE |
- FILE_PERMISSION_OTHER_EXECUTE;
- }
- }
- //
- // Attempt to create the destination directory at once. If it fails,
- // perhaps the directories leading up to it must be created.
- //
- Result = SetupFileCreateDirectory(Destination,
- DestinationPath,
- Mode);
- if (Result != 0) {
- Result = SetupCreateDirectories(Context,
- Destination,
- DestinationPath);
- if (Result == 0) {
- Result = SetupFileCreateDirectory(Destination,
- DestinationPath,
- Mode);
- }
- }
- if (Result != 0) {
- Result = errno;
- fprintf(stderr,
- "Failed to create destination directory %s.\n",
- DestinationPath);
- if (Result == 0) {
- Result = -1;
- }
- goto CopyFileEnd;
- }
- Result = SetupFileEnumerateDirectory(Source, SourcePath, &Enumeration);
- if (Result != 0) {
- fprintf(stderr, "Failed to enumerate directory %s.\n", SourcePath);
- goto CopyFileEnd;
- }
- //
- // Loop over every file in the directory.
- //
- DirectoryEntry = Enumeration;
- while (*DirectoryEntry != '\0') {
- AppendedDestinationPath = SetupAppendPaths(DestinationPath,
- DirectoryEntry);
- if (AppendedDestinationPath == NULL) {
- Result = ENOMEM;
- goto CopyFileEnd;
- }
- AppendedSourcePath = SetupAppendPaths(SourcePath, DirectoryEntry);
- if (AppendedSourcePath == NULL) {
- Result = ENOMEM;
- goto CopyFileEnd;
- }
- //
- // Recurse and copy each file inside the directory.
- //
- Result = SetupCopyFile(Context,
- Destination,
- Source,
- AppendedDestinationPath,
- AppendedSourcePath,
- Flags);
- if (Result != 0) {
- fprintf(stderr,
- "Failed to copy %s.\n",
- AppendedDestinationPath);
- goto CopyFileEnd;
- }
- free(AppendedDestinationPath);
- free(AppendedSourcePath);
- AppendedDestinationPath = NULL;
- AppendedSourcePath = NULL;
- DirectoryEntry += strlen(DirectoryEntry) + 1;
- }
- //
- // Set directory permissions.
- //
- Result = SetupFileSetAttributes(Destination,
- DestinationPath,
- ModificationDate,
- Mode);
- if (Result != 0) {
- fprintf(stderr,
- "Failed to set mode on directory %s.\n",
- DestinationPath);
- goto CopyFileEnd;
- }
- //
- // This is a regular file, so open it up in the destination and copy it in
- // chunks.
- //
- } else {
- //
- // If this is an update operation, first try to open up the destination
- // to see if it is newer than the source.
- //
- if ((Flags & SETUP_COPY_FLAG_UPDATE) != 0) {
- DestinationFile = SetupFileOpen(Destination,
- DestinationPath,
- O_RDONLY | O_NOFOLLOW,
- 0);
- if (DestinationFile != NULL) {
- Result = SetupFileFileStat(DestinationFile,
- NULL,
- &ExistingModificationDate,
- &ExistingMode);
- SetupFileClose(DestinationFile);
- DestinationFile = NULL;
- if (Result != 0) {
- goto CopyFileEnd;
- }
- //
- // If the existing one is the same type of file and is at least
- // as new, don't update it.
- //
- if ((ExistingModificationDate >= ModificationDate) &&
- (((ExistingMode ^ Mode) & S_IFMT) == 0)) {
- if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
- printf("Skipping %s -> %s\n",
- SourcePath,
- DestinationPath);
- }
- Result = 0;
- goto CopyFileEnd;
- }
- }
- }
- //
- // Some OSes don't have an executable bit, but still need to be able
- // to install executables onto OSes that do. Probe around a bit to see
- // if the file should be set executable.
- //
- if ((Mode & FILE_PERMISSION_ALL_EXECUTE) == 0) {
- SetupFileDetermineExecuteBit(SourceFile, SourcePath, &Mode);
- }
- Buffer = malloc(SETUP_FILE_BUFFER_SIZE);
- if (Buffer == NULL) {
- Result = ENOMEM;
- goto CopyFileEnd;
- }
- if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
- printf("Copying %s -> %s\n", SourcePath, DestinationPath);
- }
- SetupCreateDirectories(Context, Destination, DestinationPath);
- DestinationFile = SetupFileOpen(Destination,
- DestinationPath,
- O_CREAT | O_TRUNC | O_RDWR | O_NOFOLLOW,
- Mode);
- if (DestinationFile == NULL) {
- Result = errno;
- fprintf(stderr,
- "Failed to create destination file %s.\n",
- DestinationPath);
- if (Result == 0) {
- Result = -1;
- }
- goto CopyFileEnd;
- }
- //
- // Loop copying chunks.
- //
- while (FileSize != 0) {
- Size = SETUP_FILE_BUFFER_SIZE;
- if (Size > FileSize) {
- Size = FileSize;
- }
- Size = SetupFileRead(SourceFile, Buffer, Size);
- if (Size <= 0) {
- if (Size < 0) {
- Result = errno;
- if (Result == 0) {
- Result = EINVAL;
- }
- goto CopyFileEnd;
- }
- break;
- }
- SizeWritten = SetupFileWrite(DestinationFile, Buffer, Size);
- if (SizeWritten != Size) {
- fprintf(stderr,
- "Failed to write to file %s.\n",
- DestinationPath);
- Result = errno;
- if (Result == 0) {
- Result = errno;
- }
- goto CopyFileEnd;
- }
- FileSize -= Size;
- }
- //
- // Set file permissions.
- //
- SetupFileClose(DestinationFile);
- DestinationFile = NULL;
- Result = SetupFileSetAttributes(Destination,
- DestinationPath,
- ModificationDate,
- Mode);
- if (Result != 0) {
- fprintf(stderr,
- "Failed to set mode on file %s, ModData %llx Mode %x, "
- "Result %d\n",
- DestinationPath,
- (ULONGLONG)ModificationDate,
- Mode,
- Result);
- goto CopyFileEnd;
- }
- }
- CopyFileEnd:
- if (AppendedDestinationPath != NULL) {
- free(AppendedDestinationPath);
- }
- if (AppendedSourcePath != NULL) {
- free(AppendedSourcePath);
- }
- if (DestinationFile != NULL) {
- SetupFileClose(DestinationFile);
- }
- if (SourceFile != NULL) {
- SetupFileClose(SourceFile);
- }
- if (Enumeration != NULL) {
- free(Enumeration);
- }
- if (Buffer != NULL) {
- free(Buffer);
- }
- return Result;
- }
- INT
- SetupCreateAndWriteFile (
- PSETUP_CONTEXT Context,
- PVOID Destination,
- PCSTR DestinationPath,
- PVOID Contents,
- ULONG ContentsSize
- )
- /*++
- Routine Description:
- This routine creates a file and writes the given contents out to it.
- Arguments:
- Context - Supplies a pointer to the applicaton context.
- Destination - Supplies a pointer to the open destination volume
- handle.
- DestinationPath - Supplies a pointer to the path of the file to create at
- the destination.
- Contents - Supplies the buffer containing the file contents to write.
- ContentsSize - Supplies the size of the buffer in bytes.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PVOID DestinationFile;
- mode_t Mode;
- INT Status;
- size_t TotalWritten;
- ssize_t Written;
- Status = 0;
- Mode = FILE_PERMISSION_USER_READ |
- FILE_PERMISSION_USER_WRITE |
- FILE_PERMISSION_GROUP_READ |
- FILE_PERMISSION_GROUP_WRITE |
- FILE_PERMISSION_OTHER_READ;
- if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
- printf("Creating %s\n", DestinationPath);
- }
- SetupCreateDirectories(Context, Destination, DestinationPath);
- DestinationFile = SetupFileOpen(Destination,
- DestinationPath,
- O_CREAT | O_TRUNC | O_RDWR | O_NOFOLLOW,
- Mode);
- if (DestinationFile == NULL) {
- fprintf(stderr,
- "Failed to create destination file %s.\n",
- DestinationPath);
- goto CreateAndWriteFileEnd;
- }
- //
- // Loop copying chunks.
- //
- TotalWritten = 0;
- while (TotalWritten != ContentsSize) {
- Written = SetupFileWrite(DestinationFile,
- Contents + TotalWritten,
- ContentsSize - TotalWritten);
- if (Written <= 0) {
- fprintf(stderr,
- "Failed to write %s.\n",
- DestinationPath);
- Status = errno;
- goto CreateAndWriteFileEnd;
- }
- TotalWritten += Written;
- }
- CreateAndWriteFileEnd:
- if (DestinationFile != NULL) {
- SetupFileClose(DestinationFile);
- }
- return Status;
- }
- INT
- SetupCreateDirectories (
- PSETUP_CONTEXT Context,
- PVOID Volume,
- PCSTR Path
- )
- /*++
- Routine Description:
- This routine creates directories up to but not including the final
- component of the given path.
- Arguments:
- Context - Supplies a pointer to the applicaton context.
- Volume - Supplies a pointer to the open destination volume handle.
- Path - Supplies the full file path. The file itself won't be created, but
- all directories leading up to it will. If the path ends in a slash,
- all components will be created.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR Copy;
- ULONG Mode;
- PSTR Next;
- INT Status;
- Copy = strdup(Path);
- if (Copy == NULL) {
- return ENOMEM;
- }
- Status = 0;
- Mode = FILE_PERMISSION_USER_READ |
- FILE_PERMISSION_USER_WRITE |
- FILE_PERMISSION_USER_EXECUTE |
- FILE_PERMISSION_GROUP_READ |
- FILE_PERMISSION_GROUP_WRITE |
- FILE_PERMISSION_GROUP_EXECUTE |
- FILE_PERMISSION_OTHER_READ |
- FILE_PERMISSION_OTHER_EXECUTE;
- //
- // Get past any leading slashes.
- //
- Next = Copy;
- while (*Next == '/') {
- Next += 1;
- }
- while (TRUE) {
- while ((*Next != '\0') && (*Next != '/')) {
- Next += 1;
- }
- //
- // If the next character is the ending one, then this was the last
- // component. Don't create a directory for it.
- //
- if (*Next == '\0') {
- break;
- }
- //
- // Terminate the string and create the directory.
- //
- *Next = '\0';
- Status = SetupFileCreateDirectory(Volume, Copy, Mode);
- if (Status != 0) {
- fprintf(stderr,
- "Error: Cannot create directories for path %s: %s.\n",
- Copy,
- strerror(Status));
- goto CreateDirectoriesEnd;
- }
- *Next = '/';
- while (*Next == '/') {
- Next += 1;
- }
- }
- CreateDirectoriesEnd:
- if (Copy != NULL) {
- free(Copy);
- }
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|