FileOutputBuffer.cpp revision cd81d94322a39503e4a3e87b6ee03d4fcb3465fb
1727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//===- FileOutputBuffer.cpp - File Output Buffer ----------------*- C++ -*-===//
2727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//
3727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//                     The LLVM Compiler Infrastructure
4727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//
5727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease// This file is distributed under the University of Illinois Open Source
6727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease// License. See LICENSE.TXT for details.
7727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//
8727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//===----------------------------------------------------------------------===//
9727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//
10727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease// Utility for creating a in-memory buffer that will be written to a file.
11727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//
12727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease//===----------------------------------------------------------------------===//
13727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
14727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#include "llvm/Support/Errc.h"
15727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#include "llvm/Support/FileOutputBuffer.h"
16727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#include "llvm/ADT/SmallVector.h"
17727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#include "llvm/Support/raw_ostream.h"
18727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#include <system_error>
19727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
20727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Leaseusing llvm::sys::fs::mapped_file_region;
21727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
22727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Leasenamespace llvm {
23727dee178a392d20eb050d0c446f2fcc29058fa1Victoria LeaseFileOutputBuffer::FileOutputBuffer(mapped_file_region * R,
24727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                                   StringRef Path, StringRef TmpPath)
25727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  : Region(R)
26727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  , FinalPath(Path)
27727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  , TempPath(TmpPath) {
28727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease}
29727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
30727dee178a392d20eb050d0c446f2fcc29058fa1Victoria LeaseFileOutputBuffer::~FileOutputBuffer() {
31727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  sys::fs::remove(Twine(TempPath));
32727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease}
33727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
34727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Leasestd::error_code
35727dee178a392d20eb050d0c446f2fcc29058fa1Victoria LeaseFileOutputBuffer::create(StringRef FilePath, size_t Size,
36727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                         std::unique_ptr<FileOutputBuffer> &Result,
37727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                         unsigned Flags) {
38727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  // If file already exists, it must be a regular file (to be mappable).
39727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  sys::fs::file_status Stat;
40727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  std::error_code EC = sys::fs::status(FilePath, Stat);
41727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  switch (Stat.type()) {
42727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    case sys::fs::file_type::file_not_found:
43727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      // If file does not exist, we'll create one.
44727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      break;
45727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    case sys::fs::file_type::regular_file: {
46727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        // If file is not currently writable, error out.
47727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        // FIXME: There is no sys::fs:: api for checking this.
48727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        // FIXME: In posix, you use the access() call to check this.
49727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      }
50727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      break;
51727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    default:
52727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      if (EC)
53727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        return EC;
54727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      else
55727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        return make_error_code(errc::operation_not_permitted);
56727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  }
57727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
58727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  // Delete target file.
59727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  EC = sys::fs::remove(FilePath);
60727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  if (EC)
61727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    return EC;
62727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
63727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  unsigned Mode = sys::fs::all_read | sys::fs::all_write;
64727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  // If requested, make the output file executable.
65727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  if (Flags & F_executable)
66727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    Mode |= sys::fs::all_exe;
67727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
68727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  // Create new file in same directory but with random name.
69727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  SmallString<128> TempFilePath;
70727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  int FD;
71727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD,
72727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                                 TempFilePath, Mode);
73727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  if (EC)
74727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    return EC;
75727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
76727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  std::unique_ptr<mapped_file_region> MappedFile(new mapped_file_region(
77727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      FD, true, mapped_file_region::readwrite, Size, 0, EC));
78727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  if (EC)
79727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    return EC;
80727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
81727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  Result.reset(new FileOutputBuffer(MappedFile.get(), FilePath, TempFilePath));
82727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  if (Result)
83727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    MappedFile.release();
84727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
85727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  return std::error_code();
86727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease}
87727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
88727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Leasestd::error_code FileOutputBuffer::commit(int64_t NewSmallerSize) {
89727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  // Unmap buffer, letting OS flush dirty pages to file on disk.
90727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  Region.reset(nullptr);
91727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
92727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  // If requested, resize file as part of commit.
93727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  if ( NewSmallerSize != -1 ) {
94727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    std::error_code EC = sys::fs::resize_file(Twine(TempPath), NewSmallerSize);
95727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    if (EC)
96727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      return EC;
97727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  }
98727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
99727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  // Rename file to final name.
100727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease  return sys::fs::rename(Twine(TempPath), Twine(FinalPath));
101727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease}
102727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease} // namespace
103727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease