blob: 09542c3fabb63416531c2f0d7af18073a764a4b0 [file] [log] [blame]
Chris Lattner7a6ff2b2003-08-01 21:16:14 +00001//===- Support/FileUtilities.cpp - File System Utilities ------------------===//
John Criswellb576c942003-10-20 19:43:21 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Chris Lattner7a6ff2b2003-08-01 21:16:14 +00009//
10// This file implements a family of utility functions which are useful for doing
11// various things with files.
12//
13//===----------------------------------------------------------------------===//
14
15#include "Support/FileUtilities.h"
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +000016#include "Support/DataTypes.h"
Misha Brukmanda81eca2003-08-07 21:35:41 +000017#include "Config/unistd.h"
Chris Lattnereb082992004-05-28 00:23:48 +000018#include "Config/fcntl.h"
John Criswell6991a032003-09-02 20:14:57 +000019#include "Config/sys/types.h"
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +000020#include "Config/sys/stat.h"
Chris Lattnereb082992004-05-28 00:23:48 +000021#include "Config/sys/mman.h"
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +000022#include "Config/alloca.h"
Alkis Evlogimenos8868e842004-06-05 08:59:43 +000023#include <cerrno>
24#include <cstdio>
Chris Lattner7a6ff2b2003-08-01 21:16:14 +000025#include <fstream>
26#include <iostream>
Chris Lattner2cdd21c2003-12-14 21:35:53 +000027using namespace llvm;
Brian Gaeked0fde302003-11-11 22:41:34 +000028
Brian Gaekea2302ff2003-11-11 21:53:50 +000029/// CheckMagic - Returns true IFF the file named FN begins with Magic. FN must
30/// name a readable file.
31///
Chris Lattner2cdd21c2003-12-14 21:35:53 +000032bool llvm::CheckMagic(const std::string &FN, const std::string &Magic) {
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +000033 char *buf = (char*)alloca(1 + Magic.size());
34 std::ifstream f(FN.c_str());
35 f.read(buf, Magic.size());
36 buf[Magic.size()] = '\0';
Brian Gaekea2302ff2003-11-11 21:53:50 +000037 return Magic == buf;
38}
39
40/// IsArchive - Returns true IFF the file named FN appears to be a "ar" library
41/// archive. The file named FN must exist.
42///
Chris Lattner2cdd21c2003-12-14 21:35:53 +000043bool llvm::IsArchive(const std::string &FN) {
Brian Gaekea2302ff2003-11-11 21:53:50 +000044 // Inspect the beginning of the file to see if it contains the "ar"
45 // library archive format magic string.
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +000046 return CheckMagic(FN, "!<arch>\012");
Brian Gaekea2302ff2003-11-11 21:53:50 +000047}
48
49/// IsBytecode - Returns true IFF the file named FN appears to be an LLVM
50/// bytecode file. The file named FN must exist.
51///
Chris Lattner2cdd21c2003-12-14 21:35:53 +000052bool llvm::IsBytecode(const std::string &FN) {
Brian Gaekea2302ff2003-11-11 21:53:50 +000053 // Inspect the beginning of the file to see if it contains the LLVM
54 // bytecode format magic string.
55 return CheckMagic (FN, "llvm");
56}
57
Misha Brukman17cca962003-11-24 05:28:12 +000058/// IsSharedObject - Returns trus IFF the file named FN appears to be a shared
59/// object with an ELF header. The file named FN must exist.
60///
Chris Lattner2cdd21c2003-12-14 21:35:53 +000061bool llvm::IsSharedObject(const std::string &FN) {
Misha Brukman971a7b82003-11-24 05:36:38 +000062 // Inspect the beginning of the file to see if it contains the ELF shared
63 // object magic string.
Misha Brukman17cca962003-11-24 05:28:12 +000064 static const char elfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' };
65 return CheckMagic(FN, elfMagic);
66}
67
Brian Gaeke56be7ff2003-11-11 18:27:21 +000068/// FileOpenable - Returns true IFF Filename names an existing regular
69/// file which we can successfully open.
70///
Chris Lattner2cdd21c2003-12-14 21:35:53 +000071bool llvm::FileOpenable(const std::string &Filename) {
Brian Gaeke56be7ff2003-11-11 18:27:21 +000072 struct stat s;
73 if (stat (Filename.c_str (), &s) == -1)
74 return false; // Cannot stat file
75 if (!S_ISREG (s.st_mode))
76 return false; // File is not a regular file
77 std::ifstream FileStream (Filename.c_str ());
78 if (!FileStream)
79 return false; // File is not openable
80 return true;
81}
82
Chris Lattner7a6ff2b2003-08-01 21:16:14 +000083/// DiffFiles - Compare the two files specified, returning true if they are
84/// different or if there is a file error. If you specify a string to fill in
85/// for the error option, it will set the string to an error message if an error
86/// occurs, allowing the caller to distinguish between a failed diff and a file
87/// system error.
88///
Chris Lattner2cdd21c2003-12-14 21:35:53 +000089bool llvm::DiffFiles(const std::string &FileA, const std::string &FileB,
90 std::string *Error) {
Chris Lattner7a6ff2b2003-08-01 21:16:14 +000091 std::ifstream FileAStream(FileA.c_str());
92 if (!FileAStream) {
93 if (Error) *Error = "Couldn't open file '" + FileA + "'";
94 return true;
95 }
96
97 std::ifstream FileBStream(FileB.c_str());
98 if (!FileBStream) {
99 if (Error) *Error = "Couldn't open file '" + FileB + "'";
100 return true;
101 }
102
103 // Compare the two files...
104 int C1, C2;
105 do {
106 C1 = FileAStream.get();
107 C2 = FileBStream.get();
108 if (C1 != C2) return true;
109 } while (C1 != EOF);
110
111 return false;
112}
113
114
Chris Lattner5bfac5d2004-06-02 00:52:22 +0000115/// CopyFile - Copy the specified source file to the specified destination,
116/// overwriting destination if it exists. This returns true on failure.
117///
118bool llvm::CopyFile(const std::string &Dest, const std::string &Src) {
119 FDHandle InFD(open(Src.c_str(), O_RDONLY));
120 if (InFD == -1) return true;
121
122 FileRemover FR(Dest);
123
124 FDHandle OutFD(open(Dest.c_str(), O_WRONLY|O_CREAT, 0666));
125 if (OutFD == -1) return true;
126
127 char Buffer[16*1024];
128 while (ssize_t Amt = read(InFD, Buffer, 16*1024)) {
129 if (Amt == -1) {
130 if (errno != EINTR) return true; // Error reading the file.
131 } else {
132 char *BufPtr = Buffer;
133 while (Amt) {
134 ssize_t AmtWritten = write(OutFD, BufPtr, Amt);
135 if (AmtWritten == -1) {
136 if (errno != EINTR) return true; // Error writing the file.
137 } else {
138 Amt -= AmtWritten;
139 BufPtr += AmtWritten;
140 }
141 }
142 }
143 }
144
145 FR.releaseFile(); // Success!
146 return false;
147}
148
149
Chris Lattner7a6ff2b2003-08-01 21:16:14 +0000150/// MoveFileOverIfUpdated - If the file specified by New is different than Old,
151/// or if Old does not exist, move the New file over the Old file. Otherwise,
152/// remove the New file.
153///
Chris Lattner2cdd21c2003-12-14 21:35:53 +0000154void llvm::MoveFileOverIfUpdated(const std::string &New,
155 const std::string &Old) {
Chris Lattner7a6ff2b2003-08-01 21:16:14 +0000156 if (DiffFiles(New, Old)) {
157 if (std::rename(New.c_str(), Old.c_str()))
158 std::cerr << "Error renaming '" << New << "' to '" << Old << "'!\n";
159 } else {
160 std::remove(New.c_str());
161 }
162}
Misha Brukman3d1b0c72003-08-07 21:28:50 +0000163
164/// removeFile - Delete the specified file
165///
Chris Lattner2cdd21c2003-12-14 21:35:53 +0000166void llvm::removeFile(const std::string &Filename) {
Misha Brukman3d1b0c72003-08-07 21:28:50 +0000167 std::remove(Filename.c_str());
168}
169
170/// getUniqueFilename - Return a filename with the specified prefix. If the
171/// file does not exist yet, return it, otherwise add a suffix to make it
172/// unique.
173///
Chris Lattner2cdd21c2003-12-14 21:35:53 +0000174std::string llvm::getUniqueFilename(const std::string &FilenameBase) {
Misha Brukman3d1b0c72003-08-07 21:28:50 +0000175 if (!std::ifstream(FilenameBase.c_str()))
176 return FilenameBase; // Couldn't open the file? Use it!
177
178 // Create a pattern for mkstemp...
179 char *FNBuffer = new char[FilenameBase.size()+8];
180 strcpy(FNBuffer, FilenameBase.c_str());
181 strcpy(FNBuffer+FilenameBase.size(), "-XXXXXX");
182
183 // Agree on a temporary file name to use....
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000184#if defined(HAVE_MKSTEMP) && !defined(_MSC_VER)
Misha Brukman3d1b0c72003-08-07 21:28:50 +0000185 int TempFD;
186 if ((TempFD = mkstemp(FNBuffer)) == -1) {
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000187 // FIXME: this should return an emtpy string or something and allow the
188 // caller to deal with the error!
Misha Brukman3d1b0c72003-08-07 21:28:50 +0000189 std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current "
190 << " directory!\n";
191 exit(1);
192 }
193
Misha Brukman950971d2003-09-16 15:31:46 +0000194 // We don't need to hold the temp file descriptor... we will trust that no one
Misha Brukman3d1b0c72003-08-07 21:28:50 +0000195 // will overwrite/delete the file while we are working on it...
196 close(TempFD);
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000197#else
198 // If we don't have mkstemp, use the old and obsolete mktemp function.
199 if (mktemp(FNBuffer) == 0) {
200 // FIXME: this should return an emtpy string or something and allow the
201 // caller to deal with the error!
202 std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current "
203 << " directory!\n";
204 exit(1);
205 }
206#endif
207
Misha Brukman3d1b0c72003-08-07 21:28:50 +0000208 std::string Result(FNBuffer);
209 delete[] FNBuffer;
210 return Result;
211}
John Criswell6991a032003-09-02 20:14:57 +0000212
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000213static bool AddPermissionsBits (const std::string &Filename, int bits) {
Brian Gaeke56be7ff2003-11-11 18:27:21 +0000214 // Get the umask value from the operating system. We want to use it
215 // when changing the file's permissions. Since calling umask() sets
216 // the umask and returns its old value, we must call it a second
217 // time to reset it to the user's preference.
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000218 int mask = umask(0777); // The arg. to umask is arbitrary.
219 umask(mask); // Restore the umask.
John Criswell6991a032003-09-02 20:14:57 +0000220
Brian Gaeke56be7ff2003-11-11 18:27:21 +0000221 // Get the file's current mode.
222 struct stat st;
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000223 if ((stat(Filename.c_str(), &st)) == -1)
John Criswell6991a032003-09-02 20:14:57 +0000224 return false;
John Criswell6991a032003-09-02 20:14:57 +0000225
Brian Gaeke56be7ff2003-11-11 18:27:21 +0000226 // Change the file to have whichever permissions bits from 'bits'
227 // that the umask would not disable.
228 if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1)
John Criswell9adeccc2003-09-02 20:30:16 +0000229 return false;
John Criswell6991a032003-09-02 20:14:57 +0000230
231 return true;
232}
233
Brian Gaeke56be7ff2003-11-11 18:27:21 +0000234/// MakeFileExecutable - Make the file named Filename executable by
235/// setting whichever execute permissions bits the process's current
236/// umask would allow. Filename must name an existing file or
237/// directory. Returns true on success, false on error.
John Criswell66622be2003-09-02 21:09:30 +0000238///
Chris Lattner2cdd21c2003-12-14 21:35:53 +0000239bool llvm::MakeFileExecutable(const std::string &Filename) {
240 return AddPermissionsBits(Filename, 0111);
John Criswell66622be2003-09-02 21:09:30 +0000241}
242
Brian Gaeke56be7ff2003-11-11 18:27:21 +0000243/// MakeFileReadable - Make the file named Filename readable by
244/// setting whichever read permissions bits the process's current
245/// umask would allow. Filename must name an existing file or
246/// directory. Returns true on success, false on error.
247///
Chris Lattner2cdd21c2003-12-14 21:35:53 +0000248bool llvm::MakeFileReadable(const std::string &Filename) {
249 return AddPermissionsBits(Filename, 0444);
Brian Gaeke56be7ff2003-11-11 18:27:21 +0000250}
Chris Lattner2d6481c2003-12-29 21:35:05 +0000251
Chris Lattner316cb082003-12-30 07:36:14 +0000252/// getFileSize - Return the size of the specified file in bytes, or -1 if the
253/// file cannot be read or does not exist.
254long long llvm::getFileSize(const std::string &Filename) {
255 struct stat StatBuf;
256 if (stat(Filename.c_str(), &StatBuf) == -1)
257 return -1;
258 return StatBuf.st_size;
259}
260
Chris Lattner81a085a2003-12-31 06:15:37 +0000261/// getFileTimestamp - Get the last modified time for the specified file in an
262/// unspecified format. This is useful to allow checking to see if a file was
263/// updated since that last time the timestampt was aquired. If the file does
264/// not exist or there is an error getting the time-stamp, zero is returned.
265unsigned long long llvm::getFileTimestamp(const std::string &Filename) {
266 struct stat StatBuf;
267 if (stat(Filename.c_str(), &StatBuf) == -1)
268 return 0;
269 return StatBuf.st_mtime;
270}
271
Chris Lattnereb082992004-05-28 00:23:48 +0000272/// ReadFileIntoAddressSpace - Attempt to map the specific file into the
273/// address space of the current process for reading. If this succeeds,
274/// return the address of the buffer and the length of the file mapped. On
275/// failure, return null.
276void *llvm::ReadFileIntoAddressSpace(const std::string &Filename,
277 unsigned &Length) {
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000278#if defined(HAVE_MMAP_FILE) && !defined(_MSC_VER)
279 Length = (unsigned)getFileSize(Filename);
Chris Lattnereb082992004-05-28 00:23:48 +0000280 if ((int)Length == -1) return 0;
Chris Lattner81a085a2003-12-31 06:15:37 +0000281
Chris Lattnereb082992004-05-28 00:23:48 +0000282 FDHandle FD(open(Filename.c_str(), O_RDONLY));
283 if (FD == -1) return 0;
Chris Lattner81a085a2003-12-31 06:15:37 +0000284
Chris Lattnere53477e2004-05-28 00:34:42 +0000285 // If the file has a length of zero, mmap might return a null pointer. In
286 // this case, allocate a single byte of memory and return it instead.
287 if (Length == 0)
288 return malloc(1);
289
Chris Lattnereb082992004-05-28 00:23:48 +0000290 // mmap in the file all at once...
291 void *Buffer = (void*)mmap(0, Length, PROT_READ, MAP_PRIVATE, FD, 0);
292
293 if (Buffer == (void*)MAP_FAILED)
294 return 0;
Chris Lattnere53477e2004-05-28 00:34:42 +0000295
Chris Lattnereb082992004-05-28 00:23:48 +0000296 return Buffer;
297#else
298 // FIXME: implement with read/write
299 return 0;
300#endif
301}
302
303/// UnmapFileFromAddressSpace - Remove the specified file from the current
304/// address space.
305void llvm::UnmapFileFromAddressSpace(void *Buffer, unsigned Length) {
Chris Lattnerfa5fe7c2004-06-07 19:37:24 +0000306#if defined(HAVE_MMAP_FILE) && !defined(_MSC_VER)
Chris Lattnere53477e2004-05-28 00:34:42 +0000307 if (Length)
308 munmap((char*)Buffer, Length);
309 else
310 free(Buffer); // Zero byte files are malloc(1)'s.
Chris Lattnereb082992004-05-28 00:23:48 +0000311#else
312 free(Buffer);
313#endif
314}
Chris Lattner316cb082003-12-30 07:36:14 +0000315
Chris Lattner2d6481c2003-12-29 21:35:05 +0000316//===----------------------------------------------------------------------===//
317// FDHandle class implementation
318//
319
Chris Lattner9b448b72003-12-29 21:43:58 +0000320FDHandle::~FDHandle() throw() {
Chris Lattner2d6481c2003-12-29 21:35:05 +0000321 if (FD != -1) close(FD);
322}
323
Chris Lattner9b448b72003-12-29 21:43:58 +0000324FDHandle &FDHandle::operator=(int fd) throw() {
Chris Lattner2d6481c2003-12-29 21:35:05 +0000325 if (FD != -1) close(FD);
326 FD = fd;
327 return *this;
328}
329