Index: include/llvm/Support/FileSystem.h =================================================================== --- include/llvm/Support/FileSystem.h +++ include/llvm/Support/FileSystem.h @@ -622,7 +622,8 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, OpenFlags Flags, unsigned Mode = 0666); -std::error_code openFileForRead(const Twine &Name, int &ResultFD); +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + SmallVectorImpl *RealPath = nullptr); /// @brief Identify the type of a binary file based on how magical it is. file_magic identify_magic(StringRef magic); Index: lib/Support/Unix/Path.inc =================================================================== --- lib/Support/Unix/Path.inc +++ lib/Support/Unix/Path.inc @@ -25,6 +25,9 @@ #if HAVE_FCNTL_H #include #endif +#ifdef HAVE_UNISTD_H +#include +#endif #ifdef HAVE_SYS_MMAN_H #include #endif @@ -47,6 +50,7 @@ #ifdef __APPLE__ #include +#include #endif // Both stdio.h and cstdio are included via different pathes and @@ -506,13 +510,66 @@ return std::error_code(); } -std::error_code openFileForRead(const Twine &Name, int &ResultFD) { +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + SmallVectorImpl *RealPath) { SmallString<128> Storage; StringRef P = Name.toNullTerminatedStringRef(Storage); while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) { if (errno != EINTR) return std::error_code(errno, std::generic_category()); } + // Attempt to get the real name of the file, if the user asked + if(!RealPath) + return std::error_code(); + RealPath->clear(); +#if 0 //__APPLE__ + // On MacOS, fgetattrlist is the most reliable way to get a properly-cased + // path. + // BUGBUG commented out since fgetattrlist/ATTR_CMN_NAME seems to only + // fetch the file *name* and not the path. + struct attrlist attrList; + memset(&attrList, 0, sizeof(attrList)); + attrList.bitmapcount = ATTR_BIT_MAP_COUNT; + attrList.commonattr = ATTR_CMN_NAME; + struct NameAttr { + u_int32_t totalByteCount; + struct attrreference attrRef; + char Name[NAME_MAX * 3 + 1]; // Large enough for NAME_MAX UTF8 characters + }; + union { + NameAttr nameAttr; + char Buffer[sizeof(nameAttr)]; + }; + if (fgetattrlist(ResultFD, &attrList, Buffer, sizeof(Buffer), 0) != -1) { + assert(nameAttr.attrRef.attr_dataoffset == sizeof(struct attrreference)); + if (0 < nameAttr.attrRef.attr_length) + RealPath->append(nameAttr.Name, + nameAttr.Name + nameAttr.attrRef.attr_length - 1); + } +#elif defined(F_GETPATH) + // When F_GETPATH is availble, it is the quickest way to get + // the real path name. + char Buffer[MAXPATHLEN]; + if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1) + RealPath->append(Buffer, Buffer + strlen(Buffer)); +#else + // If we have a /proc filesystem mounted, we ca quickly establish the + // real name of the file with readlink + static const bool HasProc = (0 == ::access("/proc/self/fd", R_OK)); + char Buffer[PATH_MAX]; + if (HasProc) { + SmallString<32> ProcPathStorage; + StringRef ProcPath = Twine("/proc/self/fd/").concat(ResultFD). + toNullTerminatedStringRef(ProcPathStorage); + ssize_t CharCount = ::readlink(ProcPath.begin(), Buffer, sizeof(Buffer)); + if (CharCount > 0) + RealPath->append(Buffer, Buffer + CharCount); + } else { + // Use ::realpath to get the real path name + if (::realpath(P.begin(), Buffer) != nullptr) + RealPath->append(Buffer, Buffer + strlen(Buffer)); + } +#endif return std::error_code(); } Index: lib/Support/Windows/Path.inc =================================================================== --- lib/Support/Windows/Path.inc +++ lib/Support/Windows/Path.inc @@ -663,7 +663,8 @@ return std::error_code(); } -std::error_code openFileForRead(const Twine &Name, int &ResultFD) { +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + SmallVectorImpl *RealPath) { SmallVector PathUTF16; if (std::error_code EC = widenPath(Name, PathUTF16)) @@ -692,6 +693,22 @@ return mapWindowsError(ERROR_INVALID_HANDLE); } + // Fetch the real name of the file, if the user asked + if (RealPath) { + RealPath->clear(); + wchar_t RealPathUTF16[MAX_PATH]; + DWORD CountChars = + ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH, + FILE_NAME_NORMALIZED); + if (CountChars > 0 && CountChars < MAX_PATH) { + // Convert the result from UTF-16 to UTF-8. + SmallString RealPathUTF8; + if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8)) + RealPath->append(RealPathUTF8.data(), + RealPathUTF8.data() + strlen(RealPathUTF8.data())); + } + } + ResultFD = FD; return std::error_code(); }