123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954 |
- /*++
- 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:
- io.c
- Abstract:
- This module implements support for doing I/O on a Windows host in the setup
- application.
- Author:
- Evan Green 8-Oct-2014
- Environment:
- User
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Use CRT 6.1 for stat64.
- //
- #define __MSVCRT_VERSION__ 0x0601
- #include <assert.h>
- #include <dirent.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 <utime.h>
- #include <unistd.h>
- #include "../setup.h"
- #include "win32sup.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define some executable file magic words.
- //
- #define ELF_MAGIC 0x464C457F
- #define IMAGE_DOS_SIGNATURE 0x5A4D
- #define SCRIPT_SHEBANG 0x2123
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure describes a handle to an I/O object in the setup app.
- Members:
- Handle - Stores the device handle.
- WinHandle - Stores the Windows handle.
- --*/
- typedef struct _SETUP_OS_HANDLE {
- int Handle;
- void *WinHandle;
- } SETUP_OS_HANDLE, *PSETUP_OS_HANDLE;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // -------------------------------------------------------------------- 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.
- --*/
- {
- return ENOSYS;
- }
- 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.
- --*/
- {
- return -1;
- }
- 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.
- --*/
- {
- PSETUP_OS_HANDLE IoHandle;
- PSTR PathCopy;
- size_t PathLength;
- struct stat Stat;
- IoHandle = malloc(sizeof(SETUP_OS_HANDLE));
- if (IoHandle == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- IoHandle->Handle = -1;
- IoHandle->WinHandle = NULL;
- if (Destination->Path != NULL) {
- IoHandle->Handle = open(Destination->Path,
- Flags | O_BINARY,
- CreatePermissions);
- if (IoHandle->Handle < 0) {
- //
- // Windows doesn't allow opening directories. Make the error
- // unambiguous if this is a directory.
- //
- if ((stat(Destination->Path, &Stat) == 0) &&
- (S_ISDIR(Stat.st_mode))) {
- errno = EISDIR;
- } else {
- //
- // Windows doesn't allow opening a path with a slash on the
- // end. If the non-slash version works, then the error is it's
- // a directory.
- //
- PathLength = strlen(Destination->Path);
- if ((PathLength != 0) &&
- (Destination->Path[PathLength - 1] == '/')) {
- PathCopy = strdup(Destination->Path);
- if (PathCopy == NULL) {
- free(IoHandle);
- return NULL;
- }
- while ((PathLength > 1) &&
- (PathCopy[PathLength - 1] == '/')) {
- PathCopy[PathLength - 1] = '\0';
- PathLength -= 1;
- }
- if ((stat(PathCopy, &Stat) == 0) &&
- (S_ISDIR(Stat.st_mode))) {
- errno = EISDIR;
- }
- free(PathCopy);
- }
- }
- free(IoHandle);
- return NULL;
- }
- } else {
- IoHandle->WinHandle = SetupWin32OpenDeviceId(Destination->DeviceId);
- if (IoHandle->WinHandle == NULL) {
- free(IoHandle);
- return NULL;
- }
- }
- return IoHandle;
- }
- VOID
- SetupOsClose (
- PVOID Handle
- )
- /*++
- Routine Description:
- This routine closes a handle.
- Arguments:
- Handle - Supplies a pointer to the destination to open.
- Return Value:
- None.
- --*/
- {
- PSETUP_OS_HANDLE IoHandle;
- IoHandle = Handle;
- if (IoHandle->WinHandle != NULL) {
- SetupWin32Close(IoHandle->WinHandle);
- }
- if (IoHandle->Handle >= 0) {
- close(IoHandle->Handle);
- }
- free(IoHandle);
- 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 BytesCompleted;
- PSETUP_OS_HANDLE IoHandle;
- ssize_t TotalBytesRead;
- IoHandle = Handle;
- if (IoHandle->WinHandle != NULL) {
- return SetupWin32Read(IoHandle->WinHandle, Buffer, ByteCount);
- }
- TotalBytesRead = 0;
- while (ByteCount != 0) {
- BytesCompleted = read(IoHandle->Handle, Buffer, ByteCount);
- if (BytesCompleted <= 0) {
- break;
- }
- Buffer += BytesCompleted;
- TotalBytesRead += BytesCompleted;
- ByteCount -= BytesCompleted;
- }
- return TotalBytesRead;
- }
- 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 BytesCompleted;
- PSETUP_OS_HANDLE IoHandle;
- ssize_t TotalBytesWritten;
- IoHandle = Handle;
- if (IoHandle->WinHandle != NULL) {
- return SetupWin32Write(IoHandle->WinHandle, Buffer, ByteCount);
- }
- TotalBytesWritten = 0;
- while (ByteCount != 0) {
- BytesCompleted = write(IoHandle->Handle, Buffer, ByteCount);
- if (BytesCompleted <= 0) {
- perror("Write failed");
- break;
- }
- Buffer += BytesCompleted;
- TotalBytesWritten += BytesCompleted;
- ByteCount -= BytesCompleted;
- }
- return TotalBytesWritten;
- }
- 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.
- --*/
- {
- PSETUP_OS_HANDLE IoHandle;
- LONGLONG NewOffset;
- IoHandle = Handle;
- if (IoHandle->WinHandle != NULL) {
- return SetupWin32Seek(IoHandle->WinHandle, Offset);
- }
- NewOffset = _lseeki64(IoHandle->Handle, Offset, SEEK_SET);
- return NewOffset;
- }
- 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.
- --*/
- {
- PSETUP_OS_HANDLE IoHandle;
- ULONGLONG NewOffset;
- IoHandle = Handle;
- if (IoHandle->WinHandle != NULL) {
- return SetupWin32Tell(IoHandle->WinHandle);
- }
- NewOffset = _lseeki64(IoHandle->Handle, 0, SEEK_CUR);
- return NewOffset;
- }
- 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.
- --*/
- {
- PSETUP_OS_HANDLE IoHandle;
- int Result;
- struct __stat64 Stat;
- IoHandle = Handle;
- if (IoHandle->WinHandle != NULL) {
- if ((ModificationDate != NULL) || (Mode != NULL)) {
- fprintf(stderr,
- "Error: Modification date and mode cannot be read from a "
- "device.\n");
- return ENOSYS;
- }
- if (FileSize == NULL) {
- return 0;
- }
- return SetupWin32FileStat(IoHandle->WinHandle, FileSize);
- }
- Result = _fstat64(IoHandle->Handle, &Stat);
- if (Result != 0) {
- return Result;
- }
- if (FileSize != NULL) {
- *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.
- --*/
- {
- PSETUP_OS_HANDLE IoHandle;
- int Result;
- IoHandle = Handle;
- Result = ftruncate(IoHandle->Handle, NewSize);
- 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;
- size_t NameSize;
- PVOID NewBuffer;
- size_t NewCapacity;
- INT Result;
- struct dirent *ResultPointer;
- 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) {
- ResultPointer = readdir(Directory);
- if (ResultPointer == NULL) {
- NameSize = 1;
- } else {
- if ((strcmp(ResultPointer->d_name, ".") == 0) ||
- (strcmp(ResultPointer->d_name, "..") == 0)) {
- continue;
- }
- NameSize = strlen(ResultPointer->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 (ResultPointer == NULL) {
- strcpy(Array + UsedSize, "");
- UsedSize += 1;
- break;
- } else {
- strcpy(Array + UsedSize, ResultPointer->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);
- 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.
- --*/
- {
- ssize_t BytesRead;
- BOOL Executable;
- PSETUP_OS_HANDLE IoHandle;
- PSTR LastDot;
- off_t Offset;
- ULONG Word;
- Executable = FALSE;
- IoHandle = Handle;
- //
- // First try to guess based on the name.
- //
- LastDot = strrchr(Path, '.');
- if (LastDot != NULL) {
- LastDot += 1;
- if ((strcmp(LastDot, "sh") == 0) ||
- (strcmp(LastDot, "exe") == 0)) {
- Executable = TRUE;
- }
- }
- if (Executable == FALSE) {
- //
- // Go to the beginning of the file and read the first word.
- //
- Offset = lseek(IoHandle->Handle, 0, SEEK_CUR);
- lseek(IoHandle->Handle, 0, SEEK_SET);
- Word = 0;
- do {
- BytesRead = read(IoHandle->Handle, &Word, sizeof(Word));
- } while ((BytesRead < 0) && (errno == EINTR));
- if (BytesRead > 0) {
- if (Word == ELF_MAGIC) {
- Executable = TRUE;
- } else {
- //
- // Now just look at the first two bytes.
- //
- Word &= 0x0000FFFF;
- if ((Word == IMAGE_DOS_SIGNATURE) ||
- (Word == SCRIPT_SHEBANG)) {
- Executable = TRUE;
- }
- }
- }
- //
- // Restore the previous offset.
- //
- lseek(IoHandle->Handle, Offset, SEEK_SET);
- }
- if (Executable != FALSE) {
- *Mode |= FILE_PERMISSION_ALL_EXECUTE;
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|