1 //===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
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.
8 //===----------------------------------------------------------------------===//
10 // This file implements the Unix specific portion of the Path class.
12 //===----------------------------------------------------------------------===//
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //=== is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
22 #include <Config/config.h>
27 Path::Path(std::string unverified_path)
28 : path(unverified_path)
30 if (unverified_path.empty())
36 ThrowErrno(unverified_path + ": path is not valid");
40 Path::GetRootDirectory() {
42 result.set_directory("/");
47 Path::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");
53 result.set_directory(pathname);
54 assert(result.is_valid() && "mkdtemp didn't create a valid pathname!");
59 Path::GetSystemLibraryPath1() {
64 Path::GetSystemLibraryPath2() {
65 return Path("/usr/lib/");
69 Path::GetLLVMDefaultConfigDir() {
70 return Path("/etc/llvm/");
74 Path::GetLLVMConfigDir() {
76 if (result.set_directory(LLVM_ETCDIR))
78 return GetLLVMDefaultConfigDir();
82 Path::GetUserHomeDirectory() {
83 const char* home = getenv("HOME");
86 if (result.set_directory(home))
89 return GetRootDirectory();
93 Path::exists() const {
94 return 0 == access(path.c_str(), F_OK );
98 Path::readable() const {
99 return 0 == access(path.c_str(), F_OK | R_OK );
103 Path::writable() const {
104 return 0 == access(path.c_str(), F_OK | W_OK );
108 Path::executable() const {
109 return 0 == access(path.c_str(), R_OK | X_OK );
113 Path::getLast() const {
114 // Find the last slash
115 size_t pos = path.rfind('/');
117 // Handle the corner cases
118 if (pos == std::string::npos)
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);
128 return path.substr(pos2+1,pos-pos2-1);
130 // Return everything after the last slash
131 return path.substr(pos+1);
135 Path::set_directory(const std::string& a_path) {
136 if (a_path.size() == 0)
140 size_t last = a_path.size() -1;
141 if (last != 0 && a_path[last] != '/')
151 Path::set_file(const std::string& a_path) {
152 if (a_path.size() == 0)
156 size_t last = a_path.size() - 1;
157 while (last > 0 && a_path[last] == '/')
168 Path::append_directory(const std::string& dir) {
182 Path::elide_directory() {
185 size_t slashpos = path.rfind('/',path.size());
186 if (slashpos == 0 || slashpos == std::string::npos)
188 if (slashpos == path.size() - 1)
189 slashpos = path.rfind('/',slashpos-1);
190 if (slashpos == std::string::npos)
192 path.erase(slashpos);
197 Path::append_file(const std::string& file) {
213 size_t slashpos = path.rfind('/',path.size());
214 if (slashpos == std::string::npos)
216 path.erase(slashpos+1);
221 Path::append_suffix(const std::string& suffix) {
235 Path::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 &&
241 path.erase(dotpos, path.size()-dotpos);
249 Path::create_directory( bool create_parents) {
250 // Make sure we're dealing with a directory
251 if (!is_directory()) return false;
253 // Get a writeable copy of the path name
254 char pathname[MAXPATHLEN];
255 path.copy(pathname,MAXPATHLEN);
257 // Null-terminate the last component
258 int lastchar = path.length() - 1 ;
259 if (pathname[lastchar] == '/')
260 pathname[lastchar] = 0;
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],'/');
269 // Loop through the directory components until we're done
270 while ( 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");
276 next = strchr(pathname,'/');
279 } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
280 ThrowErrno(std::string(pathname) + ": Can't create directory");
286 Path::create_file() {
287 // Make sure we're dealing with a file
288 if (!is_file()) return false;
291 if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
292 ThrowErrno(std::string(path.c_str()) + ": Can't create file");
298 Path::destroy_directory(bool remove_contents) {
299 // Make sure we're dealing with a directory
300 if (!is_directory()) return false;
302 // If it doesn't exist, we're done.
303 if (!exists()) return true;
305 if (remove_contents) {
306 // Recursively descend the directory to remove its content
307 std::string cmd("/bin/rm -rf ");
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");
324 Path::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");