Added the MakeFileReadable() method.
[oota-llvm.git] / lib / Support / FileUtilities.cpp
1 //===- Support/FileUtilities.cpp - File System Utilities ------------------===//
2 //
3 // This file implements a family of utility functions which are useful for doing
4 // various things with files.
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "Support/FileUtilities.h"
9 #include "Config/unistd.h"
10 #include "Config/sys/stat.h"
11 #include "Config/sys/types.h"
12 #include <fstream>
13 #include <iostream>
14 #include <cstdio>
15
16 /// DiffFiles - Compare the two files specified, returning true if they are
17 /// different or if there is a file error.  If you specify a string to fill in
18 /// for the error option, it will set the string to an error message if an error
19 /// occurs, allowing the caller to distinguish between a failed diff and a file
20 /// system error.
21 ///
22 bool DiffFiles(const std::string &FileA, const std::string &FileB,
23                std::string *Error) {
24   std::ifstream FileAStream(FileA.c_str());
25   if (!FileAStream) {
26     if (Error) *Error = "Couldn't open file '" + FileA + "'";
27     return true;
28   }
29
30   std::ifstream FileBStream(FileB.c_str());
31   if (!FileBStream) {
32     if (Error) *Error = "Couldn't open file '" + FileB + "'";
33     return true;
34   }
35
36   // Compare the two files...
37   int C1, C2;
38   do {
39     C1 = FileAStream.get();
40     C2 = FileBStream.get();
41     if (C1 != C2) return true;
42   } while (C1 != EOF);
43
44   return false;
45 }
46
47
48 /// MoveFileOverIfUpdated - If the file specified by New is different than Old,
49 /// or if Old does not exist, move the New file over the Old file.  Otherwise,
50 /// remove the New file.
51 ///
52 void MoveFileOverIfUpdated(const std::string &New, const std::string &Old) {
53   if (DiffFiles(New, Old)) {
54     if (std::rename(New.c_str(), Old.c_str()))
55       std::cerr << "Error renaming '" << New << "' to '" << Old << "'!\n";
56   } else {
57     std::remove(New.c_str());
58   }  
59 }
60
61 /// removeFile - Delete the specified file
62 ///
63 void removeFile(const std::string &Filename) {
64   std::remove(Filename.c_str());
65 }
66
67 /// getUniqueFilename - Return a filename with the specified prefix.  If the
68 /// file does not exist yet, return it, otherwise add a suffix to make it
69 /// unique.
70 ///
71 std::string getUniqueFilename(const std::string &FilenameBase) {
72   if (!std::ifstream(FilenameBase.c_str()))
73     return FilenameBase;    // Couldn't open the file? Use it!
74
75   // Create a pattern for mkstemp...
76   char *FNBuffer = new char[FilenameBase.size()+8];
77   strcpy(FNBuffer, FilenameBase.c_str());
78   strcpy(FNBuffer+FilenameBase.size(), "-XXXXXX");
79
80   // Agree on a temporary file name to use....
81   int TempFD;
82   if ((TempFD = mkstemp(FNBuffer)) == -1) {
83     std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current "
84               << " directory!\n";
85     exit(1);
86   }
87
88   // We don't need to hold the temp file descriptor... we will trust that noone
89   // will overwrite/delete the file while we are working on it...
90   close(TempFD);
91   std::string Result(FNBuffer);
92   delete[] FNBuffer;
93   return Result;
94 }
95
96 ///
97 /// Method: MakeFileExecutable ()
98 ///
99 /// Description:
100 ///     This method makes the specified filename executable by giving it
101 ///     execute permission.  It respects the umask value of the process, and it
102 ///     does not enable any unnecessary access bits.
103 ///
104 /// Algorithm:
105 ///     o Get file's current permissions.
106 ///     o Get the process's current umask.
107 ///     o Take the set of all execute bits and disable those found in the umask.
108 ///     o Add the remaining permissions to the file's permissions.
109 ///
110 bool
111 MakeFileExecutable (const std::string & Filename)
112 {
113   // Permissions masking value of the user
114   mode_t mask;
115
116   // Permissions currently enabled on the file
117   struct stat fstat;
118
119   //
120   // Grab the umask value from the operating system.  We want to use it when
121   // changing the file's permissions.
122   //
123   // Note:
124   //  Umask() is one of those annoying system calls.  You have to call it
125   //  to get the current value and then set it back.
126   //
127   mask = umask (0x777);
128   umask (mask);
129
130   //
131   // Go fetch the file's current permission bits.  We want to *add* execute
132   // access to the file.
133   //
134   if ((stat (Filename.c_str(), &fstat)) == -1)
135   {
136     return false;
137   }
138
139   //
140   // Make the file executable...
141   //
142   if ((chmod(Filename.c_str(), (fstat.st_mode | (0111 & ~mask)))) == -1)
143   {
144     return false;
145   }
146
147   return true;
148 }
149
150 ///
151 /// Method: MakeFileReadable ()
152 ///
153 /// Description:
154 ///     This method makes the specified filename readable by giving it
155 ///     read permission.  It respects the umask value of the process, and it
156 ///     does not enable any unnecessary access bits.
157 ///
158 /// Algorithm:
159 ///     o Get file's current permissions.
160 ///     o Get the process's current umask.
161 ///     o Take the set of all read bits and disable those found in the umask.
162 ///     o Add the remaining permissions to the file's permissions.
163 ///
164 bool
165 MakeFileReadable (const std::string & Filename)
166 {
167   // Permissions masking value of the user
168   mode_t mask;
169
170   // Permissions currently enabled on the file
171   struct stat fstat;
172
173   //
174   // Grab the umask value from the operating system.  We want to use it when
175   // changing the file's permissions.
176   //
177   // Note:
178   //  Umask() is one of those annoying system calls.  You have to call it
179   //  to get the current value and then set it back.
180   //
181   mask = umask (0x777);
182   umask (mask);
183
184   //
185   // Go fetch the file's current permission bits.  We want to *add* execute
186   // access to the file.
187   //
188   if ((stat (Filename.c_str(), &fstat)) == -1)
189   {
190     return false;
191   }
192
193   //
194   // Make the file executable...
195   //
196   if ((chmod(Filename.c_str(), (fstat.st_mode | (0444 & ~mask)))) == -1)
197   {
198     return false;
199   }
200
201   return true;
202 }
203