[llvm-objcopy][NFC] refactor restoreStatOnFile out of llvm-objcopy.
authorAlexey Lapshin <a.v.lapshin@mail.ru>
Wed, 13 Apr 2022 20:40:27 +0000 (23:40 +0300)
committerAlexey Lapshin <a.v.lapshin@mail.ru>
Fri, 22 Apr 2022 17:06:01 +0000 (20:06 +0300)
Functionality of restoreStatOnFile may be reused. Move it into
FileUtilities.cpp. Create helper class FilePermissionsApplier
to store and apply permissions.

Differential Revision: https://reviews.llvm.org/D123821

llvm/include/llvm/Support/FileUtilities.h
llvm/lib/Support/FileUtilities.cpp
llvm/tools/llvm-objcopy/llvm-objcopy.cpp

index f8a37fe..0033638 100644 (file)
@@ -110,6 +110,27 @@ namespace llvm {
   llvm::Error
   writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
                       std::function<llvm::Error(llvm::raw_ostream &)> Writer);
+
+  /// FilePermssionsApplier helps to copy permissions from an input file to
+  /// an output one. It memorizes the status of the input file and can apply
+  /// permissions and dates to the output file.
+  class FilePermissionsApplier {
+  public:
+    static Expected<FilePermissionsApplier> create(StringRef InputFilename);
+
+    /// Apply stored permissions to the \p OutputFilename.
+    /// Copy LastAccess and ModificationTime if \p CopyDates is true.
+    /// Overwrite stored permissions if \p OverwritePermissions is specified.
+    Error apply(StringRef OutputFilename, bool CopyDates = false,
+                Optional<sys::fs::perms> OverwritePermissions = None);
+
+  private:
+    FilePermissionsApplier(StringRef InputFilename, sys::fs::file_status Status)
+        : InputFilename(InputFilename), InputStatus(Status) {}
+
+    StringRef InputFilename;
+    sys::fs::file_status InputStatus;
+  };
 } // End llvm namespace
 
 #endif
index 489b8d1..eda3eb0 100644 (file)
@@ -17,6 +17,7 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Process.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstdint>
 #include <cstdlib>
@@ -323,4 +324,69 @@ llvm::Error llvm::writeFileAtomically(
   return Error::success();
 }
 
+Expected<FilePermissionsApplier>
+FilePermissionsApplier::create(StringRef InputFilename) {
+  sys::fs::file_status Status;
+
+  if (InputFilename != "-") {
+    if (auto EC = sys::fs::status(InputFilename, Status))
+      return createFileError(InputFilename, EC);
+  } else {
+    Status.permissions(static_cast<sys::fs::perms>(0777));
+  }
+
+  return FilePermissionsApplier(InputFilename, Status);
+}
+
+Error FilePermissionsApplier::apply(
+    StringRef OutputFilename, bool CopyDates,
+    Optional<sys::fs::perms> OverwritePermissions) {
+  sys::fs::file_status Status = InputStatus;
+
+  if (OverwritePermissions)
+    Status.permissions(*OverwritePermissions);
+
+  int FD = 0;
+
+  // Writing to stdout should not be treated as an error here, just
+  // do not set access/modification times or permissions.
+  if (OutputFilename == "-")
+    return Error::success();
+
+  if (std::error_code EC = sys::fs::openFileForWrite(OutputFilename, FD,
+                                                     sys::fs::CD_OpenExisting))
+    return createFileError(OutputFilename, EC);
+
+  if (CopyDates)
+    if (std::error_code EC = sys::fs::setLastAccessAndModificationTime(
+            FD, Status.getLastAccessedTime(), Status.getLastModificationTime()))
+      return createFileError(OutputFilename, EC);
+
+  sys::fs::file_status OStat;
+  if (std::error_code EC = sys::fs::status(FD, OStat))
+    return createFileError(OutputFilename, EC);
+  if (OStat.type() == sys::fs::file_type::regular_file) {
+#ifndef _WIN32
+    // Keep ownership if llvm-objcopy is called under root.
+    if (OutputFilename == InputFilename && OStat.getUser() == 0)
+      sys::fs::changeFileOwnership(FD, Status.getUser(), Status.getGroup());
+#endif
+
+    sys::fs::perms Perm = Status.permissions();
+    if (OutputFilename != InputFilename)
+      Perm = static_cast<sys::fs::perms>(Perm & ~sys::fs::getUmask() & ~06000);
+#ifdef _WIN32
+    if (std::error_code EC = sys::fs::setPermissions(OutputFilename, Perm))
+#else
+    if (std::error_code EC = sys::fs::setPermissions(FD, Perm))
+#endif
+      return createFileError(OutputFilename, EC);
+  }
+
+  if (std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD))
+    return createFileError(OutputFilename, EC);
+
+  return Error::success();
+}
+
 char llvm::AtomicFileWriteError::ID;
index 0071266..2aaeea6 100644 (file)
@@ -41,6 +41,7 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/Memory.h"
@@ -131,66 +132,16 @@ static Error executeObjcopyOnRawBinary(ConfigManager &ConfigMgr,
   llvm_unreachable("unsupported output format");
 }
 
-static Error restoreStatOnFile(StringRef Filename,
-                               const sys::fs::file_status &Stat,
-                               const ConfigManager &ConfigMgr) {
-  int FD;
-  const CommonConfig &Config = ConfigMgr.getCommonConfig();
-
-  // Writing to stdout should not be treated as an error here, just
-  // do not set access/modification times or permissions.
-  if (Filename == "-")
-    return Error::success();
-
-  if (auto EC =
-          sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
-    return createFileError(Filename, EC);
-
-  if (Config.PreserveDates)
-    if (auto EC = sys::fs::setLastAccessAndModificationTime(
-            FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
-      return createFileError(Filename, EC);
-
-  sys::fs::file_status OStat;
-  if (std::error_code EC = sys::fs::status(FD, OStat))
-    return createFileError(Filename, EC);
-  if (OStat.type() == sys::fs::file_type::regular_file) {
-#ifndef _WIN32
-    // Keep ownership if llvm-objcopy is called under root.
-    if (Config.InputFilename == Config.OutputFilename && OStat.getUser() == 0)
-      sys::fs::changeFileOwnership(FD, Stat.getUser(), Stat.getGroup());
-#endif
-
-    sys::fs::perms Perm = Stat.permissions();
-    if (Config.InputFilename != Config.OutputFilename)
-      Perm = static_cast<sys::fs::perms>(Perm & ~sys::fs::getUmask() & ~06000);
-#ifdef _WIN32
-    if (auto EC = sys::fs::setPermissions(Filename, Perm))
-#else
-    if (auto EC = sys::fs::setPermissions(FD, Perm))
-#endif
-      return createFileError(Filename, EC);
-  }
-
-  if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
-    return createFileError(Filename, EC);
-
-  return Error::success();
-}
-
 /// The function executeObjcopy does the higher level dispatch based on the type
 /// of input (raw binary, archive or single object file) and takes care of the
 /// format-agnostic modifications, i.e. preserving dates.
 static Error executeObjcopy(ConfigManager &ConfigMgr) {
   CommonConfig &Config = ConfigMgr.Common;
 
-  sys::fs::file_status Stat;
-  if (Config.InputFilename != "-") {
-    if (auto EC = sys::fs::status(Config.InputFilename, Stat))
-      return createFileError(Config.InputFilename, EC);
-  } else {
-    Stat.permissions(static_cast<sys::fs::perms>(0777));
-  }
+  Expected<FilePermissionsApplier> PermsCarrier =
+      FilePermissionsApplier::create(Config.InputFilename);
+  if (!PermsCarrier)
+    return PermsCarrier.takeError();
 
   std::function<Error(raw_ostream & OutFile)> ObjcopyFunc;
 
@@ -259,14 +210,14 @@ static Error executeObjcopy(ConfigManager &ConfigMgr) {
     }
   }
 
-  if (Error E = restoreStatOnFile(Config.OutputFilename, Stat, ConfigMgr))
+  if (Error E =
+          PermsCarrier->apply(Config.OutputFilename, Config.PreserveDates))
     return E;
 
-  if (!Config.SplitDWO.empty()) {
-    Stat.permissions(static_cast<sys::fs::perms>(0666));
-    if (Error E = restoreStatOnFile(Config.SplitDWO, Stat, ConfigMgr))
+  if (!Config.SplitDWO.empty())
+    if (Error E = PermsCarrier->apply(Config.SplitDWO, Config.PreserveDates,
+                                      static_cast<sys::fs::perms>(0666)))
       return E;
-  }
 
   return Error::success();
 }