blob: 3e179eaf48a3a7c06f77e2fb1762a70fa340aa02 [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 Spencerd0c9e0e2004-09-18 19:29:16 +000023#include <fstream>
24#include <malloc.h>
Reid Spencercbad7012004-09-11 04:59:30 +000025
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000026static void FlipBackSlashes(std::string& s) {
27 for (size_t i = 0; i < s.size(); i++)
28 if (s[i] == '\\')
29 s[i] = '/';
30}
31
Reid Spencercbad7012004-09-11 04:59:30 +000032namespace llvm {
Reid Spencerb016a372004-09-15 05:49:50 +000033namespace sys {
Reid Spencercbad7012004-09-11 04:59:30 +000034
Reid Spencerb016a372004-09-15 05:49:50 +000035bool
Reid Spencer07adb282004-11-05 22:15:36 +000036Path::isValid() const {
Reid Spencerb016a372004-09-15 05:49:50 +000037 if (path.empty())
38 return false;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000039
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000040 // If there is a colon, it must be the second character, preceded by a letter
41 // and followed by something.
42 size_t len = path.size();
43 size_t pos = path.rfind(':',len);
44 if (pos != std::string::npos) {
45 if (pos != 1 || !isalpha(path[0]) || len < 3)
46 return false;
47 }
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000048
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000049 // Check for illegal characters.
50 if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
51 "\013\014\015\016\017\020\021\022\023\024\025\026"
52 "\027\030\031\032\033\034\035\036\037")
53 != std::string::npos)
54 return false;
55
56 // A file or directory name may not end in a period.
57 if (path[len-1] == '.')
58 return false;
59 if (len >= 2 && path[len-2] == '.' && path[len-1] == '/')
60 return false;
61
62 // A file or directory name may not end in a space.
63 if (path[len-1] == ' ')
64 return false;
65 if (len >= 2 && path[len-2] == ' ' && path[len-1] == '/')
66 return false;
67
68 return true;
Reid Spencercbad7012004-09-11 04:59:30 +000069}
70
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000071static Path *TempDirectory = NULL;
72
Reid Spencerb016a372004-09-15 05:49:50 +000073Path
74Path::GetTemporaryDirectory() {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000075 if (TempDirectory)
76 return *TempDirectory;
77
78 char pathname[MAX_PATH];
79 if (!GetTempPath(MAX_PATH, pathname))
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000080 throw std::string("Can't determine temporary directory");
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000081
Reid Spencerb016a372004-09-15 05:49:50 +000082 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +000083 result.setDirectory(pathname);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000084
85 // Append a subdirectory passed on our process id so multiple LLVMs don't
86 // step on each other's toes.
87 sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
Reid Spencer07adb282004-11-05 22:15:36 +000088 result.appendDirectory(pathname);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000089
90 // If there's a directory left over from a previous LLVM execution that
91 // happened to have the same process id, get rid of it.
Reid Spencer07adb282004-11-05 22:15:36 +000092 result.destroyDirectory(true);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000093
94 // And finally (re-)create the empty directory.
Reid Spencer07adb282004-11-05 22:15:36 +000095 result.createDirectory(false);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000096 TempDirectory = new Path(result);
97 return *TempDirectory;
Reid Spencerb016a372004-09-15 05:49:50 +000098}
99
Reid Spencer732f92d2004-12-13 06:57:15 +0000100Path::Path(const std::string& unverified_path)
Reid Spencerb016a372004-09-15 05:49:50 +0000101 : path(unverified_path)
102{
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000103 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000104 if (unverified_path.empty())
105 return;
Reid Spencer07adb282004-11-05 22:15:36 +0000106 if (this->isValid())
Reid Spencerb016a372004-09-15 05:49:50 +0000107 return;
108 // oops, not valid.
109 path.clear();
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000110 throw std::string(unverified_path + ": path is not valid");
Reid Spencerb016a372004-09-15 05:49:50 +0000111}
112
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000113// FIXME: the following set of functions don't map to Windows very well.
Reid Spencerb016a372004-09-15 05:49:50 +0000114Path
115Path::GetRootDirectory() {
116 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000117 result.setDirectory("/");
Reid Spencerb016a372004-09-15 05:49:50 +0000118 return result;
119}
120
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000121static void getPathList(const char*path, std::vector<sys::Path>& Paths) {
122 const char* at = path;
123 const char* delim = strchr(at, ';');
124 Path tmpPath;
125 while( delim != 0 ) {
126 std::string tmp(at, size_t(delim-at));
127 if (tmpPath.setDirectory(tmp))
128 if (tmpPath.readable())
129 Paths.push_back(tmpPath);
130 at = delim + 1;
131 delim = strchr(at, ';');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000132 }
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000133 if (*at != 0)
134 if (tmpPath.setDirectory(std::string(at)))
135 if (tmpPath.readable())
136 Paths.push_back(tmpPath);
137
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000138}
139
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000140void
141Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
142#ifdef LTDL_SHLIBPATH_VAR
143 char* env_var = getenv(LTDL_SHLIBPATH_VAR);
144 if (env_var != 0) {
145 getPathList(env_var,Paths);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000146 }
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000147#endif
148 // FIXME: Should this look at LD_LIBRARY_PATH too?
149 Paths.push_back(sys::Path("C:\\WINDOWS\\SYSTEM32\\"));
150 Paths.push_back(sys::Path("C:\\WINDOWS\\"));
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000151}
152
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000153void
154Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
155 char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
156 if (env_var != 0) {
157 getPathList(env_var,Paths);
158 }
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000159#ifdef LLVM_LIBDIR
160 {
161 Path tmpPath;
162 if (tmpPath.setDirectory(LLVM_LIBDIR))
163 if (tmpPath.readable())
164 Paths.push_back(tmpPath);
165 }
166#endif
167 GetSystemLibraryPaths(Paths);
Reid Spencerb016a372004-09-15 05:49:50 +0000168}
169
170Path
171Path::GetLLVMDefaultConfigDir() {
172 return Path("/etc/llvm/");
173}
174
175Path
Reid Spencerb016a372004-09-15 05:49:50 +0000176Path::GetUserHomeDirectory() {
177 const char* home = getenv("HOME");
178 if (home) {
179 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000180 if (result.setDirectory(home))
Reid Spencerb016a372004-09-15 05:49:50 +0000181 return result;
182 }
183 return GetRootDirectory();
184}
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000185// FIXME: the above set of functions don't map to Windows very well.
186
187bool
Reid Spencer07adb282004-11-05 22:15:36 +0000188Path::isFile() const {
189 return (isValid() && path[path.length()-1] != '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000190}
191
192bool
Reid Spencer07adb282004-11-05 22:15:36 +0000193Path::isDirectory() const {
194 return (isValid() && path[path.length()-1] == '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000195}
196
197std::string
Reid Spencer07adb282004-11-05 22:15:36 +0000198Path::getBasename() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000199 // Find the last slash
200 size_t slash = path.rfind('/');
201 if (slash == std::string::npos)
202 slash = 0;
203 else
204 slash++;
205
206 return path.substr(slash, path.rfind('.'));
207}
208
Reid Spencer07adb282004-11-05 22:15:36 +0000209bool Path::hasMagicNumber(const std::string &Magic) const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000210 size_t len = Magic.size();
211 char *buf = reinterpret_cast<char *>(_alloca(len+1));
212 std::ifstream f(path.c_str());
213 f.read(buf, len);
214 buf[len] = '\0';
215 return Magic == buf;
216}
217
218bool
Reid Spencer07adb282004-11-05 22:15:36 +0000219Path::isBytecodeFile() const {
Reid Spencer4b826812004-11-09 20:27:23 +0000220 char buffer[ 4];
221 buffer[0] = 0;
222 std::ifstream f(path.c_str());
223 f.read(buffer, 4);
224 if (f.bad())
225 ThrowErrno("can't read file signature");
226 return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000227}
228
229bool
Reid Spencerb016a372004-09-15 05:49:50 +0000230Path::exists() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000231 DWORD attr = GetFileAttributes(path.c_str());
232 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000233}
234
235bool
236Path::readable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000237 // FIXME: take security attributes into account.
238 DWORD attr = GetFileAttributes(path.c_str());
239 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000240}
241
242bool
243Path::writable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000244 // FIXME: take security attributes into account.
245 DWORD attr = GetFileAttributes(path.c_str());
246 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
Reid Spencerb016a372004-09-15 05:49:50 +0000247}
248
249bool
250Path::executable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000251 // FIXME: take security attributes into account.
252 DWORD attr = GetFileAttributes(path.c_str());
253 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000254}
255
256std::string
257Path::getLast() const {
258 // Find the last slash
259 size_t pos = path.rfind('/');
260
261 // Handle the corner cases
262 if (pos == std::string::npos)
263 return path;
264
265 // If the last character is a slash
266 if (pos == path.length()-1) {
267 // Find the second to last slash
268 size_t pos2 = path.rfind('/', pos-1);
269 if (pos2 == std::string::npos)
270 return path.substr(0,pos);
271 else
272 return path.substr(pos2+1,pos-pos2-1);
273 }
274 // Return everything after the last slash
275 return path.substr(pos+1);
276}
277
Jeff Cohen626e38e2004-12-14 05:26:43 +0000278void
279Path::getStatusInfo(StatusInfo& info) const {
280 WIN32_FILE_ATTRIBUTE_DATA fi;
281 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
282 ThrowError(std::string(path) + ": Can't get status: ");
283
284 info.fileSize = fi.nFileSizeHigh;
285 info.fileSize <<= 32;
286 info.fileSize += fi.nFileSizeLow;
287
288 info.mode = 0777; // Not applicable to Windows, so...
289 info.user = 9999; // Not applicable to Windows, so...
290 info.group = 9999; // Not applicable to Windows, so...
291
292 __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
293 info.modTime.fromWin32Time(ft);
294
295 info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
296 if (info.isDir && path[path.length() - 1] != '/')
297 path += '/';
298 else if (!info.isDir && path[path.length() - 1] == '/')
299 path.erase(path.length() - 1);
300}
301
Reid Spencer77cc91d2004-12-13 19:59:50 +0000302void Path::makeReadable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000303 // All files are readable on Windows (ignoring security attributes).
Reid Spencer77cc91d2004-12-13 19:59:50 +0000304}
305
306void Path::makeWriteable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000307 DWORD attr = GetFileAttributes(path.c_str());
308
309 // If it doesn't exist, we're done.
310 if (attr == INVALID_FILE_ATTRIBUTES)
311 return;
312
313 if (attr & FILE_ATTRIBUTE_READONLY) {
314 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
315 ThrowError(std::string(path) + ": Can't make file writable: ");
316 }
Reid Spencer77cc91d2004-12-13 19:59:50 +0000317}
318
319void Path::makeExecutable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000320 // All files are executable on Windows (ignoring security attributes).
Reid Spencer77cc91d2004-12-13 19:59:50 +0000321}
322
Reid Spencerb016a372004-09-15 05:49:50 +0000323bool
Reid Spencer07adb282004-11-05 22:15:36 +0000324Path::setDirectory(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000325 if (a_path.size() == 0)
326 return false;
327 Path save(*this);
328 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000329 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000330 size_t last = a_path.size() -1;
Reid Spencerb0e18872004-12-13 07:51:52 +0000331 if (a_path[last] != '/')
Reid Spencerb016a372004-09-15 05:49:50 +0000332 path += '/';
Reid Spencer07adb282004-11-05 22:15:36 +0000333 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000334 path = save.path;
335 return false;
336 }
337 return true;
338}
339
340bool
Reid Spencer07adb282004-11-05 22:15:36 +0000341Path::setFile(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000342 if (a_path.size() == 0)
343 return false;
344 Path save(*this);
345 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000346 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000347 size_t last = a_path.size() - 1;
348 while (last > 0 && a_path[last] == '/')
349 last--;
350 path.erase(last+1);
Reid Spencer07adb282004-11-05 22:15:36 +0000351 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000352 path = save.path;
353 return false;
354 }
355 return true;
356}
357
358bool
Reid Spencer07adb282004-11-05 22:15:36 +0000359Path::appendDirectory(const std::string& dir) {
360 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000361 return false;
362 Path save(*this);
363 path += dir;
364 path += "/";
Reid Spencer07adb282004-11-05 22:15:36 +0000365 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000366 path = save.path;
367 return false;
368 }
369 return true;
370}
371
372bool
Reid Spencer07adb282004-11-05 22:15:36 +0000373Path::elideDirectory() {
374 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000375 return false;
376 size_t slashpos = path.rfind('/',path.size());
377 if (slashpos == 0 || slashpos == std::string::npos)
378 return false;
379 if (slashpos == path.size() - 1)
380 slashpos = path.rfind('/',slashpos-1);
381 if (slashpos == std::string::npos)
382 return false;
383 path.erase(slashpos);
384 return true;
385}
386
387bool
Reid Spencer07adb282004-11-05 22:15:36 +0000388Path::appendFile(const std::string& file) {
389 if (!isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000390 return false;
391 Path save(*this);
392 path += file;
Reid Spencer07adb282004-11-05 22:15:36 +0000393 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000394 path = save.path;
395 return false;
396 }
397 return true;
398}
399
400bool
Reid Spencer07adb282004-11-05 22:15:36 +0000401Path::elideFile() {
402 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000403 return false;
404 size_t slashpos = path.rfind('/',path.size());
405 if (slashpos == std::string::npos)
406 return false;
407 path.erase(slashpos+1);
408 return true;
409}
410
411bool
Reid Spencer07adb282004-11-05 22:15:36 +0000412Path::appendSuffix(const std::string& suffix) {
413 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000414 return false;
415 Path save(*this);
416 path.append(".");
417 path.append(suffix);
Reid Spencer07adb282004-11-05 22:15:36 +0000418 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000419 path = save.path;
420 return false;
421 }
422 return true;
423}
424
425bool
Reid Spencer07adb282004-11-05 22:15:36 +0000426Path::elideSuffix() {
427 if (isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000428 size_t dotpos = path.rfind('.',path.size());
429 size_t slashpos = path.rfind('/',path.size());
430 if (slashpos != std::string::npos && dotpos != std::string::npos &&
431 dotpos > slashpos) {
432 path.erase(dotpos, path.size()-dotpos);
433 return true;
434 }
435 return false;
436}
437
438
439bool
Reid Spencer07adb282004-11-05 22:15:36 +0000440Path::createDirectory( bool create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000441 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000442 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000443
444 // Get a writeable copy of the path name
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000445 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000446 path.copy(pathname,path.length());
447 pathname[path.length()] = 0;
Reid Spencerb016a372004-09-15 05:49:50 +0000448
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000449 // Determine starting point for initial / search.
450 char *next = pathname;
451 if (pathname[0] == '/' && pathname[1] == '/') {
452 // Skip host name.
453 next = strchr(pathname+2, '/');
454 if (next == NULL)
455 throw std::string(pathname) + ": badly formed remote directory";
456 // Skip share name.
457 next = strchr(next+1, '/');
458 if (next == NULL)
459 throw std::string(pathname) + ": badly formed remote directory";
460 next++;
461 if (*next == 0)
462 throw std::string(pathname) + ": badly formed remote directory";
463 } else {
464 if (pathname[1] == ':')
465 next += 2; // skip drive letter
466 if (*next == '/')
467 next++; // skip root directory
468 }
Reid Spencerb016a372004-09-15 05:49:50 +0000469
470 // If we're supposed to create intermediate directories
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000471 if (create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000472 // Loop through the directory components until we're done
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000473 while (*next) {
474 next = strchr(next, '/');
Reid Spencerb016a372004-09-15 05:49:50 +0000475 *next = 0;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000476 if (!CreateDirectory(pathname, NULL))
477 ThrowError(std::string(pathname) + ": Can't create directory: ");
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000478 *next++ = '/';
Reid Spencerb016a372004-09-15 05:49:50 +0000479 }
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000480 } else {
481 // Drop trailing slash.
482 pathname[path.size()-1] = 0;
483 if (!CreateDirectory(pathname, NULL)) {
484 ThrowError(std::string(pathname) + ": Can't create directory: ");
485 }
Reid Spencerb016a372004-09-15 05:49:50 +0000486 }
487 return true;
488}
489
490bool
Reid Spencer07adb282004-11-05 22:15:36 +0000491Path::createFile() {
Reid Spencerb016a372004-09-15 05:49:50 +0000492 // Make sure we're dealing with a file
Reid Spencer07adb282004-11-05 22:15:36 +0000493 if (!isFile()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000494
495 // Create the file
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000496 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000497 FILE_ATTRIBUTE_NORMAL, NULL);
498 if (h == INVALID_HANDLE_VALUE)
499 ThrowError(std::string(path.c_str()) + ": Can't create file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000500
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000501 CloseHandle(h);
Reid Spencerb016a372004-09-15 05:49:50 +0000502 return true;
503}
504
505bool
Reid Spencer00e89302004-12-15 23:02:10 +0000506Path::destroyDirectory(bool remove_contents) const {
Reid Spencerb016a372004-09-15 05:49:50 +0000507 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000508 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000509
510 // If it doesn't exist, we're done.
511 if (!exists()) return true;
512
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000513 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
514 path.copy(pathname,path.length()+1);
515 int lastchar = path.length() - 1 ;
516 if (pathname[lastchar] == '/')
517 pathname[lastchar] = 0;
518
Reid Spencerb016a372004-09-15 05:49:50 +0000519 if (remove_contents) {
520 // Recursively descend the directory to remove its content
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000521 // FIXME: The correct way of doing this on Windows isn't pretty...
522 // but this may work if unix-like utils are present.
523 std::string cmd("rm -rf ");
Reid Spencerb016a372004-09-15 05:49:50 +0000524 cmd += path;
525 system(cmd.c_str());
526 } else {
527 // Otherwise, try to just remove the one directory
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000528 if (!RemoveDirectory(pathname))
529 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000530 }
531 return true;
532}
533
534bool
Reid Spencer00e89302004-12-15 23:02:10 +0000535Path::destroyFile() const {
Reid Spencer07adb282004-11-05 22:15:36 +0000536 if (!isFile()) return false;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000537
538 DWORD attr = GetFileAttributes(path.c_str());
539
540 // If it doesn't exist, we're done.
541 if (attr == INVALID_FILE_ATTRIBUTES)
542 return true;
543
544 // Read-only files cannot be deleted on Windows. Must remove the read-only
545 // attribute first.
546 if (attr & FILE_ATTRIBUTE_READONLY) {
547 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
548 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
549 }
550
551 if (!DeleteFile(path.c_str()))
552 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000553 return true;
554}
555
Reid Spencer3b0cc782004-12-14 18:42:13 +0000556bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
557 if (!isFile())
558 return false;
559 assert(len < 1024 && "Request for magic string too long");
560 char* buf = (char*) alloca(1 + len);
561 std::ofstream ofs(path.c_str(),std::ofstream::in);
562 if (!ofs.is_open())
563 return false;
564 std::ifstream ifs(path.c_str());
565 if (!ifs.is_open())
566 return false;
567 ifs.read(buf, len);
568 ofs.close();
569 ifs.close();
570 buf[len] = '\0';
571 Magic = buf;
572 return true;
573}
574
Reid Spencerc29befb2004-12-15 01:50:13 +0000575void
576CopyFile(const sys::Path &Dest, const sys::Path &Src) {
577 if (!::CopyFile(Src.c_str(), Dest.c_str(), false))
578 ThrowError("Can't copy '" + Src.toString() +
579 "' to '" + Dest.toString() + "'");
580}
581
582void
Reid Spencer07f9f4e2004-12-15 08:32:45 +0000583Path::makeUnique( bool reuse_current ) {
584 if (reuse_current && !exists())
Reid Spencerc29befb2004-12-15 01:50:13 +0000585 return; // File doesn't exist already, just use it!
586
587 Path dir (*this);
588 dir.elideFile();
589 std::string fname = this->getLast();
590
Jeff Cohenab68df02004-12-15 04:08:15 +0000591 char newName[MAX_PATH + 1];
Reid Spencerc29befb2004-12-15 01:50:13 +0000592 if (!GetTempFileName(dir.c_str(), fname.c_str(), 0, newName))
593 ThrowError("Cannot make unique filename for '" + path + "'");
594
595 path = newName;
596}
597
Reid Spencer07f9f4e2004-12-15 08:32:45 +0000598bool
599Path::createTemporaryFile(bool reuse_current) {
600 // Make sure we're dealing with a file
601 if (!isFile())
602 return false;
603
604 // Make this into a unique file name
605 makeUnique( reuse_current );
606}
607
Reid Spencerb016a372004-09-15 05:49:50 +0000608}
Reid Spencercbad7012004-09-11 04:59:30 +0000609}
610
611// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
Reid Spencerb016a372004-09-15 05:49:50 +0000612