blob: 08a3d402e8806eef0ed880d17d889fa054ee1df1 [file] [log] [blame]
Reid Spencerb016a372004-09-15 05:49:50 +00001//===- llvm/System/Linux/Path.cpp - Linux Path Implementation ---*- C++ -*-===//
2//
Reid Spencercbad7012004-09-11 04:59:30 +00003// The LLVM Compiler Infrastructure
4//
Reid Spencerb016a372004-09-15 05:49:50 +00005// This file was developed by Reid Spencer and is distributed under the
Reid Spencercbad7012004-09-11 04:59:30 +00006// University of Illinois Open Source License. See LICENSE.TXT for details.
Reid Spencerb016a372004-09-15 05:49:50 +00007//
8// Modified by Henrik Bach to comply with at least MinGW.
Reid Spencerd0c9e0e2004-09-18 19:29:16 +00009// Ported to Win32 by Jeff Cohen.
Reid Spencerb016a372004-09-15 05:49:50 +000010//
Reid Spencercbad7012004-09-11 04:59:30 +000011//===----------------------------------------------------------------------===//
12//
13// This file provides the Win32 specific implementation of the Path class.
14//
15//===----------------------------------------------------------------------===//
16
17//===----------------------------------------------------------------------===//
Reid Spencerb016a372004-09-15 05:49:50 +000018//=== WARNING: Implementation here must contain only generic Win32 code that
19//=== is guaranteed to work on *all* Win32 variants.
Reid Spencercbad7012004-09-11 04:59:30 +000020//===----------------------------------------------------------------------===//
21
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000022#include "Win32.h"
Reid Spencerb016a372004-09-15 05:49:50 +000023#include <llvm/System/Path.h>
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000024#include <fstream>
25#include <malloc.h>
Reid Spencercbad7012004-09-11 04:59:30 +000026
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000027static void FlipBackSlashes(std::string& s) {
28 for (size_t i = 0; i < s.size(); i++)
29 if (s[i] == '\\')
30 s[i] = '/';
31}
32
Reid Spencercbad7012004-09-11 04:59:30 +000033namespace llvm {
Reid Spencerb016a372004-09-15 05:49:50 +000034namespace sys {
Reid Spencercbad7012004-09-11 04:59:30 +000035
Reid Spencerb016a372004-09-15 05:49:50 +000036bool
Reid Spencer07adb282004-11-05 22:15:36 +000037Path::isValid() const {
Reid Spencerb016a372004-09-15 05:49:50 +000038 if (path.empty())
39 return false;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000040
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000041 // If there is a colon, it must be the second character, preceded by a letter
42 // and followed by something.
43 size_t len = path.size();
44 size_t pos = path.rfind(':',len);
45 if (pos != std::string::npos) {
46 if (pos != 1 || !isalpha(path[0]) || len < 3)
47 return false;
48 }
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000049
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000050 // Check for illegal characters.
51 if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
52 "\013\014\015\016\017\020\021\022\023\024\025\026"
53 "\027\030\031\032\033\034\035\036\037")
54 != std::string::npos)
55 return false;
56
57 // A file or directory name may not end in a period.
58 if (path[len-1] == '.')
59 return false;
60 if (len >= 2 && path[len-2] == '.' && path[len-1] == '/')
61 return false;
62
63 // A file or directory name may not end in a space.
64 if (path[len-1] == ' ')
65 return false;
66 if (len >= 2 && path[len-2] == ' ' && path[len-1] == '/')
67 return false;
68
69 return true;
Reid Spencercbad7012004-09-11 04:59:30 +000070}
71
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000072static Path *TempDirectory = NULL;
73
Reid Spencerb016a372004-09-15 05:49:50 +000074Path
75Path::GetTemporaryDirectory() {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000076 if (TempDirectory)
77 return *TempDirectory;
78
79 char pathname[MAX_PATH];
80 if (!GetTempPath(MAX_PATH, pathname))
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000081 throw std::string("Can't determine temporary directory");
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000082
Reid Spencerb016a372004-09-15 05:49:50 +000083 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +000084 result.setDirectory(pathname);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000085
86 // Append a subdirectory passed on our process id so multiple LLVMs don't
87 // step on each other's toes.
88 sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
Reid Spencer07adb282004-11-05 22:15:36 +000089 result.appendDirectory(pathname);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000090
91 // If there's a directory left over from a previous LLVM execution that
92 // happened to have the same process id, get rid of it.
Reid Spencer07adb282004-11-05 22:15:36 +000093 result.destroyDirectory(true);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000094
95 // And finally (re-)create the empty directory.
Reid Spencer07adb282004-11-05 22:15:36 +000096 result.createDirectory(false);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000097 TempDirectory = new Path(result);
98 return *TempDirectory;
Reid Spencerb016a372004-09-15 05:49:50 +000099}
100
101Path::Path(std::string unverified_path)
102 : path(unverified_path)
103{
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000104 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000105 if (unverified_path.empty())
106 return;
Reid Spencer07adb282004-11-05 22:15:36 +0000107 if (this->isValid())
Reid Spencerb016a372004-09-15 05:49:50 +0000108 return;
109 // oops, not valid.
110 path.clear();
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000111 throw std::string(unverified_path + ": path is not valid");
Reid Spencerb016a372004-09-15 05:49:50 +0000112}
113
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000114// FIXME: the following set of functions don't map to Windows very well.
Reid Spencerb016a372004-09-15 05:49:50 +0000115Path
116Path::GetRootDirectory() {
117 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000118 result.setDirectory("/");
Reid Spencerb016a372004-09-15 05:49:50 +0000119 return result;
120}
121
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000122std::string
123Path::GetDLLSuffix() {
124 return "dll";
125}
126
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000127static inline bool IsLibrary(Path& path, const std::string& basename) {
Reid Spencer07adb282004-11-05 22:15:36 +0000128 if (path.appendFile(std::string("lib") + basename)) {
129 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000130 return true;
Reid Spencer07adb282004-11-05 22:15:36 +0000131 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000132 return true;
Reid Spencer07adb282004-11-05 22:15:36 +0000133 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000134 return true;
Reid Spencer07adb282004-11-05 22:15:36 +0000135 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000136 return true;
Reid Spencer07adb282004-11-05 22:15:36 +0000137 } else if (path.elideFile() && path.appendFile(basename)) {
138 if (path.appendSuffix(Path::GetDLLSuffix()) && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000139 return true;
Reid Spencer07adb282004-11-05 22:15:36 +0000140 else if (path.elideSuffix() && path.appendSuffix("a") && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000141 return true;
Reid Spencer07adb282004-11-05 22:15:36 +0000142 else if (path.elideSuffix() && path.appendSuffix("o") && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000143 return true;
Reid Spencer07adb282004-11-05 22:15:36 +0000144 else if (path.elideSuffix() && path.appendSuffix("bc") && path.readable())
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000145 return true;
146 }
147 path.clear();
148 return false;
149}
150
151Path
152Path::GetLibraryPath(const std::string& basename,
153 const std::vector<std::string>& LibPaths) {
154 Path result;
155
156 // Try the paths provided
157 for (std::vector<std::string>::const_iterator I = LibPaths.begin(),
158 E = LibPaths.end(); I != E; ++I ) {
Reid Spencer07adb282004-11-05 22:15:36 +0000159 if (result.setDirectory(*I) && IsLibrary(result,basename))
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000160 return result;
161 }
162
163 // Try the LLVM lib directory in the LLVM install area
Reid Spencer07adb282004-11-05 22:15:36 +0000164 //if (result.setDirectory(LLVM_LIBDIR) && IsLibrary(result,basename))
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000165 // return result;
166
167 // Try /usr/lib
Reid Spencer07adb282004-11-05 22:15:36 +0000168 if (result.setDirectory("/usr/lib/") && IsLibrary(result,basename))
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000169 return result;
170
171 // Try /lib
Reid Spencer07adb282004-11-05 22:15:36 +0000172 if (result.setDirectory("/lib/") && IsLibrary(result,basename))
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000173 return result;
174
175 // Can't find it, give up and return invalid path.
176 result.clear();
177 return result;
178}
179
Reid Spencerb016a372004-09-15 05:49:50 +0000180Path
181Path::GetSystemLibraryPath1() {
182 return Path("/lib/");
183}
184
185Path
186Path::GetSystemLibraryPath2() {
187 return Path("/usr/lib/");
188}
189
190Path
191Path::GetLLVMDefaultConfigDir() {
192 return Path("/etc/llvm/");
193}
194
195Path
196Path::GetLLVMConfigDir() {
Reid Spencerb016a372004-09-15 05:49:50 +0000197 return GetLLVMDefaultConfigDir();
198}
199
200Path
201Path::GetUserHomeDirectory() {
202 const char* home = getenv("HOME");
203 if (home) {
204 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000205 if (result.setDirectory(home))
Reid Spencerb016a372004-09-15 05:49:50 +0000206 return result;
207 }
208 return GetRootDirectory();
209}
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000210// FIXME: the above set of functions don't map to Windows very well.
211
212bool
Reid Spencer07adb282004-11-05 22:15:36 +0000213Path::isFile() const {
214 return (isValid() && path[path.length()-1] != '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000215}
216
217bool
Reid Spencer07adb282004-11-05 22:15:36 +0000218Path::isDirectory() const {
219 return (isValid() && path[path.length()-1] == '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000220}
221
222std::string
Reid Spencer07adb282004-11-05 22:15:36 +0000223Path::getBasename() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000224 // Find the last slash
225 size_t slash = path.rfind('/');
226 if (slash == std::string::npos)
227 slash = 0;
228 else
229 slash++;
230
231 return path.substr(slash, path.rfind('.'));
232}
233
Reid Spencer07adb282004-11-05 22:15:36 +0000234bool Path::hasMagicNumber(const std::string &Magic) const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000235 size_t len = Magic.size();
236 char *buf = reinterpret_cast<char *>(_alloca(len+1));
237 std::ifstream f(path.c_str());
238 f.read(buf, len);
239 buf[len] = '\0';
240 return Magic == buf;
241}
242
243bool
Reid Spencer07adb282004-11-05 22:15:36 +0000244Path::isBytecodeFile() const {
Reid Spencer4b826812004-11-09 20:27:23 +0000245 char buffer[ 4];
246 buffer[0] = 0;
247 std::ifstream f(path.c_str());
248 f.read(buffer, 4);
249 if (f.bad())
250 ThrowErrno("can't read file signature");
251 return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000252}
253
254bool
Reid Spencer07adb282004-11-05 22:15:36 +0000255Path::isArchive() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000256 if (readable()) {
Reid Spencer07adb282004-11-05 22:15:36 +0000257 return hasMagicNumber("!<arch>\012");
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000258 }
259 return false;
260}
Reid Spencerb016a372004-09-15 05:49:50 +0000261
262bool
263Path::exists() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000264 DWORD attr = GetFileAttributes(path.c_str());
265 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000266}
267
268bool
269Path::readable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000270 // FIXME: take security attributes into account.
271 DWORD attr = GetFileAttributes(path.c_str());
272 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000273}
274
275bool
276Path::writable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000277 // FIXME: take security attributes into account.
278 DWORD attr = GetFileAttributes(path.c_str());
279 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
Reid Spencerb016a372004-09-15 05:49:50 +0000280}
281
282bool
283Path::executable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000284 // FIXME: take security attributes into account.
285 DWORD attr = GetFileAttributes(path.c_str());
286 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000287}
288
289std::string
290Path::getLast() const {
291 // Find the last slash
292 size_t pos = path.rfind('/');
293
294 // Handle the corner cases
295 if (pos == std::string::npos)
296 return path;
297
298 // If the last character is a slash
299 if (pos == path.length()-1) {
300 // Find the second to last slash
301 size_t pos2 = path.rfind('/', pos-1);
302 if (pos2 == std::string::npos)
303 return path.substr(0,pos);
304 else
305 return path.substr(pos2+1,pos-pos2-1);
306 }
307 // Return everything after the last slash
308 return path.substr(pos+1);
309}
310
311bool
Reid Spencer07adb282004-11-05 22:15:36 +0000312Path::setDirectory(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000313 if (a_path.size() == 0)
314 return false;
315 Path save(*this);
316 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000317 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000318 size_t last = a_path.size() -1;
319 if (last != 0 && a_path[last] != '/')
320 path += '/';
Reid Spencer07adb282004-11-05 22:15:36 +0000321 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000322 path = save.path;
323 return false;
324 }
325 return true;
326}
327
328bool
Reid Spencer07adb282004-11-05 22:15:36 +0000329Path::setFile(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000330 if (a_path.size() == 0)
331 return false;
332 Path save(*this);
333 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000334 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000335 size_t last = a_path.size() - 1;
336 while (last > 0 && a_path[last] == '/')
337 last--;
338 path.erase(last+1);
Reid Spencer07adb282004-11-05 22:15:36 +0000339 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000340 path = save.path;
341 return false;
342 }
343 return true;
344}
345
346bool
Reid Spencer07adb282004-11-05 22:15:36 +0000347Path::appendDirectory(const std::string& dir) {
348 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000349 return false;
350 Path save(*this);
351 path += dir;
352 path += "/";
Reid Spencer07adb282004-11-05 22:15:36 +0000353 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000354 path = save.path;
355 return false;
356 }
357 return true;
358}
359
360bool
Reid Spencer07adb282004-11-05 22:15:36 +0000361Path::elideDirectory() {
362 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000363 return false;
364 size_t slashpos = path.rfind('/',path.size());
365 if (slashpos == 0 || slashpos == std::string::npos)
366 return false;
367 if (slashpos == path.size() - 1)
368 slashpos = path.rfind('/',slashpos-1);
369 if (slashpos == std::string::npos)
370 return false;
371 path.erase(slashpos);
372 return true;
373}
374
375bool
Reid Spencer07adb282004-11-05 22:15:36 +0000376Path::appendFile(const std::string& file) {
377 if (!isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000378 return false;
379 Path save(*this);
380 path += file;
Reid Spencer07adb282004-11-05 22:15:36 +0000381 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000382 path = save.path;
383 return false;
384 }
385 return true;
386}
387
388bool
Reid Spencer07adb282004-11-05 22:15:36 +0000389Path::elideFile() {
390 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000391 return false;
392 size_t slashpos = path.rfind('/',path.size());
393 if (slashpos == std::string::npos)
394 return false;
395 path.erase(slashpos+1);
396 return true;
397}
398
399bool
Reid Spencer07adb282004-11-05 22:15:36 +0000400Path::appendSuffix(const std::string& suffix) {
401 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000402 return false;
403 Path save(*this);
404 path.append(".");
405 path.append(suffix);
Reid Spencer07adb282004-11-05 22:15:36 +0000406 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000407 path = save.path;
408 return false;
409 }
410 return true;
411}
412
413bool
Reid Spencer07adb282004-11-05 22:15:36 +0000414Path::elideSuffix() {
415 if (isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000416 size_t dotpos = path.rfind('.',path.size());
417 size_t slashpos = path.rfind('/',path.size());
418 if (slashpos != std::string::npos && dotpos != std::string::npos &&
419 dotpos > slashpos) {
420 path.erase(dotpos, path.size()-dotpos);
421 return true;
422 }
423 return false;
424}
425
426
427bool
Reid Spencer07adb282004-11-05 22:15:36 +0000428Path::createDirectory( bool create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000429 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000430 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000431
432 // Get a writeable copy of the path name
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000433 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000434 path.copy(pathname,path.length());
435 pathname[path.length()] = 0;
Reid Spencerb016a372004-09-15 05:49:50 +0000436
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000437 // Determine starting point for initial / search.
438 char *next = pathname;
439 if (pathname[0] == '/' && pathname[1] == '/') {
440 // Skip host name.
441 next = strchr(pathname+2, '/');
442 if (next == NULL)
443 throw std::string(pathname) + ": badly formed remote directory";
444 // Skip share name.
445 next = strchr(next+1, '/');
446 if (next == NULL)
447 throw std::string(pathname) + ": badly formed remote directory";
448 next++;
449 if (*next == 0)
450 throw std::string(pathname) + ": badly formed remote directory";
451 } else {
452 if (pathname[1] == ':')
453 next += 2; // skip drive letter
454 if (*next == '/')
455 next++; // skip root directory
456 }
Reid Spencerb016a372004-09-15 05:49:50 +0000457
458 // If we're supposed to create intermediate directories
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000459 if (create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000460 // Loop through the directory components until we're done
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000461 while (*next) {
462 next = strchr(next, '/');
Reid Spencerb016a372004-09-15 05:49:50 +0000463 *next = 0;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000464 if (!CreateDirectory(pathname, NULL))
465 ThrowError(std::string(pathname) + ": Can't create directory: ");
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000466 *next++ = '/';
Reid Spencerb016a372004-09-15 05:49:50 +0000467 }
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000468 } else {
469 // Drop trailing slash.
470 pathname[path.size()-1] = 0;
471 if (!CreateDirectory(pathname, NULL)) {
472 ThrowError(std::string(pathname) + ": Can't create directory: ");
473 }
Reid Spencerb016a372004-09-15 05:49:50 +0000474 }
475 return true;
476}
477
478bool
Reid Spencer07adb282004-11-05 22:15:36 +0000479Path::createFile() {
Reid Spencerb016a372004-09-15 05:49:50 +0000480 // Make sure we're dealing with a file
Reid Spencer07adb282004-11-05 22:15:36 +0000481 if (!isFile()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000482
483 // Create the file
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000484 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000485 FILE_ATTRIBUTE_NORMAL, NULL);
486 if (h == INVALID_HANDLE_VALUE)
487 ThrowError(std::string(path.c_str()) + ": Can't create file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000488
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000489 CloseHandle(h);
Reid Spencerb016a372004-09-15 05:49:50 +0000490 return true;
491}
492
493bool
Reid Spencer07adb282004-11-05 22:15:36 +0000494Path::destroyDirectory(bool remove_contents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000495 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000496 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000497
498 // If it doesn't exist, we're done.
499 if (!exists()) return true;
500
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000501 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
502 path.copy(pathname,path.length()+1);
503 int lastchar = path.length() - 1 ;
504 if (pathname[lastchar] == '/')
505 pathname[lastchar] = 0;
506
Reid Spencerb016a372004-09-15 05:49:50 +0000507 if (remove_contents) {
508 // Recursively descend the directory to remove its content
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000509 // FIXME: The correct way of doing this on Windows isn't pretty...
510 // but this may work if unix-like utils are present.
511 std::string cmd("rm -rf ");
Reid Spencerb016a372004-09-15 05:49:50 +0000512 cmd += path;
513 system(cmd.c_str());
514 } else {
515 // Otherwise, try to just remove the one directory
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000516 if (!RemoveDirectory(pathname))
517 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000518 }
519 return true;
520}
521
522bool
Reid Spencer07adb282004-11-05 22:15:36 +0000523Path::destroyFile() {
524 if (!isFile()) return false;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000525
526 DWORD attr = GetFileAttributes(path.c_str());
527
528 // If it doesn't exist, we're done.
529 if (attr == INVALID_FILE_ATTRIBUTES)
530 return true;
531
532 // Read-only files cannot be deleted on Windows. Must remove the read-only
533 // attribute first.
534 if (attr & FILE_ATTRIBUTE_READONLY) {
535 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
536 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
537 }
538
539 if (!DeleteFile(path.c_str()))
540 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000541 return true;
542}
543
544}
Reid Spencercbad7012004-09-11 04:59:30 +0000545}
546
547// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
Reid Spencerb016a372004-09-15 05:49:50 +0000548