blob: 24cfc465181e82458d0f18d87c839c6e0cc146a0 [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 }
159#ifdef LLVMGCCDIR
160 {
Reid Spencerc29befb2004-12-15 01:50:13 +0000161 Path tmpPath(std::string(LLVMGCCDIR) + "lib/");
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000162 if (tmpPath.readable())
163 Paths.push_back(tmpPath);
164 }
165#endif
166#ifdef LLVM_LIBDIR
167 {
168 Path tmpPath;
169 if (tmpPath.setDirectory(LLVM_LIBDIR))
170 if (tmpPath.readable())
171 Paths.push_back(tmpPath);
172 }
173#endif
174 GetSystemLibraryPaths(Paths);
Reid Spencerb016a372004-09-15 05:49:50 +0000175}
176
177Path
178Path::GetLLVMDefaultConfigDir() {
179 return Path("/etc/llvm/");
180}
181
182Path
Reid Spencerb016a372004-09-15 05:49:50 +0000183Path::GetUserHomeDirectory() {
184 const char* home = getenv("HOME");
185 if (home) {
186 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000187 if (result.setDirectory(home))
Reid Spencerb016a372004-09-15 05:49:50 +0000188 return result;
189 }
190 return GetRootDirectory();
191}
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000192// FIXME: the above set of functions don't map to Windows very well.
193
194bool
Reid Spencer07adb282004-11-05 22:15:36 +0000195Path::isFile() const {
196 return (isValid() && path[path.length()-1] != '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000197}
198
199bool
Reid Spencer07adb282004-11-05 22:15:36 +0000200Path::isDirectory() const {
201 return (isValid() && path[path.length()-1] == '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000202}
203
204std::string
Reid Spencer07adb282004-11-05 22:15:36 +0000205Path::getBasename() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000206 // Find the last slash
207 size_t slash = path.rfind('/');
208 if (slash == std::string::npos)
209 slash = 0;
210 else
211 slash++;
212
213 return path.substr(slash, path.rfind('.'));
214}
215
Reid Spencer07adb282004-11-05 22:15:36 +0000216bool Path::hasMagicNumber(const std::string &Magic) const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000217 size_t len = Magic.size();
218 char *buf = reinterpret_cast<char *>(_alloca(len+1));
219 std::ifstream f(path.c_str());
220 f.read(buf, len);
221 buf[len] = '\0';
222 return Magic == buf;
223}
224
225bool
Reid Spencer07adb282004-11-05 22:15:36 +0000226Path::isBytecodeFile() const {
Reid Spencer4b826812004-11-09 20:27:23 +0000227 char buffer[ 4];
228 buffer[0] = 0;
229 std::ifstream f(path.c_str());
230 f.read(buffer, 4);
231 if (f.bad())
232 ThrowErrno("can't read file signature");
233 return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000234}
235
236bool
Reid Spencerb016a372004-09-15 05:49:50 +0000237Path::exists() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000238 DWORD attr = GetFileAttributes(path.c_str());
239 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000240}
241
242bool
243Path::readable() 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;
Reid Spencerb016a372004-09-15 05:49:50 +0000247}
248
249bool
250Path::writable() 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) && !(attr & FILE_ATTRIBUTE_READONLY);
Reid Spencerb016a372004-09-15 05:49:50 +0000254}
255
256bool
257Path::executable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000258 // FIXME: take security attributes into account.
259 DWORD attr = GetFileAttributes(path.c_str());
260 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000261}
262
263std::string
264Path::getLast() const {
265 // Find the last slash
266 size_t pos = path.rfind('/');
267
268 // Handle the corner cases
269 if (pos == std::string::npos)
270 return path;
271
272 // If the last character is a slash
273 if (pos == path.length()-1) {
274 // Find the second to last slash
275 size_t pos2 = path.rfind('/', pos-1);
276 if (pos2 == std::string::npos)
277 return path.substr(0,pos);
278 else
279 return path.substr(pos2+1,pos-pos2-1);
280 }
281 // Return everything after the last slash
282 return path.substr(pos+1);
283}
284
Jeff Cohen626e38e2004-12-14 05:26:43 +0000285void
286Path::getStatusInfo(StatusInfo& info) const {
287 WIN32_FILE_ATTRIBUTE_DATA fi;
288 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
289 ThrowError(std::string(path) + ": Can't get status: ");
290
291 info.fileSize = fi.nFileSizeHigh;
292 info.fileSize <<= 32;
293 info.fileSize += fi.nFileSizeLow;
294
295 info.mode = 0777; // Not applicable to Windows, so...
296 info.user = 9999; // Not applicable to Windows, so...
297 info.group = 9999; // Not applicable to Windows, so...
298
299 __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
300 info.modTime.fromWin32Time(ft);
301
302 info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
303 if (info.isDir && path[path.length() - 1] != '/')
304 path += '/';
305 else if (!info.isDir && path[path.length() - 1] == '/')
306 path.erase(path.length() - 1);
307}
308
Reid Spencer77cc91d2004-12-13 19:59:50 +0000309void Path::makeReadable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000310 // All files are readable on Windows (ignoring security attributes).
Reid Spencer77cc91d2004-12-13 19:59:50 +0000311}
312
313void Path::makeWriteable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000314 DWORD attr = GetFileAttributes(path.c_str());
315
316 // If it doesn't exist, we're done.
317 if (attr == INVALID_FILE_ATTRIBUTES)
318 return;
319
320 if (attr & FILE_ATTRIBUTE_READONLY) {
321 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
322 ThrowError(std::string(path) + ": Can't make file writable: ");
323 }
Reid Spencer77cc91d2004-12-13 19:59:50 +0000324}
325
326void Path::makeExecutable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000327 // All files are executable on Windows (ignoring security attributes).
Reid Spencer77cc91d2004-12-13 19:59:50 +0000328}
329
Reid Spencerb016a372004-09-15 05:49:50 +0000330bool
Reid Spencer07adb282004-11-05 22:15:36 +0000331Path::setDirectory(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000332 if (a_path.size() == 0)
333 return false;
334 Path save(*this);
335 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000336 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000337 size_t last = a_path.size() -1;
Reid Spencerb0e18872004-12-13 07:51:52 +0000338 if (a_path[last] != '/')
Reid Spencerb016a372004-09-15 05:49:50 +0000339 path += '/';
Reid Spencer07adb282004-11-05 22:15:36 +0000340 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000341 path = save.path;
342 return false;
343 }
344 return true;
345}
346
347bool
Reid Spencer07adb282004-11-05 22:15:36 +0000348Path::setFile(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000349 if (a_path.size() == 0)
350 return false;
351 Path save(*this);
352 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000353 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000354 size_t last = a_path.size() - 1;
355 while (last > 0 && a_path[last] == '/')
356 last--;
357 path.erase(last+1);
Reid Spencer07adb282004-11-05 22:15:36 +0000358 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000359 path = save.path;
360 return false;
361 }
362 return true;
363}
364
365bool
Reid Spencer07adb282004-11-05 22:15:36 +0000366Path::appendDirectory(const std::string& dir) {
367 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000368 return false;
369 Path save(*this);
370 path += dir;
371 path += "/";
Reid Spencer07adb282004-11-05 22:15:36 +0000372 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000373 path = save.path;
374 return false;
375 }
376 return true;
377}
378
379bool
Reid Spencer07adb282004-11-05 22:15:36 +0000380Path::elideDirectory() {
381 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000382 return false;
383 size_t slashpos = path.rfind('/',path.size());
384 if (slashpos == 0 || slashpos == std::string::npos)
385 return false;
386 if (slashpos == path.size() - 1)
387 slashpos = path.rfind('/',slashpos-1);
388 if (slashpos == std::string::npos)
389 return false;
390 path.erase(slashpos);
391 return true;
392}
393
394bool
Reid Spencer07adb282004-11-05 22:15:36 +0000395Path::appendFile(const std::string& file) {
396 if (!isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000397 return false;
398 Path save(*this);
399 path += file;
Reid Spencer07adb282004-11-05 22:15:36 +0000400 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000401 path = save.path;
402 return false;
403 }
404 return true;
405}
406
407bool
Reid Spencer07adb282004-11-05 22:15:36 +0000408Path::elideFile() {
409 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000410 return false;
411 size_t slashpos = path.rfind('/',path.size());
412 if (slashpos == std::string::npos)
413 return false;
414 path.erase(slashpos+1);
415 return true;
416}
417
418bool
Reid Spencer07adb282004-11-05 22:15:36 +0000419Path::appendSuffix(const std::string& suffix) {
420 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000421 return false;
422 Path save(*this);
423 path.append(".");
424 path.append(suffix);
Reid Spencer07adb282004-11-05 22:15:36 +0000425 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000426 path = save.path;
427 return false;
428 }
429 return true;
430}
431
432bool
Reid Spencer07adb282004-11-05 22:15:36 +0000433Path::elideSuffix() {
434 if (isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000435 size_t dotpos = path.rfind('.',path.size());
436 size_t slashpos = path.rfind('/',path.size());
437 if (slashpos != std::string::npos && dotpos != std::string::npos &&
438 dotpos > slashpos) {
439 path.erase(dotpos, path.size()-dotpos);
440 return true;
441 }
442 return false;
443}
444
445
446bool
Reid Spencer07adb282004-11-05 22:15:36 +0000447Path::createDirectory( bool create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000448 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000449 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000450
451 // Get a writeable copy of the path name
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000452 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000453 path.copy(pathname,path.length());
454 pathname[path.length()] = 0;
Reid Spencerb016a372004-09-15 05:49:50 +0000455
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000456 // Determine starting point for initial / search.
457 char *next = pathname;
458 if (pathname[0] == '/' && pathname[1] == '/') {
459 // Skip host name.
460 next = strchr(pathname+2, '/');
461 if (next == NULL)
462 throw std::string(pathname) + ": badly formed remote directory";
463 // Skip share name.
464 next = strchr(next+1, '/');
465 if (next == NULL)
466 throw std::string(pathname) + ": badly formed remote directory";
467 next++;
468 if (*next == 0)
469 throw std::string(pathname) + ": badly formed remote directory";
470 } else {
471 if (pathname[1] == ':')
472 next += 2; // skip drive letter
473 if (*next == '/')
474 next++; // skip root directory
475 }
Reid Spencerb016a372004-09-15 05:49:50 +0000476
477 // If we're supposed to create intermediate directories
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000478 if (create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000479 // Loop through the directory components until we're done
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000480 while (*next) {
481 next = strchr(next, '/');
Reid Spencerb016a372004-09-15 05:49:50 +0000482 *next = 0;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000483 if (!CreateDirectory(pathname, NULL))
484 ThrowError(std::string(pathname) + ": Can't create directory: ");
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000485 *next++ = '/';
Reid Spencerb016a372004-09-15 05:49:50 +0000486 }
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000487 } else {
488 // Drop trailing slash.
489 pathname[path.size()-1] = 0;
490 if (!CreateDirectory(pathname, NULL)) {
491 ThrowError(std::string(pathname) + ": Can't create directory: ");
492 }
Reid Spencerb016a372004-09-15 05:49:50 +0000493 }
494 return true;
495}
496
497bool
Reid Spencer07adb282004-11-05 22:15:36 +0000498Path::createFile() {
Reid Spencerb016a372004-09-15 05:49:50 +0000499 // Make sure we're dealing with a file
Reid Spencer07adb282004-11-05 22:15:36 +0000500 if (!isFile()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000501
502 // Create the file
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000503 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000504 FILE_ATTRIBUTE_NORMAL, NULL);
505 if (h == INVALID_HANDLE_VALUE)
506 ThrowError(std::string(path.c_str()) + ": Can't create file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000507
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000508 CloseHandle(h);
Reid Spencerb016a372004-09-15 05:49:50 +0000509 return true;
510}
511
512bool
Reid Spencer07adb282004-11-05 22:15:36 +0000513Path::destroyDirectory(bool remove_contents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000514 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000515 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000516
517 // If it doesn't exist, we're done.
518 if (!exists()) return true;
519
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000520 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
521 path.copy(pathname,path.length()+1);
522 int lastchar = path.length() - 1 ;
523 if (pathname[lastchar] == '/')
524 pathname[lastchar] = 0;
525
Reid Spencerb016a372004-09-15 05:49:50 +0000526 if (remove_contents) {
527 // Recursively descend the directory to remove its content
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000528 // FIXME: The correct way of doing this on Windows isn't pretty...
529 // but this may work if unix-like utils are present.
530 std::string cmd("rm -rf ");
Reid Spencerb016a372004-09-15 05:49:50 +0000531 cmd += path;
532 system(cmd.c_str());
533 } else {
534 // Otherwise, try to just remove the one directory
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000535 if (!RemoveDirectory(pathname))
536 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000537 }
538 return true;
539}
540
541bool
Reid Spencer07adb282004-11-05 22:15:36 +0000542Path::destroyFile() {
543 if (!isFile()) return false;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000544
545 DWORD attr = GetFileAttributes(path.c_str());
546
547 // If it doesn't exist, we're done.
548 if (attr == INVALID_FILE_ATTRIBUTES)
549 return true;
550
551 // Read-only files cannot be deleted on Windows. Must remove the read-only
552 // attribute first.
553 if (attr & FILE_ATTRIBUTE_READONLY) {
554 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
555 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
556 }
557
558 if (!DeleteFile(path.c_str()))
559 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000560 return true;
561}
562
Reid Spencer3b0cc782004-12-14 18:42:13 +0000563bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
564 if (!isFile())
565 return false;
566 assert(len < 1024 && "Request for magic string too long");
567 char* buf = (char*) alloca(1 + len);
568 std::ofstream ofs(path.c_str(),std::ofstream::in);
569 if (!ofs.is_open())
570 return false;
571 std::ifstream ifs(path.c_str());
572 if (!ifs.is_open())
573 return false;
574 ifs.read(buf, len);
575 ofs.close();
576 ifs.close();
577 buf[len] = '\0';
578 Magic = buf;
579 return true;
580}
581
Reid Spencerc29befb2004-12-15 01:50:13 +0000582void
583CopyFile(const sys::Path &Dest, const sys::Path &Src) {
584 if (!::CopyFile(Src.c_str(), Dest.c_str(), false))
585 ThrowError("Can't copy '" + Src.toString() +
586 "' to '" + Dest.toString() + "'");
587}
588
589void
590Path::makeUnique() {
591 if (!exists())
592 return; // File doesn't exist already, just use it!
593
594 Path dir (*this);
595 dir.elideFile();
596 std::string fname = this->getLast();
597
Jeff Cohenab68df02004-12-15 04:08:15 +0000598 char newName[MAX_PATH + 1];
Reid Spencerc29befb2004-12-15 01:50:13 +0000599 if (!GetTempFileName(dir.c_str(), fname.c_str(), 0, newName))
600 ThrowError("Cannot make unique filename for '" + path + "'");
601
602 path = newName;
603}
604
Reid Spencerb016a372004-09-15 05:49:50 +0000605}
Reid Spencercbad7012004-09-11 04:59:30 +0000606}
607
608// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
Reid Spencerb016a372004-09-15 05:49:50 +0000609