diff --git a/llvm/include/llvm/Support/FileSystem.h b/llvm/include/llvm/Support/FileSystem.h --- a/llvm/include/llvm/Support/FileSystem.h +++ b/llvm/include/llvm/Support/FileSystem.h @@ -1159,6 +1159,17 @@ /// means that the filesystem may have failed to perform some buffered writes. std::error_code closeFile(file_t &F); +#ifdef LLVM_ON_UNIX +/// @brief Change ownership of a file +/// +/// @param Owner The owner of the file to change to +/// @param Group The group of the file to change to +/// @returns errc::success if successfully updated file ownership, otherwise an +/// error code is returned. +std::error_code changeFileOwnership(const Twine &Name, uint32_t Owner, + uint32_t Group); +#endif + /// RAII class that facilitates file locking. class FileLocker { int FD; ///< Locked file handle. diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -1213,6 +1213,17 @@ return std::error_code(); } +std::error_code changeFileOwnership(const Twine &Name, uint32_t Owner, uint32_t Group) { + int FD; + if (std::error_code EC = sys::fs::openFileForWrite(Name, FD, sys::fs::CD_OpenExisting)) + return EC; + auto Chown = [&]() { return fchown(FD, Owner, Group); }; + if ((sys::RetryAfterSignal(-1, Chown)) < 0) + return std::error_code(errno, std::generic_category()); + if (std::error_code EC = sys::fs::closeFile(FD)) + return EC; +} + } // end namespace fs namespace path { diff --git a/llvm/test/tools/llvm-objcopy/tool-ownership.s b/llvm/test/tools/llvm-objcopy/tool-ownership.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/tool-ownership.s @@ -0,0 +1,11 @@ +# RUN: llvm-mc -triple=i386 %s -filetype=obj -o %t +# RUN: sudo llvm-strip %t -o %t1 +# RUN: ls -l %t1 | FileCheck --strict-whitespace --check-prefix=STRIP-NEW %s +# RUN: sudo llvm-strip %t +# RUN: ls -l %t | FileCheck --strict-whitespace --check-prefix=STRIP-OVERWRITE -DUSER=$(stat -c '%U' %s) -DGROUP=$(stat -c '%G' %s) %s +# RUN: sudo llvm-objcopy %t +# RUN: ls -l %t | FileCheck --strict-whitespace --check-prefix=OBJCOPY-OVERWRITE -DUSER=$(stat -c '%U' %s) -DGROUP=$(stat -c '%G' %s) %s +nop +# STRIP-NEW: root root +# STRIP-OVERWRITE: [[USER]] [[GROUP]] +# OBJCOPY-OVERWRITE: [[USER]] [[GROUP]] diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -328,6 +328,20 @@ return E; } +#if !defined(_WIN32) || defined(__CYGWIN32__) + // Preserve the ownership if the input file is overwritten + if (Config.InputFilename != "-" && + Config.InputFilename == Config.OutputFilename) { + sys::fs::file_status OStat; + if (std::error_code EC = sys::fs::status(Config.OutputFilename, OStat)) + return createFileError(Config.OutputFilename, EC); + if (Stat.getUser() != OStat.getUser() || + Stat.getGroup() != OStat.getGroup()) + sys::fs::changeFileOwnership(Config.OutputFilename, Stat.getUser(), + Stat.getGroup()); + } +#endif + return Error::success(); }