LCOV - code coverage report
Current view: top level - lib/Support - FileOutputBuffer.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 47 49 95.9 %
Date: 2017-09-14 15:23:50 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- FileOutputBuffer.cpp - File Output Buffer ----------------*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // Utility for creating a in-memory buffer that will be written to a file.
      11             : //
      12             : //===----------------------------------------------------------------------===//
      13             : 
      14             : #include "llvm/Support/FileOutputBuffer.h"
      15             : #include "llvm/ADT/STLExtras.h"
      16             : #include "llvm/ADT/SmallString.h"
      17             : #include "llvm/Support/Errc.h"
      18             : #include "llvm/Support/Path.h"
      19             : #include "llvm/Support/Signals.h"
      20             : #include <system_error>
      21             : 
      22             : #if !defined(_MSC_VER) && !defined(__MINGW32__)
      23             : #include <unistd.h>
      24             : #else
      25             : #include <io.h>
      26             : #endif
      27             : 
      28             : using llvm::sys::fs::mapped_file_region;
      29             : 
      30             : namespace llvm {
      31        3627 : FileOutputBuffer::FileOutputBuffer(std::unique_ptr<mapped_file_region> R,
      32             :                                    StringRef Path, StringRef TmpPath,
      33        3627 :                                    bool IsRegular)
      34        3627 :     : Region(std::move(R)), FinalPath(Path), TempPath(TmpPath),
      35       14508 :       IsRegular(IsRegular) {}
      36             : 
      37       14508 : FileOutputBuffer::~FileOutputBuffer() {
      38             :   // Close the mapping before deleting the temp file, so that the removal
      39             :   // succeeds.
      40        7254 :   Region.reset();
      41        7254 :   sys::fs::remove(Twine(TempPath));
      42        3627 : }
      43             : 
      44             : ErrorOr<std::unique_ptr<FileOutputBuffer>>
      45        3638 : FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) {
      46             :   // Check file is not a regular file, in which case we cannot remove it.
      47        3638 :   sys::fs::file_status Stat;
      48        3638 :   std::error_code EC = sys::fs::status(FilePath, Stat);
      49        3638 :   bool IsRegular = true;
      50        3638 :   switch (Stat.type()) {
      51             :     case sys::fs::file_type::file_not_found:
      52             :       // If file does not exist, we'll create one.
      53             :       break;
      54             :     case sys::fs::file_type::regular_file: {
      55             :         // If file is not currently writable, error out.
      56             :         // FIXME: There is no sys::fs:: api for checking this.
      57             :         // FIXME: In posix, you use the access() call to check this.
      58             :       }
      59             :       break;
      60           2 :     case sys::fs::file_type::directory_file:
      61             :       return errc::is_a_directory;
      62          10 :     default:
      63          10 :       if (EC)
      64             :         return EC;
      65             :       IsRegular = false;
      66             :   }
      67             : 
      68             :   if (IsRegular) {
      69             :     // Delete target file.
      70        3626 :     EC = sys::fs::remove(FilePath);
      71        3626 :     if (EC)
      72             :       return EC;
      73             :   }
      74             : 
      75        7266 :   SmallString<128> TempFilePath;
      76             :   int FD;
      77        3633 :   if (IsRegular) {
      78        3626 :     unsigned Mode = sys::fs::all_read | sys::fs::all_write;
      79             :     // If requested, make the output file executable.
      80        3626 :     if (Flags & F_executable)
      81        1852 :       Mode |= sys::fs::all_exe;
      82             :     // Create new file in same directory but with random name.
      83       10878 :     EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD,
      84             :                                    TempFilePath, Mode);
      85             :   } else {
      86             :     // Create a temporary file. Since this is a special file, we will not move
      87             :     // it and the new file can be in another filesystem. This avoids trying to
      88             :     // create a temporary file in /dev when outputting to /dev/null for example.
      89          21 :     EC = sys::fs::createTemporaryFile(sys::path::filename(FilePath), "", FD,
      90          28 :                                       TempFilePath);
      91             :   }
      92             : 
      93        3633 :   if (EC)
      94             :     return EC;
      95             : 
      96        3627 :   sys::RemoveFileOnSignal(TempFilePath);
      97             : 
      98             : #ifndef LLVM_ON_WIN32
      99             :   // On Windows, CreateFileMapping (the mmap function on Windows)
     100             :   // automatically extends the underlying file. We don't need to
     101             :   // extend the file beforehand. _chsize (ftruncate on Windows) is
     102             :   // pretty slow just like it writes specified amount of bytes,
     103             :   // so we should avoid calling that.
     104        3627 :   EC = sys::fs::resize_file(FD, Size);
     105        3627 :   if (EC)
     106             :     return EC;
     107             : #endif
     108             : 
     109             :   auto MappedFile = llvm::make_unique<mapped_file_region>(
     110       10881 :       FD, mapped_file_region::readwrite, Size, 0, EC);
     111        3627 :   int Ret = close(FD);
     112        3627 :   if (EC)
     113             :     return EC;
     114        3627 :   if (Ret)
     115           0 :     return std::error_code(errno, std::generic_category());
     116             : 
     117             :   std::unique_ptr<FileOutputBuffer> Buf(new FileOutputBuffer(
     118       18135 :       std::move(MappedFile), FilePath, TempFilePath, IsRegular));
     119        7254 :   return std::move(Buf);
     120             : }
     121             : 
     122        1968 : std::error_code FileOutputBuffer::commit() {
     123             :   // Unmap buffer, letting OS flush dirty pages to file on disk.
     124        3936 :   Region.reset();
     125             : 
     126        1968 :   std::error_code EC;
     127        1968 :   if (IsRegular) {
     128             :     // Rename file to final name.
     129        5895 :     EC = sys::fs::rename(Twine(TempPath), Twine(FinalPath));
     130        3930 :     sys::DontRemoveFileOnSignal(TempPath);
     131             :   } else {
     132           9 :     EC = sys::fs::copy_file(TempPath, FinalPath);
     133           6 :     std::error_code RMEC = sys::fs::remove(TempPath);
     134           6 :     sys::DontRemoveFileOnSignal(TempPath);
     135           3 :     if (RMEC)
     136           0 :       return RMEC;
     137             :   }
     138             : 
     139        1968 :   return EC;
     140             : }
     141             : } // namespace

Generated by: LCOV version 1.13