diff --git a/llvm/include/llvm/Support/AutoConvert.h b/llvm/include/llvm/Support/AutoConvert.h index 6f45c4683f777..a1577713f1b65 100644 --- a/llvm/include/llvm/Support/AutoConvert.h +++ b/llvm/include/llvm/Support/AutoConvert.h @@ -52,6 +52,9 @@ std::error_code restorezOSStdHandleAutoConversion(int FD); /// \brief Set the tag information for a file descriptor. std::error_code setzOSFileTag(int FD, int CCSID, bool Text); +// Query the file tag to determine if the file is a text file. +bool iszOSTextFile(const char *Filename, const int FD = -1); + } // namespace llvm #endif // __cplusplus diff --git a/llvm/lib/Support/AutoConvert.cpp b/llvm/lib/Support/AutoConvert.cpp index 66570735f8fc8..47cf839bfa39c 100644 --- a/llvm/lib/Support/AutoConvert.cpp +++ b/llvm/lib/Support/AutoConvert.cpp @@ -116,4 +116,30 @@ std::error_code llvm::setzOSFileTag(int FD, int CCSID, bool Text) { return std::error_code(); } +ErrorOr<__ccsid_t> getzOSFileTag(const char *FileName, const int FD) { + // If we have a file descriptor, use it to find out file tagging. Otherwise we + // need to use stat() with the file path. + if (FD != -1) { + struct f_cnvrt Query = { + QUERYCVT, // cvtcmd + 0, // pccsid + 0, // fccsid + }; + if (fcntl(FD, F_CONTROL_CVT, &Query) == -1) + return std::error_code(errno, std::generic_category()); + return Query.fccsid; + } + struct stat Attr; + if (stat(FileName, &Attr) == -1) + return std::error_code(errno, std::generic_category()); + return Attr.st_tag.ft_ccsid; +} + +bool llvm::iszOSTextFile(const char *Filename, const int FD) { + ErrorOr<__ccsid_t> Ccsid = getzOSFileTag(Filename, FD); + if (std::error_code EC = Ccsid.getError()) + return false; + return *Ccsid != FT_BINARY; +} + #endif // __MVS__ diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index 928c0b5a24ed6..d9df9c951d4bb 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -325,8 +325,14 @@ ErrorOr RealFileSystem::status(const Twine &Path) { ErrorOr> RealFileSystem::openFileForRead(const Twine &Name) { SmallString<256> RealName, Storage; + auto OpenFlags = sys::fs::OF_None; +#ifdef __MVS__ + // If the file is tagged with a text ccsid, it may require autoconversion. + if (llvm::iszOSTextFile(Name.str().c_str())) + OpenFlags |= sys::fs::OF_Text; +#endif Expected FDOrErr = sys::fs::openNativeFileForRead( - adjustPath(Name, Storage), sys::fs::OF_None, &RealName); + adjustPath(Name, Storage), OpenFlags, &RealName); if (!FDOrErr) return errorToErrorCode(FDOrErr.takeError()); return std::unique_ptr(