123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861 |
- /*++
- Copyright (c) 2016 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:
- io.c
- Abstract:
- This module implements support for doing I/O on generic POSIX systems in
- the setup application.
- Author:
- Evan Green 19-Jan-2016
- Environment:
- User
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #define _FILE_OFFSET_BITS 64
- #include <assert.h>
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include <time.h>
- #include <unistd.h>
- #include <utime.h>
- #if defined(__APPLE__) || defined(__FreeBSD__)
- #include <sys/disk.h>
- #endif
- #if defined(__linux__)
- #include <sys/mount.h>
- #endif
- #include "../setup.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- INT
- SetupOsGetBlockDeviceSize (
- INT Descriptor,
- PULONGLONG Size
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- SetupOsReadLink (
- PSTR Path,
- PSTR *LinkTarget,
- INT *LinkTargetSize
- )
- /*++
- Routine Description:
- This routine attempts to read a symbolic link.
- Arguments:
- 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:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- int Size;
- *LinkTarget = malloc(SETUP_SYMLINK_MAX);
- if (*LinkTarget == NULL) {
- return errno;
- }
- Size = readlink(Path, *LinkTarget, SETUP_SYMLINK_MAX - 1);
- if (Size < 0) {
- free(*LinkTarget);
- *LinkTarget = NULL;
- return errno;
- }
- (*LinkTarget)[Size] = '\0';
- *LinkTargetSize = Size;
- return 0;
- }
- INT
- SetupOsSymlink (
- PSTR Path,
- PSTR LinkTarget,
- INT LinkTargetSize
- )
- /*++
- Routine Description:
- This routine creates a symbolic link.
- Arguments:
- 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.
- --*/
- {
- INT Result;
- //
- // Create the symlink. If it already exists, attempt to unlink that file
- // and create a new one.
- //
- Result = symlink(LinkTarget, Path);
- if ((Result < 0) && (errno == EEXIST)) {
- if (unlink(LinkTarget) == 0) {
- Result = symlink(LinkTarget, Path);
- }
- }
- return Result;
- }
- PVOID
- SetupOsOpenDestination (
- PSETUP_DESTINATION Destination,
- INT Flags,
- INT CreatePermissions
- )
- /*++
- Routine Description:
- This routine opens a handle to a given destination.
- Arguments:
- Destination - Supplies a pointer to the destination 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.
- --*/
- {
- int Descriptor;
- if (Destination->Path == NULL) {
- fprintf(stderr, "Error: Device ID paths not supported.\n");
- errno = ENOENT;
- return NULL;
- }
- Descriptor = open(Destination->Path, Flags, CreatePermissions);
- if (Descriptor == -1) {
- return NULL;
- }
- return (PVOID)(INTN)Descriptor;
- }
- VOID
- SetupOsClose (
- PVOID Handle
- )
- /*++
- Routine Description:
- This routine closes a handle.
- Arguments:
- Handle - Supplies a pointer to the destination to open.
- Return Value:
- None.
- --*/
- {
- close((INTN)Handle);
- return;
- }
- ssize_t
- SetupOsRead (
- PVOID Handle,
- void *Buffer,
- size_t ByteCount
- )
- /*++
- Routine Description:
- This routine reads from an open handle.
- 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.
- -1 on failure.
- --*/
- {
- ssize_t BytesRead;
- do {
- BytesRead = read((INTN)Handle, Buffer, ByteCount);
- } while ((BytesRead < 0) && (errno == EINTR));
- return BytesRead;
- }
- ssize_t
- SetupOsWrite (
- PVOID Handle,
- void *Buffer,
- size_t ByteCount
- )
- /*++
- Routine Description:
- This routine writes data to an open 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.
- --*/
- {
- ssize_t BytesWritten;
- do {
- BytesWritten = write((INTN)Handle, Buffer, ByteCount);
- } while ((BytesWritten < 0) && (errno == EINTR));
- return BytesWritten;
- }
- LONGLONG
- SetupOsSeek (
- PVOID Handle,
- LONGLONG Offset
- )
- /*++
- Routine Description:
- This routine seeks in the current file or device.
- 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.
- --*/
- {
- return lseek((INTN)Handle, Offset, SEEK_SET);
- }
- LONGLONG
- SetupOsTell (
- PVOID Handle
- )
- /*++
- Routine Description:
- This routine returns the current offset in the given file or device.
- Arguments:
- Handle - Supplies the handle.
- Return Value:
- Returns the file offset on success.
- -1 on failure, and errno will contain more information. The file offset
- will remain unchanged.
- --*/
- {
- return lseek((INTN)Handle, 0, SEEK_CUR);
- }
- INT
- SetupOsFstat (
- 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.
- --*/
- {
- int Result;
- struct stat Stat;
- Result = fstat((INTN)Handle, &Stat);
- if (Result != 0) {
- return Result;
- }
- if (FileSize != NULL) {
- if (S_ISBLK(Stat.st_mode)) {
- Result = SetupOsGetBlockDeviceSize((INTN)Handle, FileSize);
- if (Result != 0) {
- return Result;
- }
- } else {
- *FileSize = Stat.st_size;
- }
- }
- if (ModificationDate != NULL) {
- *ModificationDate = Stat.st_mtime;
- }
- if (Mode != NULL) {
- *Mode = Stat.st_mode;
- }
- return Result;
- }
- INT
- SetupOsFtruncate (
- 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.
- --*/
- {
- int Result;
- Result = ftruncate((INTN)Handle, NewSize);
- if (Result != 0) {
- return Result;
- }
- return Result;
- }
- INT
- SetupOsEnumerateDirectory (
- PVOID Handle,
- PSTR DirectoryPath,
- PSTR *Enumeration
- )
- /*++
- Routine Description:
- This routine enumerates the contents of a given directory.
- Arguments:
- Handle - 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;
- DIR *Directory;
- struct dirent *DirectoryEntry;
- size_t NameSize;
- PVOID NewBuffer;
- size_t NewCapacity;
- INT Result;
- size_t UsedSize;
- Array = NULL;
- ArrayCapacity = 0;
- Directory = NULL;
- UsedSize = 0;
- Directory = opendir(DirectoryPath);
- if (Directory == NULL) {
- Result = errno;
- goto OsEnumerateDirectoryEnd;
- }
- //
- // Loop reading directory entries.
- //
- while (TRUE) {
- errno = 0;
- DirectoryEntry = readdir(Directory);
- if (DirectoryEntry == NULL) {
- if (errno != 0) {
- Result = errno;
- goto OsEnumerateDirectoryEnd;
- }
- NameSize = 1;
- } else {
- if ((strcmp(DirectoryEntry->d_name, ".") == 0) ||
- (strcmp(DirectoryEntry->d_name, "..") == 0)) {
- continue;
- }
- NameSize = strlen(DirectoryEntry->d_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 OsEnumerateDirectoryEnd;
- }
- Array = NewBuffer;
- ArrayCapacity = NewCapacity;
- }
- //
- // Copy the entry (or an empty file if this is the end).
- //
- if (DirectoryEntry == NULL) {
- strcpy(Array + UsedSize, "");
- UsedSize += 1;
- break;
- } else {
- strcpy(Array + UsedSize, DirectoryEntry->d_name);
- UsedSize += NameSize;
- }
- }
- Result = 0;
- OsEnumerateDirectoryEnd:
- if (Directory != NULL) {
- closedir(Directory);
- }
- if (Result != 0) {
- if (Array != NULL) {
- free(Array);
- Array = NULL;
- }
- }
- *Enumeration = Array;
- return Result;
- }
- INT
- SetupOsCreateDirectory (
- PSTR Path,
- mode_t Permissions
- )
- /*++
- Routine Description:
- This routine creates a new directory.
- Arguments:
- 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.
- --*/
- {
- INT Result;
- Result = mkdir(Path, Permissions);
- if (Result != 0) {
- Result = errno;
- if (Result == 0) {
- Result = -1;
- }
- }
- return Result;
- }
- INT
- SetupOsSetAttributes (
- PSTR Path,
- time_t ModificationDate,
- mode_t Permissions
- )
- /*++
- Routine Description:
- This routine sets attributes on a given path.
- Arguments:
- 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.
- --*/
- {
- INT Result;
- struct utimbuf Times;
- Times.actime = time(NULL);
- Times.modtime = ModificationDate;
- Result = utime(Path, &Times);
- if (Result != 0) {
- Result = errno;
- return Result;
- }
- Result = chmod(Path, Permissions);
- if (Result != 0) {
- Result = errno;
- return Result;
- }
- return 0;
- }
- VOID
- SetupOsDetermineExecuteBit (
- 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.
- --*/
- {
- //
- // Since POSIX systems have support for executable bits, don't screw with
- // the permissions that are already set.
- //
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- INT
- SetupOsGetBlockDeviceSize (
- INT Descriptor,
- PULONGLONG Size
- )
- /*++
- Routine Description:
- This routine gets the size of the open block device size.
- Arguments:
- Descriptor - Supplies the open file descriptor.
- Size - Supplies a pointer where the block device size will be returned on
- success.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- //
- // The IOCTL for Apple devices.
- //
- #ifdef DKIOCGETBLOCKCOUNT
- if (ioctl(Descriptor, DKIOCGETBLOCKCOUNT, Size) >= 0) {
- *Size *= 512;
- return 0;
- }
- #endif
- //
- // The IOCTLs for Linux devices.
- //
- #ifdef BLKGETSIZE64
- if (ioctl(Descriptor, BLKGETSIZE64, Size) >= 0) {
- return 0;
- }
- #endif
- #ifdef BLKGETSIZE
- if (ioctl(Descriptor, BLKGETSIZE, Size) >= 0) {
- *Size *= 512;
- return 0;
- }
- #endif
- //
- // The IOCTL for FreeBSD.
- //
- #ifdef DIOCGMEDIASIZE
- if (ioctl(Descriptor, DIOCGMEDIASIZE, Size) >= 0) {
- return 0;
- }
- #endif
- return ENOSYS;
- }
|