1adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik//===- FileOutputBuffer.cpp - File Output Buffer ----------------*- C++ -*-===// 2adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// 3adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// The LLVM Compiler Infrastructure 4adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// 5adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// This file is distributed under the University of Illinois Open Source 6adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// License. See LICENSE.TXT for details. 7adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// 8adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik//===----------------------------------------------------------------------===// 9adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// 10adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// Utility for creating a in-memory buffer that will be written to a file. 11adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik// 12adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik//===----------------------------------------------------------------------===// 13adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 14adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik#include "llvm/Support/FileOutputBuffer.h" 15adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 16adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik#include "llvm/ADT/OwningPtr.h" 17adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik#include "llvm/ADT/SmallVector.h" 18adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik#include "llvm/Support/FileSystem.h" 19adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik#include "llvm/Support/raw_ostream.h" 20adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik#include "llvm/Support/system_error.h" 21adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 22adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 23adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledziknamespace llvm { 24adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 25adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 26adfe2637b839efe041165f27c9ad57e3befb2be0Nick KledzikFileOutputBuffer::FileOutputBuffer(uint8_t *Start, uint8_t *End, 27adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik StringRef Path, StringRef TmpPath) 28adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik : BufferStart(Start), BufferEnd(End) { 29adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik FinalPath.assign(Path); 30adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik TempPath.assign(TmpPath); 31adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik} 32adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 33adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 34adfe2637b839efe041165f27c9ad57e3befb2be0Nick KledzikFileOutputBuffer::~FileOutputBuffer() { 35adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // If not already commited, delete buffer and remove temp file. 36adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if ( BufferStart != NULL ) { 37adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik sys::fs::unmap_file_pages((void*)BufferStart, getBufferSize()); 38adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik bool Existed; 39adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik sys::fs::remove(Twine(TempPath), Existed); 40adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik } 41adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik} 42adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 43adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 44adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzikerror_code FileOutputBuffer::create(StringRef FilePath, 45adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik size_t Size, 46adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik OwningPtr<FileOutputBuffer> &Result, 47adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik unsigned Flags) { 48adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // If file already exists, it must be a regular file (to be mappable). 49adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik sys::fs::file_status Stat; 50adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik error_code EC = sys::fs::status(FilePath, Stat); 51adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik switch (Stat.type()) { 52adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik case sys::fs::file_type::file_not_found: 53adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // If file does not exist, we'll create one. 54adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik break; 55adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik case sys::fs::file_type::regular_file: { 56adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // If file is not currently writable, error out. 57adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // FIXME: There is no sys::fs:: api for checking this. 58adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // FIXME: In posix, you use the access() call to check this. 59adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik } 60adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik break; 61adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik default: 62adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 63adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 64adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik else 65adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return make_error_code(errc::operation_not_permitted); 66adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik } 67adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 68adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // Delete target file. 69adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik bool Existed; 70adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik EC = sys::fs::remove(FilePath, Existed); 71adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 72adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 73adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 74adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // Create new file in same directory but with random name. 75adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik SmallString<128> TempFilePath; 76adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik int FD; 77adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik EC = sys::fs::unique_file(Twine(FilePath) + ".tmp%%%%%%%", 78adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik FD, TempFilePath, false, 0644); 79adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 80adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 81adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 82adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // The unique_file() interface leaks lower layers and returns a file 83adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // descriptor. There is no way to directly close it, so use this hack 84adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // to hand it off to raw_fd_ostream to close for us. 85adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik { 86adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik raw_fd_ostream Dummy(FD, /*shouldClose=*/true); 87adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik } 88adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 89adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // Resize file to requested initial size 90adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik EC = sys::fs::resize_file(Twine(TempFilePath), Size); 91adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 92adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 93adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 94adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // If requested, make the output file executable. 95adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if ( Flags & F_executable ) { 96adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik sys::fs::file_status Stat2; 97adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik EC = sys::fs::status(Twine(TempFilePath), Stat2); 98adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 99adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 100adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 101adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik sys::fs::perms new_perms = Stat2.permissions(); 102adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if ( new_perms & sys::fs::owner_read ) 103adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik new_perms |= sys::fs::owner_exe; 104adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if ( new_perms & sys::fs::group_read ) 105adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik new_perms |= sys::fs::group_exe; 106adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if ( new_perms & sys::fs::others_read ) 107adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik new_perms |= sys::fs::others_exe; 108adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik new_perms |= sys::fs::add_perms; 109adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik EC = sys::fs::permissions(Twine(TempFilePath), new_perms); 110adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 111adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 112adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik } 113adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 114adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // Memory map new file. 115adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik void *Base; 116adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik EC = sys::fs::map_file_pages(Twine(TempFilePath), 0, Size, true, Base); 117adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 118adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 119adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 120adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // Create FileOutputBuffer object to own mapped range. 121adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik uint8_t *Start = reinterpret_cast<uint8_t*>(Base); 122adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik Result.reset(new FileOutputBuffer(Start, Start+Size, FilePath, TempFilePath)); 123adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 124adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return error_code::success(); 125adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik} 126adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 127adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 128adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzikerror_code FileOutputBuffer::commit(int64_t NewSmallerSize) { 129adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // Unmap buffer, letting OS flush dirty pages to file on disk. 130adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik void *Start = reinterpret_cast<void*>(BufferStart); 131adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik error_code EC = sys::fs::unmap_file_pages(Start, getBufferSize()); 132adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 133adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 134adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 135adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // If requested, resize file as part of commit. 136adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if ( NewSmallerSize != -1 ) { 137adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik EC = sys::fs::resize_file(Twine(TempPath), NewSmallerSize); 138adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik if (EC) 139adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return EC; 140adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik } 141adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 142adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik // Rename file to final name. 143adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik return sys::fs::rename(Twine(TempPath), Twine(FinalPath)); 144adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik} 145adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 146adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 147adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik} // namespace 148adfe2637b839efe041165f27c9ad57e3befb2be0Nick Kledzik 149