LLVM API Documentation
00001 //===- Support/FileUtilities.cpp - File System Utilities ------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by the LLVM research group and is distributed under 00006 // the University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements a family of utility functions which are useful for doing 00011 // various things with files. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "llvm/Support/FileUtilities.h" 00016 #include "llvm/Support/DataTypes.h" 00017 #include "llvm/Config/unistd.h" 00018 #include "llvm/Config/fcntl.h" 00019 #include "llvm/Config/sys/types.h" 00020 #include "llvm/Config/sys/stat.h" 00021 #include "llvm/Config/sys/mman.h" 00022 #include "llvm/Config/alloca.h" 00023 #include <cerrno> 00024 #include <cstdio> 00025 #include <fstream> 00026 #include <iostream> 00027 using namespace llvm; 00028 00029 /// CheckMagic - Returns true IFF the file named FN begins with Magic. FN must 00030 /// name a readable file. 00031 /// 00032 bool llvm::CheckMagic(const std::string &FN, const std::string &Magic) { 00033 char *buf = (char*)alloca(1 + Magic.size()); 00034 std::ifstream f(FN.c_str()); 00035 f.read(buf, Magic.size()); 00036 buf[Magic.size()] = '\0'; 00037 return Magic == buf; 00038 } 00039 00040 /// IsArchive - Returns true IFF the file named FN appears to be a "ar" library 00041 /// archive. The file named FN must exist. 00042 /// 00043 bool llvm::IsArchive(const std::string &FN) { 00044 // Inspect the beginning of the file to see if it contains the "ar" 00045 // library archive format magic string. 00046 return CheckMagic(FN, "!<arch>\012"); 00047 } 00048 00049 /// IsBytecode - Returns true IFF the file named FN appears to be an LLVM 00050 /// bytecode file. The file named FN must exist. 00051 /// 00052 bool llvm::IsBytecode(const std::string &FN) { 00053 // Inspect the beginning of the file to see if it contains the LLVM 00054 // bytecode format magic string. 00055 return CheckMagic(FN, "llvm") || CheckMagic(FN, "llvc"); 00056 } 00057 00058 /// IsSharedObject - Returns trus IFF the file named FN appears to be a shared 00059 /// object with an ELF header. The file named FN must exist. 00060 /// 00061 bool llvm::IsSharedObject(const std::string &FN) { 00062 // Inspect the beginning of the file to see if it contains the ELF shared 00063 // object magic string. 00064 static const char elfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' }; 00065 return CheckMagic(FN, elfMagic); 00066 } 00067 00068 /// FileOpenable - Returns true IFF Filename names an existing regular 00069 /// file which we can successfully open. 00070 /// 00071 bool llvm::FileOpenable(const std::string &Filename) { 00072 struct stat s; 00073 if (stat (Filename.c_str (), &s) == -1) 00074 return false; // Cannot stat file 00075 if (!S_ISREG (s.st_mode)) 00076 return false; // File is not a regular file 00077 std::ifstream FileStream (Filename.c_str ()); 00078 if (!FileStream) 00079 return false; // File is not openable 00080 return true; 00081 } 00082 00083 /// DiffFiles - Compare the two files specified, returning true if they are 00084 /// different or if there is a file error. If you specify a string to fill in 00085 /// for the error option, it will set the string to an error message if an error 00086 /// occurs, allowing the caller to distinguish between a failed diff and a file 00087 /// system error. 00088 /// 00089 bool llvm::DiffFiles(const std::string &FileA, const std::string &FileB, 00090 std::string *Error) { 00091 std::ifstream FileAStream(FileA.c_str()); 00092 if (!FileAStream) { 00093 if (Error) *Error = "Couldn't open file '" + FileA + "'"; 00094 return true; 00095 } 00096 00097 std::ifstream FileBStream(FileB.c_str()); 00098 if (!FileBStream) { 00099 if (Error) *Error = "Couldn't open file '" + FileB + "'"; 00100 return true; 00101 } 00102 00103 // Compare the two files... 00104 int C1, C2; 00105 do { 00106 C1 = FileAStream.get(); 00107 C2 = FileBStream.get(); 00108 if (C1 != C2) return true; 00109 } while (C1 != EOF); 00110 00111 return false; 00112 } 00113 00114 00115 /// CopyFile - Copy the specified source file to the specified destination, 00116 /// overwriting destination if it exists. This returns true on failure. 00117 /// 00118 bool llvm::CopyFile(const std::string &Dest, const std::string &Src) { 00119 FDHandle InFD(open(Src.c_str(), O_RDONLY)); 00120 if (InFD == -1) return true; 00121 00122 FileRemover FR(Dest); 00123 00124 FDHandle OutFD(open(Dest.c_str(), O_WRONLY|O_CREAT, 0666)); 00125 if (OutFD == -1) return true; 00126 00127 char Buffer[16*1024]; 00128 while (ssize_t Amt = read(InFD, Buffer, 16*1024)) { 00129 if (Amt == -1) { 00130 if (errno != EINTR) return true; // Error reading the file. 00131 } else { 00132 char *BufPtr = Buffer; 00133 while (Amt) { 00134 ssize_t AmtWritten = write(OutFD, BufPtr, Amt); 00135 if (AmtWritten == -1) { 00136 if (errno != EINTR) return true; // Error writing the file. 00137 } else { 00138 Amt -= AmtWritten; 00139 BufPtr += AmtWritten; 00140 } 00141 } 00142 } 00143 } 00144 00145 FR.releaseFile(); // Success! 00146 return false; 00147 } 00148 00149 00150 /// MoveFileOverIfUpdated - If the file specified by New is different than Old, 00151 /// or if Old does not exist, move the New file over the Old file. Otherwise, 00152 /// remove the New file. 00153 /// 00154 void llvm::MoveFileOverIfUpdated(const std::string &New, 00155 const std::string &Old) { 00156 if (DiffFiles(New, Old)) { 00157 if (std::rename(New.c_str(), Old.c_str())) 00158 std::cerr << "Error renaming '" << New << "' to '" << Old << "'!\n"; 00159 } else { 00160 std::remove(New.c_str()); 00161 } 00162 } 00163 00164 /// removeFile - Delete the specified file 00165 /// 00166 void llvm::removeFile(const std::string &Filename) { 00167 std::remove(Filename.c_str()); 00168 } 00169 00170 /// getUniqueFilename - Return a filename with the specified prefix. If the 00171 /// file does not exist yet, return it, otherwise add a suffix to make it 00172 /// unique. 00173 /// 00174 std::string llvm::getUniqueFilename(const std::string &FilenameBase) { 00175 if (!std::ifstream(FilenameBase.c_str())) 00176 return FilenameBase; // Couldn't open the file? Use it! 00177 00178 // Create a pattern for mkstemp... 00179 char *FNBuffer = new char[FilenameBase.size()+8]; 00180 strcpy(FNBuffer, FilenameBase.c_str()); 00181 strcpy(FNBuffer+FilenameBase.size(), "-XXXXXX"); 00182 00183 // Agree on a temporary file name to use.... 00184 #if defined(HAVE_MKSTEMP) && !defined(_MSC_VER) 00185 int TempFD; 00186 if ((TempFD = mkstemp(FNBuffer)) == -1) { 00187 // FIXME: this should return an emtpy string or something and allow the 00188 // caller to deal with the error! 00189 std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current " 00190 << " directory!\n"; 00191 exit(1); 00192 } 00193 00194 // We don't need to hold the temp file descriptor... we will trust that no one 00195 // will overwrite/delete the file while we are working on it... 00196 close(TempFD); 00197 #else 00198 // If we don't have mkstemp, use the old and obsolete mktemp function. 00199 if (mktemp(FNBuffer) == 0) { 00200 // FIXME: this should return an emtpy string or something and allow the 00201 // caller to deal with the error! 00202 std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current " 00203 << " directory!\n"; 00204 exit(1); 00205 } 00206 #endif 00207 00208 std::string Result(FNBuffer); 00209 delete[] FNBuffer; 00210 return Result; 00211 } 00212 00213 static bool AddPermissionsBits (const std::string &Filename, int bits) { 00214 // Get the umask value from the operating system. We want to use it 00215 // when changing the file's permissions. Since calling umask() sets 00216 // the umask and returns its old value, we must call it a second 00217 // time to reset it to the user's preference. 00218 int mask = umask(0777); // The arg. to umask is arbitrary. 00219 umask(mask); // Restore the umask. 00220 00221 // Get the file's current mode. 00222 struct stat st; 00223 if ((stat(Filename.c_str(), &st)) == -1) 00224 return false; 00225 00226 // Change the file to have whichever permissions bits from 'bits' 00227 // that the umask would not disable. 00228 if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1) 00229 return false; 00230 00231 return true; 00232 } 00233 00234 /// MakeFileExecutable - Make the file named Filename executable by 00235 /// setting whichever execute permissions bits the process's current 00236 /// umask would allow. Filename must name an existing file or 00237 /// directory. Returns true on success, false on error. 00238 /// 00239 bool llvm::MakeFileExecutable(const std::string &Filename) { 00240 return AddPermissionsBits(Filename, 0111); 00241 } 00242 00243 /// MakeFileReadable - Make the file named Filename readable by 00244 /// setting whichever read permissions bits the process's current 00245 /// umask would allow. Filename must name an existing file or 00246 /// directory. Returns true on success, false on error. 00247 /// 00248 bool llvm::MakeFileReadable(const std::string &Filename) { 00249 return AddPermissionsBits(Filename, 0444); 00250 } 00251 00252 /// getFileSize - Return the size of the specified file in bytes, or -1 if the 00253 /// file cannot be read or does not exist. 00254 long long llvm::getFileSize(const std::string &Filename) { 00255 struct stat StatBuf; 00256 if (stat(Filename.c_str(), &StatBuf) == -1) 00257 return -1; 00258 return StatBuf.st_size; 00259 } 00260 00261 /// getFileTimestamp - Get the last modified time for the specified file in an 00262 /// unspecified format. This is useful to allow checking to see if a file was 00263 /// updated since that last time the timestampt was aquired. If the file does 00264 /// not exist or there is an error getting the time-stamp, zero is returned. 00265 unsigned long long llvm::getFileTimestamp(const std::string &Filename) { 00266 struct stat StatBuf; 00267 if (stat(Filename.c_str(), &StatBuf) == -1) 00268 return 0; 00269 return StatBuf.st_mtime; 00270 } 00271 00272 /// ReadFileIntoAddressSpace - Attempt to map the specific file into the 00273 /// address space of the current process for reading. If this succeeds, 00274 /// return the address of the buffer and the length of the file mapped. On 00275 /// failure, return null. 00276 void *llvm::ReadFileIntoAddressSpace(const std::string &Filename, 00277 unsigned &Length) { 00278 #if defined(HAVE_MMAP_FILE) && !defined(_MSC_VER) 00279 Length = (unsigned)getFileSize(Filename); 00280 if ((int)Length == -1) return 0; 00281 00282 FDHandle FD(open(Filename.c_str(), O_RDONLY)); 00283 if (FD == -1) return 0; 00284 00285 // If the file has a length of zero, mmap might return a null pointer. In 00286 // this case, allocate a single byte of memory and return it instead. 00287 if (Length == 0) 00288 return malloc(1); 00289 00290 // mmap in the file all at once... 00291 void *Buffer = (void*)mmap(0, Length, PROT_READ, MAP_PRIVATE, FD, 0); 00292 00293 if (Buffer == (void*)MAP_FAILED) 00294 return 0; 00295 00296 return Buffer; 00297 #else 00298 // FIXME: implement with read/write 00299 #error Unimplemented ReadFileIntoAddressSpace - need to use read/write. 00300 return 0; 00301 #endif 00302 } 00303 00304 /// UnmapFileFromAddressSpace - Remove the specified file from the current 00305 /// address space. 00306 void llvm::UnmapFileFromAddressSpace(void *Buffer, unsigned Length) { 00307 #if defined(HAVE_MMAP_FILE) && !defined(_MSC_VER) 00308 if (Length) 00309 munmap((char*)Buffer, Length); 00310 else 00311 free(Buffer); // Zero byte files are malloc(1)'s. 00312 #else 00313 free(Buffer); 00314 #endif 00315 } 00316 00317 //===----------------------------------------------------------------------===// 00318 // FDHandle class implementation 00319 // 00320 00321 FDHandle::~FDHandle() throw() { 00322 if (FD != -1) close(FD); 00323 } 00324 00325 FDHandle &FDHandle::operator=(int fd) throw() { 00326 if (FD != -1) close(FD); 00327 FD = fd; 00328 return *this; 00329 } 00330