Added the MakeFileExecutable() method. This method takes a filename and
[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.
102 ///
103 ///     For the UNIX version of this method, we turn on all of the read and
104 ///     execute bits and then turn off anything specified in the umask.  This
105 ///     should help ensure that access to the file remains at the level that
106 ///     the user desires.
107 ///
108 bool
109 MakeFileExecutable (const std::string & Filename)
110 {
111   // Permissions masking value of the user
112   mode_t mask;
113
114   // Permissions currently enabled on the file
115   struct stat fstat;
116
117   //
118   // Grab the umask value from the operating system.  We want to use it when
119   // changing the file's permissions.
120   //
121   // Note:
122   //  Umask() is one of those annoying system calls.  You have to call it
123   //  to get the current value and then set it back.
124   //
125   mask = umask (0x777);
126   umask (mask);
127
128   //
129   // Go fetch the file's current permission bits.  We want to *add* execute
130   // access to the file.
131   //
132   if ((stat (Filename.c_str(), &fstat)) == -1)
133   {
134     return false;
135   }
136
137   // Make the script executable...
138   chmod(Filename.c_str(), (fstat.st_mode | (0111 & ~mask)));
139
140   return true;
141 }
142