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 //===----------------------------------------------------------------------===//
19 #include <llvm/Config/config.h>
28 Path::Path(std::string unverified_path)
29 : path(unverified_path)
31 if (unverified_path.empty())
37 ThrowErrno(unverified_path + ": path is not valid");
41 Path::GetRootDirectory() {
43 result.set_directory("/");
48 Path::GetSystemLibraryPath1() {
53 Path::GetSystemLibraryPath2() {
54 return Path("/usr/lib/");
58 Path::GetLLVMDefaultConfigDir() {
59 return Path("/etc/llvm/");
63 Path::GetLLVMConfigDir() {
65 if (result.set_directory(LLVM_ETCDIR))
67 return GetLLVMDefaultConfigDir();
71 Path::GetUserHomeDirectory() {
72 const char* home = getenv("HOME");
75 if (result.set_directory(home))
78 return GetRootDirectory();
82 Path::is_file() const {
83 return (is_valid() && path[path.length()-1] != '/');
87 Path::is_directory() const {
88 return (is_valid() && path[path.length()-1] == '/');
92 Path::get_basename() const {
93 // Find the last slash
94 size_t slash = path.rfind('/');
95 if (slash == std::string::npos)
100 return path.substr(slash, path.rfind('.'));
103 bool Path::has_magic_number(const std::string &Magic) const {
104 size_t len = Magic.size();
106 std::ifstream f(path.c_str());
113 Path::is_bytecode_file() const {
115 return has_magic_number("llvm");
121 Path::is_archive() const {
123 return has_magic_number("!<arch>\012");
129 Path::exists() const {
130 return 0 == access(path.c_str(), F_OK );
134 Path::readable() const {
135 return 0 == access(path.c_str(), F_OK | R_OK );
139 Path::writable() const {
140 return 0 == access(path.c_str(), F_OK | W_OK );
144 Path::executable() const {
145 return 0 == access(path.c_str(), R_OK | X_OK );
149 Path::getLast() const {
150 // Find the last slash
151 size_t pos = path.rfind('/');
153 // Handle the corner cases
154 if (pos == std::string::npos)
157 // If the last character is a slash
158 if (pos == path.length()-1) {
159 // Find the second to last slash
160 size_t pos2 = path.rfind('/', pos-1);
161 if (pos2 == std::string::npos)
162 return path.substr(0,pos);
164 return path.substr(pos2+1,pos-pos2-1);
166 // Return everything after the last slash
167 return path.substr(pos+1);
171 Path::set_directory(const std::string& a_path) {
172 if (a_path.size() == 0)
176 size_t last = a_path.size() -1;
177 if (last != 0 && a_path[last] != '/')
187 Path::set_file(const std::string& a_path) {
188 if (a_path.size() == 0)
192 size_t last = a_path.size() - 1;
193 while (last > 0 && a_path[last] == '/')
204 Path::append_directory(const std::string& dir) {
218 Path::elide_directory() {
221 size_t slashpos = path.rfind('/',path.size());
222 if (slashpos == 0 || slashpos == std::string::npos)
224 if (slashpos == path.size() - 1)
225 slashpos = path.rfind('/',slashpos-1);
226 if (slashpos == std::string::npos)
228 path.erase(slashpos);
233 Path::append_file(const std::string& file) {
249 size_t slashpos = path.rfind('/',path.size());
250 if (slashpos == std::string::npos)
252 path.erase(slashpos+1);
257 Path::append_suffix(const std::string& suffix) {
271 Path::elide_suffix() {
272 if (is_directory()) return false;
273 size_t dotpos = path.rfind('.',path.size());
274 size_t slashpos = path.rfind('/',path.size());
275 if (slashpos != std::string::npos && dotpos != std::string::npos &&
277 path.erase(dotpos, path.size()-dotpos);
285 Path::create_directory( bool create_parents) {
286 // Make sure we're dealing with a directory
287 if (!is_directory()) return false;
289 // Get a writeable copy of the path name
290 char pathname[MAXPATHLEN];
291 path.copy(pathname,MAXPATHLEN);
293 // Null-terminate the last component
294 int lastchar = path.length() - 1 ;
295 if (pathname[lastchar] == '/')
296 pathname[lastchar] = 0;
298 // If we're supposed to create intermediate directories
299 if ( create_parents ) {
300 // Find the end of the initial name component
301 char * next = strchr(pathname,'/');
302 if ( pathname[0] == '/')
303 next = strchr(&pathname[1],'/');
305 // Loop through the directory components until we're done
306 while ( next != 0 ) {
308 if (0 != access(pathname, F_OK | R_OK | W_OK))
309 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
310 ThrowErrno(std::string(pathname) + ": Can't create directory");
312 next = strchr(pathname,'/');
315 } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
316 ThrowErrno(std::string(pathname) + ": Can't create directory");
322 Path::create_file() {
323 // Make sure we're dealing with a file
324 if (!is_file()) return false;
327 if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
328 ThrowErrno(std::string(path.c_str()) + ": Can't create file");
334 Path::destroy_directory(bool remove_contents) {
335 // Make sure we're dealing with a directory
336 if (!is_directory()) return false;
338 // If it doesn't exist, we're done.
339 if (!exists()) return true;
341 if (remove_contents) {
342 // Recursively descend the directory to remove its content
343 std::string cmd("/bin/rm -rf ");
347 // Otherwise, try to just remove the one directory
348 char pathname[MAXPATHLEN];
349 path.copy(pathname,MAXPATHLEN);
350 int lastchar = path.length() - 1 ;
351 if (pathname[lastchar] == '/')
352 pathname[lastchar] = 0;
353 if ( 0 != rmdir(pathname))
354 ThrowErrno(std::string(pathname) + ": Can't destroy directory");
360 Path::destroy_file() {
361 if (!is_file()) return false;
362 if (0 != unlink(path.c_str()))
363 ThrowErrno(std::string(path.c_str()) + ": Can't destroy file");