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