Add implementation of FileOpenable().
[oota-llvm.git] / lib / Support / FileUtilities.cpp
1 //===- Support/FileUtilities.cpp - File System Utilities ------------------===//
2 // 
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 //===----------------------------------------------------------------------===//
9 //
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"
16 #include "Config/unistd.h"
17 #include "Config/sys/stat.h"
18 #include "Config/sys/types.h"
19 #include <fstream>
20 #include <iostream>
21 #include <cstdio>
22
23 /// FileOpenable - Returns true IFF Filename names an existing regular
24 /// file which we can successfully open.
25 ///
26 bool FileOpenable (const std::string &Filename) {
27   struct stat s;
28   if (stat (Filename.c_str (), &s) == -1)
29     return false; // Cannot stat file
30   if (!S_ISREG (s.st_mode))
31     return false; // File is not a regular file
32   std::ifstream FileStream (Filename.c_str ());
33   if (!FileStream)
34     return false; // File is not openable
35   return true;
36 }
37
38 /// DiffFiles - Compare the two files specified, returning true if they are
39 /// different or if there is a file error.  If you specify a string to fill in
40 /// for the error option, it will set the string to an error message if an error
41 /// occurs, allowing the caller to distinguish between a failed diff and a file
42 /// system error.
43 ///
44 bool DiffFiles(const std::string &FileA, const std::string &FileB,
45                std::string *Error) {
46   std::ifstream FileAStream(FileA.c_str());
47   if (!FileAStream) {
48     if (Error) *Error = "Couldn't open file '" + FileA + "'";
49     return true;
50   }
51
52   std::ifstream FileBStream(FileB.c_str());
53   if (!FileBStream) {
54     if (Error) *Error = "Couldn't open file '" + FileB + "'";
55     return true;
56   }
57
58   // Compare the two files...
59   int C1, C2;
60   do {
61     C1 = FileAStream.get();
62     C2 = FileBStream.get();
63     if (C1 != C2) return true;
64   } while (C1 != EOF);
65
66   return false;
67 }
68
69
70 /// MoveFileOverIfUpdated - If the file specified by New is different than Old,
71 /// or if Old does not exist, move the New file over the Old file.  Otherwise,
72 /// remove the New file.
73 ///
74 void MoveFileOverIfUpdated(const std::string &New, const std::string &Old) {
75   if (DiffFiles(New, Old)) {
76     if (std::rename(New.c_str(), Old.c_str()))
77       std::cerr << "Error renaming '" << New << "' to '" << Old << "'!\n";
78   } else {
79     std::remove(New.c_str());
80   }  
81 }
82
83 /// removeFile - Delete the specified file
84 ///
85 void removeFile(const std::string &Filename) {
86   std::remove(Filename.c_str());
87 }
88
89 /// getUniqueFilename - Return a filename with the specified prefix.  If the
90 /// file does not exist yet, return it, otherwise add a suffix to make it
91 /// unique.
92 ///
93 std::string getUniqueFilename(const std::string &FilenameBase) {
94   if (!std::ifstream(FilenameBase.c_str()))
95     return FilenameBase;    // Couldn't open the file? Use it!
96
97   // Create a pattern for mkstemp...
98   char *FNBuffer = new char[FilenameBase.size()+8];
99   strcpy(FNBuffer, FilenameBase.c_str());
100   strcpy(FNBuffer+FilenameBase.size(), "-XXXXXX");
101
102   // Agree on a temporary file name to use....
103   int TempFD;
104   if ((TempFD = mkstemp(FNBuffer)) == -1) {
105     std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current "
106               << " directory!\n";
107     exit(1);
108   }
109
110   // We don't need to hold the temp file descriptor... we will trust that no one
111   // will overwrite/delete the file while we are working on it...
112   close(TempFD);
113   std::string Result(FNBuffer);
114   delete[] FNBuffer;
115   return Result;
116 }
117
118 static bool AddPermissionsBits (const std::string &Filename, mode_t bits) {
119   // Get the umask value from the operating system.  We want to use it
120   // when changing the file's permissions. Since calling umask() sets
121   // the umask and returns its old value, we must call it a second
122   // time to reset it to the user's preference.
123   mode_t mask = umask (0777); // The arg. to umask is arbitrary...
124   umask (mask);
125
126   // Get the file's current mode.
127   struct stat st;
128   if ((stat (Filename.c_str(), &st)) == -1)
129     return false;
130
131   // Change the file to have whichever permissions bits from 'bits'
132   // that the umask would not disable.
133   if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1)
134     return false;
135
136   return true;
137 }
138
139 /// MakeFileExecutable - Make the file named Filename executable by
140 /// setting whichever execute permissions bits the process's current
141 /// umask would allow. Filename must name an existing file or
142 /// directory.  Returns true on success, false on error.
143 ///
144 bool MakeFileExecutable (const std::string &Filename) {
145   return AddPermissionsBits (Filename, 0111);
146 }
147
148 /// MakeFileReadable - Make the file named Filename readable by
149 /// setting whichever read permissions bits the process's current
150 /// umask would allow. Filename must name an existing file or
151 /// directory.  Returns true on success, false on error.
152 ///
153 bool MakeFileReadable (const std::string &Filename) {
154   return AddPermissionsBits (Filename, 0444);
155 }