blob: 9a860a0672f2b11b310683bf593c507aa1442e0d [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
Reid Spencer8e665952004-08-29 05:24:01 +000046Path
47Path::GetSystemLibraryPath1() {
48 return Path("/lib/");
49}
50
51Path
52Path::GetSystemLibraryPath2() {
53 return Path("/usr/lib/");
54}
55
56Path
57Path::GetLLVMDefaultConfigDir() {
58 return Path("/etc/llvm/");
59}
60
61Path
62Path::GetLLVMConfigDir() {
63 Path result;
64 if (result.set_directory(LLVM_ETCDIR))
65 return result;
66 return GetLLVMDefaultConfigDir();
67}
68
69Path
70Path::GetUserHomeDirectory() {
71 const char* home = getenv("HOME");
72 if (home) {
73 Path result;
74 if (result.set_directory(home))
75 return result;
76 }
77 return GetRootDirectory();
78}
79
80bool
81Path::exists() const {
82 return 0 == access(path.c_str(), F_OK );
83}
84
85bool
86Path::readable() const {
87 return 0 == access(path.c_str(), F_OK | R_OK );
88}
89
90bool
91Path::writable() const {
92 return 0 == access(path.c_str(), F_OK | W_OK );
93}
94
95bool
96Path::executable() const {
97 return 0 == access(path.c_str(), R_OK | X_OK );
98}
99
100std::string
101Path::getLast() const {
102 // Find the last slash
103 size_t pos = path.rfind('/');
104
105 // Handle the corner cases
106 if (pos == std::string::npos)
107 return path;
108
109 // If the last character is a slash
110 if (pos == path.length()-1) {
111 // Find the second to last slash
112 size_t pos2 = path.rfind('/', pos-1);
113 if (pos2 == std::string::npos)
114 return path.substr(0,pos);
115 else
116 return path.substr(pos2+1,pos-pos2-1);
117 }
118 // Return everything after the last slash
119 return path.substr(pos+1);
120}
121
122bool
123Path::set_directory(const std::string& a_path) {
124 if (a_path.size() == 0)
125 return false;
126 Path save(*this);
127 path = a_path;
128 size_t last = a_path.size() -1;
129 if (last != 0 && a_path[last] != '/')
130 path += '/';
131 if (!is_valid()) {
132 path = save.path;
133 return false;
134 }
135 return true;
136}
137
138bool
139Path::set_file(const std::string& a_path) {
140 if (a_path.size() == 0)
141 return false;
142 Path save(*this);
143 path = a_path;
144 size_t last = a_path.size() - 1;
145 while (last > 0 && a_path[last] == '/')
146 last--;
147 path.erase(last+1);
148 if (!is_valid()) {
149 path = save.path;
150 return false;
151 }
152 return true;
153}
154
155bool
156Path::append_directory(const std::string& dir) {
157 if (is_file())
158 return false;
159 Path save(*this);
160 path += dir;
161 path += "/";
162 if (!is_valid()) {
163 path = save.path;
164 return false;
165 }
166 return true;
167}
168
169bool
170Path::elide_directory() {
171 if (is_file())
172 return false;
173 size_t slashpos = path.rfind('/',path.size());
174 if (slashpos == 0 || slashpos == std::string::npos)
175 return false;
176 if (slashpos == path.size() - 1)
177 slashpos = path.rfind('/',slashpos-1);
178 if (slashpos == std::string::npos)
179 return false;
180 path.erase(slashpos);
181 return true;
182}
183
184bool
185Path::append_file(const std::string& file) {
186 if (!is_directory())
187 return false;
188 Path save(*this);
189 path += file;
190 if (!is_valid()) {
191 path = save.path;
192 return false;
193 }
194 return true;
195}
196
197bool
198Path::elide_file() {
199 if (is_directory())
200 return false;
201 size_t slashpos = path.rfind('/',path.size());
202 if (slashpos == std::string::npos)
203 return false;
204 path.erase(slashpos+1);
205 return true;
206}
207
208bool
209Path::append_suffix(const std::string& suffix) {
210 if (is_directory())
211 return false;
212 Path save(*this);
213 path.append(".");
214 path.append(suffix);
215 if (!is_valid()) {
216 path = save.path;
217 return false;
218 }
219 return true;
220}
221
222bool
223Path::elide_suffix() {
224 if (is_directory()) return false;
225 size_t dotpos = path.rfind('.',path.size());
226 size_t slashpos = path.rfind('/',path.size());
227 if (slashpos != std::string::npos && dotpos != std::string::npos &&
228 dotpos > slashpos) {
229 path.erase(dotpos, path.size()-dotpos);
230 return true;
231 }
232 return false;
233}
234
235
236bool
237Path::create_directory( bool create_parents) {
238 // Make sure we're dealing with a directory
239 if (!is_directory()) return false;
240
241 // Get a writeable copy of the path name
242 char pathname[MAXPATHLEN];
243 path.copy(pathname,MAXPATHLEN);
244
245 // Null-terminate the last component
246 int lastchar = path.length() - 1 ;
247 if (pathname[lastchar] == '/')
248 pathname[lastchar] = 0;
249
250 // If we're supposed to create intermediate directories
251 if ( create_parents ) {
252 // Find the end of the initial name component
253 char * next = strchr(pathname,'/');
254 if ( pathname[0] == '/')
255 next = strchr(&pathname[1],'/');
256
257 // Loop through the directory components until we're done
258 while ( next != 0 ) {
259 *next = 0;
260 if (0 != access(pathname, F_OK | R_OK | W_OK))
261 if (0 != mkdir(pathname, S_IRWXU | S_IRWXG))
262 ThrowErrno(std::string(pathname) + ": Can't create directory");
263 char* save = next;
264 next = strchr(pathname,'/');
265 *save = '/';
266 }
267 } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
268 ThrowErrno(std::string(pathname) + ": Can't create directory");
269 }
270 return true;
271}
272
273bool
Reid Spencerb89a2232004-08-25 06:20:07 +0000274Path::create_file() {
Reid Spencer8e665952004-08-29 05:24:01 +0000275 // Make sure we're dealing with a file
276 if (!is_file()) return false;
277
278 // Create the file
279 if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
280 ThrowErrno(std::string(path.c_str()) + ": Can't create file");
281
282 return true;
Reid Spencerb89a2232004-08-25 06:20:07 +0000283}
284
Reid Spencer8e665952004-08-29 05:24:01 +0000285bool
286Path::destroy_directory(bool remove_contents) {
287 // Make sure we're dealing with a directory
288 if (!is_directory()) return false;
289
290 // If it doesn't exist, we're done.
291 if (!exists()) return true;
292
293 if (remove_contents) {
294 // Recursively descend the directory to remove its content
295 std::string cmd("/bin/rm -rf ");
296 cmd += path;
297 system(cmd.c_str());
298 } else {
299 // Otherwise, try to just remove the one directory
300 char pathname[MAXPATHLEN];
301 path.copy(pathname,MAXPATHLEN);
302 int lastchar = path.length() - 1 ;
303 if (pathname[lastchar] == '/')
304 pathname[lastchar] = 0;
305 if ( 0 != rmdir(pathname))
306 ThrowErrno(std::string(pathname) + ": Can't destroy directory");
307 }
308 return true;
309}
310
311bool
312Path::destroy_file() {
313 if (!is_file()) return false;
314 if (0 != unlink(path.c_str()))
315 ThrowErrno(std::string(path.c_str()) + ": Can't destroy file");
316 return true;
317}
318
Reid Spencerb89a2232004-08-25 06:20:07 +0000319}
320
321// vim: sw=2