1239310Sdim//===- FileOutputBuffer.cpp - File Output Buffer ----------------*- C++ -*-===// 2239310Sdim// 3239310Sdim// The LLVM Compiler Infrastructure 4239310Sdim// 5239310Sdim// This file is distributed under the University of Illinois Open Source 6239310Sdim// License. See LICENSE.TXT for details. 7239310Sdim// 8239310Sdim//===----------------------------------------------------------------------===// 9239310Sdim// 10239310Sdim// Utility for creating a in-memory buffer that will be written to a file. 11239310Sdim// 12239310Sdim//===----------------------------------------------------------------------===// 13239310Sdim 14239310Sdim#include "llvm/Support/FileOutputBuffer.h" 15239310Sdim#include "llvm/ADT/OwningPtr.h" 16239310Sdim#include "llvm/ADT/SmallVector.h" 17239310Sdim#include "llvm/Support/raw_ostream.h" 18239310Sdim#include "llvm/Support/system_error.h" 19239310Sdim 20249423Sdimusing llvm::sys::fs::mapped_file_region; 21239310Sdim 22239310Sdimnamespace llvm { 23249423SdimFileOutputBuffer::FileOutputBuffer(mapped_file_region * R, 24249423Sdim StringRef Path, StringRef TmpPath) 25249423Sdim : Region(R) 26249423Sdim , FinalPath(Path) 27249423Sdim , TempPath(TmpPath) { 28239310Sdim} 29239310Sdim 30239310SdimFileOutputBuffer::~FileOutputBuffer() { 31249423Sdim bool Existed; 32249423Sdim sys::fs::remove(Twine(TempPath), Existed); 33239310Sdim} 34239310Sdim 35249423Sdimerror_code FileOutputBuffer::create(StringRef FilePath, 36249423Sdim size_t Size, 37239310Sdim OwningPtr<FileOutputBuffer> &Result, 38239310Sdim unsigned Flags) { 39239310Sdim // If file already exists, it must be a regular file (to be mappable). 40239310Sdim sys::fs::file_status Stat; 41239310Sdim error_code EC = sys::fs::status(FilePath, Stat); 42239310Sdim switch (Stat.type()) { 43239310Sdim case sys::fs::file_type::file_not_found: 44239310Sdim // If file does not exist, we'll create one. 45239310Sdim break; 46239310Sdim case sys::fs::file_type::regular_file: { 47239310Sdim // If file is not currently writable, error out. 48239310Sdim // FIXME: There is no sys::fs:: api for checking this. 49239310Sdim // FIXME: In posix, you use the access() call to check this. 50239310Sdim } 51239310Sdim break; 52239310Sdim default: 53239310Sdim if (EC) 54239310Sdim return EC; 55239310Sdim else 56239310Sdim return make_error_code(errc::operation_not_permitted); 57239310Sdim } 58239310Sdim 59239310Sdim // Delete target file. 60239310Sdim bool Existed; 61239310Sdim EC = sys::fs::remove(FilePath, Existed); 62239310Sdim if (EC) 63239310Sdim return EC; 64249423Sdim 65263508Sdim unsigned Mode = sys::fs::all_read | sys::fs::all_write; 66263508Sdim // If requested, make the output file executable. 67263508Sdim if (Flags & F_executable) 68263508Sdim Mode |= sys::fs::all_exe; 69263508Sdim 70239310Sdim // Create new file in same directory but with random name. 71239310Sdim SmallString<128> TempFilePath; 72239310Sdim int FD; 73263508Sdim EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD, 74263508Sdim TempFilePath, Mode); 75239310Sdim if (EC) 76239310Sdim return EC; 77249423Sdim 78249423Sdim OwningPtr<mapped_file_region> MappedFile(new mapped_file_region( 79249423Sdim FD, true, mapped_file_region::readwrite, Size, 0, EC)); 80239310Sdim if (EC) 81239310Sdim return EC; 82249423Sdim 83249423Sdim Result.reset(new FileOutputBuffer(MappedFile.get(), FilePath, TempFilePath)); 84249423Sdim if (Result) 85249423Sdim MappedFile.take(); 86249423Sdim 87239310Sdim return error_code::success(); 88249423Sdim} 89239310Sdim 90239310Sdimerror_code FileOutputBuffer::commit(int64_t NewSmallerSize) { 91239310Sdim // Unmap buffer, letting OS flush dirty pages to file on disk. 92249423Sdim Region.reset(0); 93249423Sdim 94239310Sdim // If requested, resize file as part of commit. 95239310Sdim if ( NewSmallerSize != -1 ) { 96249423Sdim error_code EC = sys::fs::resize_file(Twine(TempPath), NewSmallerSize); 97239310Sdim if (EC) 98239310Sdim return EC; 99239310Sdim } 100249423Sdim 101239310Sdim // Rename file to final name. 102239310Sdim return sys::fs::rename(Twine(TempPath), Twine(FinalPath)); 103239310Sdim} 104239310Sdim} // namespace 105