Use the new script to sort the includes of every file under lib.
[oota-llvm.git] / lib / Support / FileOutputBuffer.cpp
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/OwningPtr.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "llvm/Support/system_error.h"
20
21
22 namespace llvm {
23
24
25 FileOutputBuffer::FileOutputBuffer(uint8_t *Start, uint8_t *End, 
26                                   StringRef Path, StringRef TmpPath)
27   : BufferStart(Start), BufferEnd(End) {
28   FinalPath.assign(Path);
29   TempPath.assign(TmpPath);
30 }
31
32
33 FileOutputBuffer::~FileOutputBuffer() {
34   // If not already commited, delete buffer and remove temp file.
35   if ( BufferStart != NULL ) {
36     sys::fs::unmap_file_pages((void*)BufferStart, getBufferSize());
37     bool Existed;
38     sys::fs::remove(Twine(TempPath), Existed);
39   }
40 }
41
42  
43 error_code FileOutputBuffer::create(StringRef FilePath, 
44                                     size_t Size,  
45                                     OwningPtr<FileOutputBuffer> &Result,
46                                     unsigned Flags) {
47   // If file already exists, it must be a regular file (to be mappable).
48   sys::fs::file_status Stat;
49   error_code EC = sys::fs::status(FilePath, Stat);
50   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     default:
61       if (EC)
62         return EC;
63       else
64         return make_error_code(errc::operation_not_permitted);
65   }
66
67   // Delete target file.
68   bool Existed;
69   EC = sys::fs::remove(FilePath, Existed);
70   if (EC)
71     return EC;
72   
73   // Create new file in same directory but with random name.
74   SmallString<128> TempFilePath;
75   int FD;
76   EC = sys::fs::unique_file(Twine(FilePath) + ".tmp%%%%%%%",  
77                                                 FD, TempFilePath, false, 0644);
78   if (EC)
79     return EC;
80   
81   // The unique_file() interface leaks lower layers and returns a file 
82   // descriptor.  There is no way to directly close it, so use this hack
83   // to hand it off to raw_fd_ostream to close for us.
84   {
85     raw_fd_ostream Dummy(FD, /*shouldClose=*/true);
86   }
87   
88   // Resize file to requested initial size
89   EC = sys::fs::resize_file(Twine(TempFilePath), Size);
90   if (EC)
91     return EC;
92   
93   // If requested, make the output file executable.
94   if ( Flags & F_executable ) {
95     sys::fs::file_status Stat2;
96     EC = sys::fs::status(Twine(TempFilePath), Stat2);
97     if (EC)
98       return EC;
99     
100     sys::fs::perms new_perms = Stat2.permissions();
101     if ( new_perms & sys::fs::owner_read )
102       new_perms |= sys::fs::owner_exe;
103     if ( new_perms & sys::fs::group_read )
104       new_perms |= sys::fs::group_exe;
105     if ( new_perms & sys::fs::others_read )
106       new_perms |= sys::fs::others_exe;
107     new_perms |= sys::fs::add_perms;
108     EC = sys::fs::permissions(Twine(TempFilePath), new_perms);
109     if (EC)
110       return EC;
111   }
112
113   // Memory map new file.
114   void *Base;
115   EC = sys::fs::map_file_pages(Twine(TempFilePath), 0, Size, true, Base);
116   if (EC)
117     return EC;
118   
119   // Create FileOutputBuffer object to own mapped range.
120   uint8_t *Start = reinterpret_cast<uint8_t*>(Base);
121   Result.reset(new FileOutputBuffer(Start, Start+Size, FilePath, TempFilePath));
122                      
123   return error_code::success();
124 }                    
125
126
127 error_code FileOutputBuffer::commit(int64_t NewSmallerSize) {
128   // Unmap buffer, letting OS flush dirty pages to file on disk.
129   void *Start = reinterpret_cast<void*>(BufferStart);
130   error_code EC = sys::fs::unmap_file_pages(Start, getBufferSize());
131   if (EC)
132     return EC;
133   
134   // If requested, resize file as part of commit.
135   if ( NewSmallerSize != -1 ) {
136     EC = sys::fs::resize_file(Twine(TempPath), NewSmallerSize);
137     if (EC)
138       return EC;
139   }
140   
141   // Rename file to final name.
142   return sys::fs::rename(Twine(TempPath), Twine(FinalPath));
143 }
144
145
146 } // namespace
147