blob: 23b938b9019fceb42d06656d6d78bf004c8c18b4 [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
Reid Spencer551ccae2004-09-01 22:55:40 +000019#include <llvm/Config/config.h>
Reid Spencerb89a2232004-08-25 06:20:07 +000020#include "Unix.h"
21#include <sys/stat.h>
22#include <fcntl.h>
Reid Spencer1b554b42004-09-11 04:55:08 +000023#include <fstream>
Reid Spencerb89a2232004-08-25 06:20:07 +000024
Reid Spencer8e665952004-08-29 05:24:01 +000025namespace llvm {
26using namespace sys;
Reid Spencerb89a2232004-08-25 06:20:07 +000027
Reid Spencer8e665952004-08-29 05:24:01 +000028Path::Path(std::string unverified_path)
29 : path(unverified_path)
Reid Spencerb89a2232004-08-25 06:20:07 +000030{
Reid Spencer8e665952004-08-29 05:24:01 +000031 if (unverified_path.empty())
32 return;
33 if (this->is_valid())
34 return;
35 // oops, not valid.
36 path.clear();
37 ThrowErrno(unverified_path + ": path is not valid");
Reid Spencerb89a2232004-08-25 06:20:07 +000038}
39
Reid Spencer8e665952004-08-29 05:24:01 +000040Path
41Path::GetRootDirectory() {
42 Path result;
43 result.set_directory("/");
44 return result;
45}
46
Reid Spencer8e665952004-08-29 05:24:01 +000047Path
48Path::GetSystemLibraryPath1() {
49 return Path("/lib/");
50}
51
52Path
53Path::GetSystemLibraryPath2() {
54 return Path("/usr/lib/");
55}
56
57Path
58Path::GetLLVMDefaultConfigDir() {
59 return Path("/etc/llvm/");
60}
61
62Path
63Path::GetLLVMConfigDir() {
64 Path result;
65 if (result.set_directory(LLVM_ETCDIR))
66 return result;
67 return GetLLVMDefaultConfigDir();
68}
69
70Path
71Path::GetUserHomeDirectory() {
72 const char* home = getenv("HOME");
73 if (home) {
74 Path result;
75 if (result.set_directory(home))
76 return result;
77 }
78 return GetRootDirectory();
79}
80
81bool
Reid Spencer1b554b42004-09-11 04:55:08 +000082Path::is_file() const {
83 return (is_valid() && path[path.length()-1] != '/');
84}
85
86bool
87Path::is_directory() const {
88 return (is_valid() && path[path.length()-1] == '/');
89}
90
91std::string
92Path::get_basename() const {
93 // Find the last slash
94 size_t slash = path.rfind('/');
95 if (slash == std::string::npos)
96 slash = 0;
97 else
98 slash++;
99
100 return path.substr(slash, path.rfind('.'));
101}
102
103bool Path::has_magic_number(const std::string &Magic) const {
104 size_t len = Magic.size();
105 char buf[ 1 + len];
106 std::ifstream f(path.c_str());
107 f.read(buf, len);
108 buf[len] = '\0';
109 return Magic == buf;
110}
111
112bool
113Path::is_bytecode_file() const {
114 if (readable()) {
115 return has_magic_number("llvm");
116 }
117 return false;
118}
119
120bool
121Path::is_archive() const {
122 if (readable()) {
123 return has_magic_number("!<arch>\012");
124 }
125 return false;
126}
127
128bool
Reid Spencer8e665952004-08-29 05:24:01 +0000129Path::exists() const {
130 return 0 == access(path.c_str(), F_OK );
131}
132
133bool
134Path::readable() const {
135 return 0 == access(path.c_str(), F_OK | R_OK );
136}
137
138bool
139Path::writable() const {
140 return 0 == access(path.c_str(), F_OK | W_OK );
141}
142
143bool
144Path::executable() const {
145 return 0 == access(path.c_str(), R_OK | X_OK );
146}
147
148std::string
149Path::getLast() const {
150 // Find the last slash
151 size_t pos = path.rfind('/');
152
153 // Handle the corner cases
154 if (pos == std::string::npos)
155 return path;
156
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);
163 else
164 return path.substr(pos2+1,pos-pos2-1);
165 }
166 // Return everything after the last slash
167 return path.substr(pos+1);
168}
169
170bool
171Path::set_directory(const std::string& a_path) {
172 if (a_path.size() == 0)
173 return false;
174 Path save(*this);
175 path = a_path;
176 size_t last = a_path.size() -1;
177 if (last != 0 && a_path[last] != '/')
178 path += '/';
179 if (!is_valid()) {
180 path = save.path;
181 return false;
182 }
183 return true;
184}
185
186bool
187Path::set_file(const std::string& a_path) {
188 if (a_path.size() == 0)
189 return false;
190 Path save(*this);
191 path = a_path;
192 size_t last = a_path.size() - 1;
193 while (last > 0 && a_path[last] == '/')
194 last--;
195 path.erase(last+1);
196 if (!is_valid()) {
197 path = save.path;
198 return false;
199 }
200 return true;
201}
202
203bool
204Path::append_directory(const std::string& dir) {
205 if (is_file())
206 return false;
207 Path save(*this);
208 path += dir;
209 path += "/";
210 if (!is_valid()) {
211 path = save.path;
212 return false;
213 }
214 return true;
215}
216
217bool
218Path::elide_directory() {
219 if (is_file())
220 return false;
221 size_t slashpos = path.rfind('/',path.size());
222 if (slashpos == 0 || slashpos == std::string::npos)
223 return false;
224 if (slashpos == path.size() - 1)
225 slashpos = path.rfind('/',slashpos-1);
226 if (slashpos == std::string::npos)
227 return false;
228 path.erase(slashpos);
229 return true;
230}
231
232bool
233Path::append_file(const std::string& file) {
234 if (!is_directory())
235 return false;
236 Path save(*this);
237 path += file;
238 if (!is_valid()) {
239 path = save.path;
240 return false;
241 }
242 return true;
243}
244
245bool
246Path::elide_file() {
247 if (is_directory())
248 return false;
249 size_t slashpos = path.rfind('/',path.size());
250 if (slashpos == std::string::npos)
251 return false;
252 path.erase(slashpos+1);
253 return true;
254}
255
256bool
257Path::append_suffix(const std::string& suffix) {
258 if (is_directory())
259 return false;
260 Path save(*this);
261 path.append(".");
262 path.append(suffix);
263 if (!is_valid()) {
264 path = save.path;
265 return false;
266 }
267 return true;
268}
269
270bool
271Path::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 &&
276 dotpos > slashpos) {
277 path.erase(dotpos, path.size()-dotpos);
278 return true;
279 }
280 return false;
281}
282
283
284bool
285Path::create_directory( bool create_parents) {
286 // Make sure we're dealing with a directory
287 if (!is_directory()) return false;
288
289 // Get a writeable copy of the path name
290 char pathname[MAXPATHLEN];
291 path.copy(pathname,MAXPATHLEN);
292
293 // Null-terminate the last component
294 int lastchar = path.length() - 1 ;
295 if (pathname[lastchar] == '/')
296 pathname[lastchar] = 0;
297
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],'/');
304
305 // Loop through the directory components until we're done
306 while ( next != 0 ) {
307 *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");
311 char* save = next;
312 next = strchr(pathname,'/');
313 *save = '/';
314 }
315 } else if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) {
316 ThrowErrno(std::string(pathname) + ": Can't create directory");
317 }
318 return true;
319}
320
321bool
Reid Spencerb89a2232004-08-25 06:20:07 +0000322Path::create_file() {
Reid Spencer8e665952004-08-29 05:24:01 +0000323 // Make sure we're dealing with a file
324 if (!is_file()) return false;
325
326 // Create the file
327 if (0 != creat(path.c_str(), S_IRUSR | S_IWUSR))
328 ThrowErrno(std::string(path.c_str()) + ": Can't create file");
329
330 return true;
Reid Spencerb89a2232004-08-25 06:20:07 +0000331}
332
Reid Spencer8e665952004-08-29 05:24:01 +0000333bool
334Path::destroy_directory(bool remove_contents) {
335 // Make sure we're dealing with a directory
336 if (!is_directory()) return false;
337
338 // If it doesn't exist, we're done.
339 if (!exists()) return true;
340
341 if (remove_contents) {
342 // Recursively descend the directory to remove its content
343 std::string cmd("/bin/rm -rf ");
344 cmd += path;
345 system(cmd.c_str());
346 } else {
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");
355 }
356 return true;
357}
358
359bool
360Path::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");
364 return true;
365}
366
Reid Spencerb89a2232004-08-25 06:20:07 +0000367}
368
369// vim: sw=2