diff options
Diffstat (limited to 'llvm/lib/Support/Unix/Path.inc')
| -rw-r--r-- | llvm/lib/Support/Unix/Path.inc | 136 |
1 files changed, 113 insertions, 23 deletions
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc index 77f3f54bd881..c37b3a54644a 100644 --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -50,6 +50,7 @@ extern char **environ; #elif defined(__DragonFly__) #include <sys/mount.h> #elif defined(__MVS__) +#include "llvm/Support/AutoConvert.h" #include <sys/ps.h> #endif @@ -208,8 +209,11 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { // to the file. char exe_path[PATH_MAX]; #if __FreeBSD_version >= 1300057 - if (elf_aux_info(AT_EXECPATH, exe_path, sizeof(exe_path)) == 0) - return exe_path; + if (elf_aux_info(AT_EXECPATH, exe_path, sizeof(exe_path)) == 0) { + char link_path[PATH_MAX]; + if (realpath(exe_path, link_path)) + return link_path; + } #else // elf_aux_info(AT_EXECPATH, ... is not available in all supported versions, // fall back to finding the ELF auxiliary vectors after the process's @@ -218,9 +222,12 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { while (*p++ != 0) ; // Iterate through auxiliary vectors for AT_EXECPATH. - for (; *(uintptr_t *)p != AT_NULL; p++) { - if (*(uintptr_t *)p++ == AT_EXECPATH) - return *p; + for (Elf_Auxinfo *aux = (Elf_Auxinfo *)p; aux->a_type != AT_NULL; aux++) { + if (aux->a_type == AT_EXECPATH) { + char link_path[PATH_MAX]; + if (realpath((char *)aux->a_un.a_ptr, link_path)) + return link_path; + } } #endif // Fall back to argv[0] if auxiliary vectors are not available. @@ -815,6 +822,9 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); +#if defined(MAP_NORESERVE) + flags |= MAP_NORESERVE; +#endif #if defined(__APPLE__) //---------------------------------------------------------------------- // Newer versions of MacOSX have a flag that will allow us to read from @@ -843,33 +853,18 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, uint64_t offset, std::error_code &ec) - : Size(length), Mapping(), Mode(mode) { + : Size(length), Mode(mode) { (void)Mode; ec = init(fd, offset, mode); if (ec) - Mapping = nullptr; + copyFrom(mapped_file_region()); } -mapped_file_region::~mapped_file_region() { +void mapped_file_region::unmapImpl() { if (Mapping) ::munmap(Mapping, Size); } -size_t mapped_file_region::size() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Size; -} - -char *mapped_file_region::data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<char*>(Mapping); -} - -const char *mapped_file_region::const_data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<const char*>(Mapping); -} - int mapped_file_region::alignment() { return Process::getPageSizeEstimate(); } @@ -971,8 +966,13 @@ static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags, // Nothing special, just don't add O_CREAT and we get these semantics. } +// Using append mode with z/OS UTF-8 auto-conversion results in EINVAL when +// calling write(). Instead we need to use lseek() to set offset to EOF after +// open(). +#ifndef __MVS__ if (Flags & OF_Append) Result |= O_APPEND; +#endif #ifdef O_CLOEXEC if (!(Flags & OF_ChildInherit)) @@ -1001,6 +1001,88 @@ std::error_code openFile(const Twine &Name, int &ResultFD, assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); } #endif + +#ifdef __MVS__ + /* Reason about auto-conversion and file tags. Setting the file tag only + * applies if file is opened in write mode: + * + * Text file: + * File exists File created + * CD_CreateNew n/a conv: on + * tag: set 1047 + * CD_CreateAlways conv: auto conv: on + * tag: auto 1047 tag: set 1047 + * CD_OpenAlways conv: auto conv: on + * tag: auto 1047 tag: set 1047 + * CD_OpenExisting conv: auto n/a + * tag: unchanged + * + * Binary file: + * File exists File created + * CD_CreateNew n/a conv: off + * tag: set binary + * CD_CreateAlways conv: off conv: off + * tag: auto binary tag: set binary + * CD_OpenAlways conv: off conv: off + * tag: auto binary tag: set binary + * CD_OpenExisting conv: off n/a + * tag: unchanged + * + * Actions: + * conv: off -> auto-conversion is turned off + * conv: on -> auto-conversion is turned on + * conv: auto -> auto-conversion is turned on if the file is untagged + * tag: set 1047 -> set the file tag to text encoded in 1047 + * tag: set binary -> set the file tag to binary + * tag: auto 1047 -> set file tag to 1047 if not set + * tag: auto binary -> set file tag to binary if not set + * tag: unchanged -> do not care about the file tag + * + * It is not possible to distinguish between the cases "file exists" and + * "file created". In the latter case, the file tag is not set and the file + * size is zero. The decision table boils down to: + * + * the file tag is set if + * - the file is opened for writing + * - the create disposition is not equal to CD_OpenExisting + * - the file tag is not set + * - the file size is zero + * + * This only applies if the file is a regular file. E.g. enabling + * auto-conversion for reading from /dev/null results in error EINVAL when + * calling read(). + * + * Using append mode with z/OS UTF-8 auto-conversion results in EINVAL when + * calling write(). Instead we need to use lseek() to set offset to EOF after + * open(). + */ + if ((Flags & OF_Append) && lseek(ResultFD, 0, SEEK_END) == -1) + return std::error_code(errno, std::generic_category()); + struct stat Stat; + if (fstat(ResultFD, &Stat) == -1) + return std::error_code(errno, std::generic_category()); + if (S_ISREG(Stat.st_mode)) { + bool DoSetTag = (Access & FA_Write) && (Disp != CD_OpenExisting) && + !Stat.st_tag.ft_txtflag && !Stat.st_tag.ft_ccsid && + Stat.st_size == 0; + if (Flags & OF_Text) { + if (auto EC = llvm::enableAutoConversion(ResultFD)) + return EC; + if (DoSetTag) { + if (auto EC = llvm::setFileTag(ResultFD, CCSID_IBM_1047, true)) + return EC; + } + } else { + if (auto EC = llvm::disableAutoConversion(ResultFD)) + return EC; + if (DoSetTag) { + if (auto EC = llvm::setFileTag(ResultFD, FT_BINARY, false)) + return EC; + } + } + } +#endif + return std::error_code(); } @@ -1211,6 +1293,14 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, return std::error_code(); } +std::error_code changeFileOwnership(int FD, uint32_t Owner, uint32_t Group) { + auto FChown = [&]() { return ::fchown(FD, Owner, Group); }; + // Retry if fchown call fails due to interruption. + if ((sys::RetryAfterSignal(-1, FChown)) < 0) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + } // end namespace fs namespace path { |
