blob: 9d9dd99103feac25d11758c736cd48f434bc6af2 [file] [log] [blame]
Reid Spencerb89a2232004-08-25 06:20:07 +00001//===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Reid Spencer and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Unix specific portion of the Path class.
11//
12//===----------------------------------------------------------------------===//
13
14//===----------------------------------------------------------------------===//
15//=== WARNING: Implementation here must contain only generic UNIX code that
Reid Spencer8e665952004-08-29 05:24:01 +000016//=== is guaranteed to work on *all* UNIX variants.
Reid Spencerb89a2232004-08-25 06:20:07 +000017//===----------------------------------------------------------------------===//
18
19#include "Unix.h"
20#include <sys/stat.h>
21#include <fcntl.h>
Reid Spencer8e665952004-08-29 05:24:01 +000022#include <Config/config.h>
Reid Spencerb89a2232004-08-25 06:20:07 +000023
Reid Spencer8e665952004-08-29 05:24:01 +000024namespace llvm {
25using namespace sys;
Reid Spencerb89a2232004-08-25 06:20:07 +000026
Reid Spencer8e665952004-08-29 05:24:01 +000027Path::Path(std::string unverified_path)
28 : path(unverified_path)
Reid Spencerb89a2232004-08-25 06:20:07 +000029{
Reid Spencer8e665952004-08-29 05:24:01 +000030 if (unverified_path.empty())
31 return;
32 if (this->is_valid())
33 return;
34 // oops, not valid.
35 path.clear();
36 ThrowErrno(unverified_path + ": path is not valid");
Reid Spencerb89a2232004-08-25 06:20:07 +000037}
38
Reid Spencer8e665952004-08-29 05:24:01 +000039Path
40Path::GetRootDirectory() {
41 Path result;
42 result.set_directory("/");
43 return result;
44}
45
46Path
47Path::GetTemporaryDirectory() {
48 char pathname[MAXPATHLEN];
49 strcpy(pathname,"/tmp/llvm_XXXXXX");
50 if (0 == mkdtemp(pathname))
51 ThrowErrno(std::string(pathname) + ": Can't create temporary directory");
52 Path result;
53 result.set_directory(pathname);
54 assert(result.is_valid() && "mkdtemp didn't create a valid pathname!");
55 return result;
56}
57
58Path
59Path::GetSystemLibraryPath1() {
60 return Path("/lib/");
61}
62
63Path
64Path::GetSystemLibraryPath2() {
65 return Path("/usr/lib/");
66}
67
68Path
69Path::GetLLVMDefaultConfigDir() {
70 return Path("/etc/llvm/");
71}
72
73Path
74Path::GetLLVMConfigDir() {
75 Path result;
76 if (result.set_directory(LLVM_ETCDIR))
77 return result;
78 return GetLLVMDefaultConfigDir();
79}
80
81Path
82Path::GetUserHomeDirectory() {
83 const char* home = getenv("HOME");
84 if (home) {
85 Path result;
86 if (result.set_directory(home))
87 return result;
88 }
89 return GetRootDirectory();
90}
91
92bool
93Path::exists() const {
94 return 0 == access(path.c_str(), F_OK );
95}
96
97bool
98Path::readable() const {
99 return 0 == access(path.c_str(), F_OK | R_OK );
100}
101
102bool
103Path::writable() const {
104 return 0 == access(path.c_str(), F_OK | W_OK );
105}
106
107bool
108Path::executable() const {
109 return 0 == access(path.c_str(), R_OK | X_OK );
110}
111
112std::string
113Path::getLast() const {
114 // Find the last slash
115 size_t pos = path.rfind('/');
116
117 // Handle the corner cases
118 if (pos == std::string::npos)
119 return path;
120
121 // If the last character is a slash
122 if (pos == path.length()-1) {
123 // Find the second to last slash
124 size_t pos2 = path.rfind('/', pos-1);
125 if (pos2 == std::string::npos)
126 return path.substr(0,pos);
127 else
128 return path.substr(pos2+1,pos-pos2-1);
129 }
130 // Return everything after the last slash
131 return path.substr(pos+1);
132}
133
134bool
135Path::set_directory(const std::string& a_path) {
136 if (a_path.size() == 0)
137 return false;
138 Path save(*this);
139 path = a_path;
140 size_t last = a_path.size() -1;
141 if (last != 0 && a_path[last] != '/')
142 path += '/';
143 if (!is_valid()) {
144 path = save.path;
145 return false;
146 }
147 return true;
148}
149
150bool
151Path::set_file(const std::string& a_path) {
152 if (a_path.size() == 0)
153 return false;
154 Path save(*this);
155 path = a_path;
156 size_t last = a_path.size() - 1;
157 while (last > 0 && a_path[last] == '/')
158 last--;
159 path.erase(last+1);
160 if (!is_valid()) {
161 path = save.path;
162 return false;
163 }
164 return true;
165}
166
167bool
168Path::append_directory(const std::string& dir) {
169 if (is_file())
170 return false;
171 Path save(*this);
172 path += dir;
173 path += "/";
174 if (!is_valid()) {
175 path = save.path;
176 return false;
177 }
178 return true;
179}
180
181bool
182Path::elide_directory() {
183 if (is_file())
184 return false;
185 size_t slashpos = path.rfind('/',path.size());
186 if (slashpos == 0 || slashpos == std::string::npos)
187 return false;
188 if (slashpos == path.size() - 1)
189 slashpos = path.rfind('/',slashpos-1);
190 if (slashpos == std::string::npos)
191 return false;
192 path.erase(slashpos);
193 return true;
194}
195
196bool
197Path::append_file(const std::string& file) {
198 if (!is_directory())
199 return false;
200 Path save(*this);
201 path += file;
202 if (!is_valid()) {
203 path = save.path;
204 return false;
205 }
206 return true;
207}
208
209bool
210Path::elide_file() {
211 if (is_directory())
212 return false;
213 size_t slashpos = path.rfind('/',path.size());
214 if (slashpos == std::string::npos)
215 return false;
216 path.erase(slashpos+1);
217 return true;
218}
219
220bool
221Path::append_suffix(const std::string& suffix) {
222 if (is_directory())
223 return false;
224 Path save(*this);
225 path.append(".");
226 path.append(suffix);
227 if (!is_valid()) {
228 path = save.path;
229 return false;
230 }
231 return true;
232}
233
234bool
235Path::elide_suffix() {
236 if (is_directory()) return false;
237 size_t dotpos = path.rfind('.',path.size());
238 size_t slashpos = path.rfind('/',path.size());
239 if (slashpos != std::string::npos && dotpos != std::string::npos &&
240 dotpos > slashpos) {
241 path.erase(dotpos, path.size()-dotpos);
242 return true;
243 }
244 return false;
245}
246
247
248bool
249Path::create_directory( bool create_parents) {
250 // Make sure we're dealing with a directory
251 if (!is_directory()) return false;
252
253 // Get a writeable copy of the path name
254 char pathname[MAXPATHLEN];
255 path.copy(pathname,MAXPATHLEN);
256
257 // Null-terminate the last component
258 int lastchar = path.length() - 1 ;
259 if (pathname[lastchar] == '/')
260 pathname[lastchar] = 0;
261
262 // If we're supposed to create intermediate directories
263 if ( create_parents ) {
264 // Find the end of the initial name component
265 char * next = strchr(pathname,'/');
266 if ( pathname[0] == '/')
267 next = strchr(&pathname[1],'/');
268
269 // Loop through the directory components until we're done
270 while ( next != 0 ) {
271 *next = 0;
272 if (0 != access(pathname, F_OK | R_OK | W_OK))
273 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
274 ThrowErrno(std::string(pathname) + ": Can't create directory");
275 char* save = next;
276 next = strchr(pathname,'/');
277 *save = '/';
278 }
279 } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
280 ThrowErrno(std::string(pathname) + ": Can't create directory");
281 }
282 return true;
283}
284
285bool
Reid Spencerb89a2232004-08-25 06:20:07 +0000286Path::create_file() {
Reid Spencer8e665952004-08-29 05:24:01 +0000287 // Make sure we're dealing with a file
288 if (!is_file()) return false;
289
290 // Create the file
291 if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
292 ThrowErrno(std::string(path.c_str()) + ": Can't create file");
293
294 return true;
Reid Spencerb89a2232004-08-25 06:20:07 +0000295}
296
Reid Spencer8e665952004-08-29 05:24:01 +0000297bool
298Path::destroy_directory(bool remove_contents) {
299 // Make sure we're dealing with a directory
300 if (!is_directory()) return false;
301
302 // If it doesn't exist, we're done.
303 if (!exists()) return true;
304
305 if (remove_contents) {
306 // Recursively descend the directory to remove its content
307 std::string cmd("/bin/rm -rf ");
308 cmd += path;
309 system(cmd.c_str());
310 } else {
311 // Otherwise, try to just remove the one directory
312 char pathname[MAXPATHLEN];
313 path.copy(pathname,MAXPATHLEN);
314 int lastchar = path.length() - 1 ;
315 if (pathname[lastchar] == '/')
316 pathname[lastchar] = 0;
317 if ( 0 != rmdir(pathname))
318 ThrowErrno(std::string(pathname) + ": Can't destroy directory");
319 }
320 return true;
321}
322
323bool
324Path::destroy_file() {
325 if (!is_file()) return false;
326 if (0 != unlink(path.c_str()))
327 ThrowErrno(std::string(path.c_str()) + ": Can't destroy file");
328 return true;
329}
330
Reid Spencerb89a2232004-08-25 06:20:07 +0000331}
332
333// vim: sw=2