blob: 9377c426454d21af45854be4b711c0a596c18ab7 [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
Jeff Cohencb652552004-12-24 02:38:34 +000026// We need to undo a macro defined in Windows.h, otherwise we won't compile:
27#undef CopyFile
28
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000029static void FlipBackSlashes(std::string& s) {
30 for (size_t i = 0; i < s.size(); i++)
31 if (s[i] == '\\')
32 s[i] = '/';
33}
34
Reid Spencercbad7012004-09-11 04:59:30 +000035namespace llvm {
Reid Spencerb016a372004-09-15 05:49:50 +000036namespace sys {
Reid Spencercbad7012004-09-11 04:59:30 +000037
Reid Spencerb016a372004-09-15 05:49:50 +000038bool
Reid Spencer07adb282004-11-05 22:15:36 +000039Path::isValid() const {
Reid Spencerb016a372004-09-15 05:49:50 +000040 if (path.empty())
41 return false;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000042
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000043 // If there is a colon, it must be the second character, preceded by a letter
44 // and followed by something.
45 size_t len = path.size();
46 size_t pos = path.rfind(':',len);
47 if (pos != std::string::npos) {
48 if (pos != 1 || !isalpha(path[0]) || len < 3)
49 return false;
50 }
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000051
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000052 // Check for illegal characters.
53 if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
54 "\013\014\015\016\017\020\021\022\023\024\025\026"
55 "\027\030\031\032\033\034\035\036\037")
56 != std::string::npos)
57 return false;
58
59 // A file or directory name may not end in a period.
60 if (path[len-1] == '.')
61 return false;
62 if (len >= 2 && path[len-2] == '.' && path[len-1] == '/')
63 return false;
64
65 // A file or directory name may not end in a space.
66 if (path[len-1] == ' ')
67 return false;
68 if (len >= 2 && path[len-2] == ' ' && path[len-1] == '/')
69 return false;
70
71 return true;
Reid Spencercbad7012004-09-11 04:59:30 +000072}
73
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000074static Path *TempDirectory = NULL;
75
Reid Spencerb016a372004-09-15 05:49:50 +000076Path
77Path::GetTemporaryDirectory() {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000078 if (TempDirectory)
79 return *TempDirectory;
80
81 char pathname[MAX_PATH];
82 if (!GetTempPath(MAX_PATH, pathname))
Reid Spencer6a0ec6f2004-09-29 00:01:17 +000083 throw std::string("Can't determine temporary directory");
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000084
Reid Spencerb016a372004-09-15 05:49:50 +000085 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +000086 result.setDirectory(pathname);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000087
88 // Append a subdirectory passed on our process id so multiple LLVMs don't
89 // step on each other's toes.
90 sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
Reid Spencer07adb282004-11-05 22:15:36 +000091 result.appendDirectory(pathname);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000092
93 // If there's a directory left over from a previous LLVM execution that
94 // happened to have the same process id, get rid of it.
Reid Spencer07adb282004-11-05 22:15:36 +000095 result.destroyDirectory(true);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000096
97 // And finally (re-)create the empty directory.
Reid Spencer07adb282004-11-05 22:15:36 +000098 result.createDirectory(false);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +000099 TempDirectory = new Path(result);
100 return *TempDirectory;
Reid Spencerb016a372004-09-15 05:49:50 +0000101}
102
Reid Spencer732f92d2004-12-13 06:57:15 +0000103Path::Path(const std::string& unverified_path)
Reid Spencerb016a372004-09-15 05:49:50 +0000104 : path(unverified_path)
105{
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000106 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000107 if (unverified_path.empty())
108 return;
Reid Spencer07adb282004-11-05 22:15:36 +0000109 if (this->isValid())
Reid Spencerb016a372004-09-15 05:49:50 +0000110 return;
111 // oops, not valid.
112 path.clear();
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000113 throw std::string(unverified_path + ": path is not valid");
Reid Spencerb016a372004-09-15 05:49:50 +0000114}
115
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000116// FIXME: the following set of functions don't map to Windows very well.
Reid Spencerb016a372004-09-15 05:49:50 +0000117Path
118Path::GetRootDirectory() {
119 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000120 result.setDirectory("/");
Reid Spencerb016a372004-09-15 05:49:50 +0000121 return result;
122}
123
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000124static void getPathList(const char*path, std::vector<sys::Path>& Paths) {
125 const char* at = path;
126 const char* delim = strchr(at, ';');
127 Path tmpPath;
128 while( delim != 0 ) {
129 std::string tmp(at, size_t(delim-at));
130 if (tmpPath.setDirectory(tmp))
131 if (tmpPath.readable())
132 Paths.push_back(tmpPath);
133 at = delim + 1;
134 delim = strchr(at, ';');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000135 }
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000136 if (*at != 0)
137 if (tmpPath.setDirectory(std::string(at)))
138 if (tmpPath.readable())
139 Paths.push_back(tmpPath);
140
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000141}
142
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000143void
144Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
145#ifdef LTDL_SHLIBPATH_VAR
146 char* env_var = getenv(LTDL_SHLIBPATH_VAR);
147 if (env_var != 0) {
148 getPathList(env_var,Paths);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000149 }
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000150#endif
151 // FIXME: Should this look at LD_LIBRARY_PATH too?
152 Paths.push_back(sys::Path("C:\\WINDOWS\\SYSTEM32\\"));
153 Paths.push_back(sys::Path("C:\\WINDOWS\\"));
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000154}
155
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000156void
157Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
158 char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
159 if (env_var != 0) {
160 getPathList(env_var,Paths);
161 }
Reid Spencer6c4b7bd2004-12-13 03:03:42 +0000162#ifdef LLVM_LIBDIR
163 {
164 Path tmpPath;
165 if (tmpPath.setDirectory(LLVM_LIBDIR))
166 if (tmpPath.readable())
167 Paths.push_back(tmpPath);
168 }
169#endif
170 GetSystemLibraryPaths(Paths);
Reid Spencerb016a372004-09-15 05:49:50 +0000171}
172
173Path
174Path::GetLLVMDefaultConfigDir() {
175 return Path("/etc/llvm/");
176}
177
178Path
Reid Spencerb016a372004-09-15 05:49:50 +0000179Path::GetUserHomeDirectory() {
180 const char* home = getenv("HOME");
181 if (home) {
182 Path result;
Reid Spencer07adb282004-11-05 22:15:36 +0000183 if (result.setDirectory(home))
Reid Spencerb016a372004-09-15 05:49:50 +0000184 return result;
185 }
186 return GetRootDirectory();
187}
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000188// FIXME: the above set of functions don't map to Windows very well.
189
190bool
Reid Spencer07adb282004-11-05 22:15:36 +0000191Path::isFile() const {
192 return (isValid() && path[path.length()-1] != '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000193}
194
195bool
Reid Spencer07adb282004-11-05 22:15:36 +0000196Path::isDirectory() const {
197 return (isValid() && path[path.length()-1] == '/');
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000198}
199
200std::string
Reid Spencer07adb282004-11-05 22:15:36 +0000201Path::getBasename() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000202 // Find the last slash
203 size_t slash = path.rfind('/');
204 if (slash == std::string::npos)
205 slash = 0;
206 else
207 slash++;
208
209 return path.substr(slash, path.rfind('.'));
210}
211
Reid Spencer07adb282004-11-05 22:15:36 +0000212bool Path::hasMagicNumber(const std::string &Magic) const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000213 size_t len = Magic.size();
214 char *buf = reinterpret_cast<char *>(_alloca(len+1));
215 std::ifstream f(path.c_str());
216 f.read(buf, len);
217 buf[len] = '\0';
218 return Magic == buf;
219}
220
221bool
Reid Spencer07adb282004-11-05 22:15:36 +0000222Path::isBytecodeFile() const {
Reid Spencer4b826812004-11-09 20:27:23 +0000223 char buffer[ 4];
224 buffer[0] = 0;
225 std::ifstream f(path.c_str());
226 f.read(buffer, 4);
227 if (f.bad())
228 ThrowErrno("can't read file signature");
229 return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4);
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000230}
231
232bool
Reid Spencerb016a372004-09-15 05:49:50 +0000233Path::exists() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000234 DWORD attr = GetFileAttributes(path.c_str());
235 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000236}
237
238bool
239Path::readable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000240 // FIXME: take security attributes into account.
241 DWORD attr = GetFileAttributes(path.c_str());
242 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000243}
244
245bool
246Path::writable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000247 // FIXME: take security attributes into account.
248 DWORD attr = GetFileAttributes(path.c_str());
249 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
Reid Spencerb016a372004-09-15 05:49:50 +0000250}
251
252bool
253Path::executable() const {
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000254 // FIXME: take security attributes into account.
255 DWORD attr = GetFileAttributes(path.c_str());
256 return attr != INVALID_FILE_ATTRIBUTES;
Reid Spencerb016a372004-09-15 05:49:50 +0000257}
258
259std::string
260Path::getLast() const {
261 // Find the last slash
262 size_t pos = path.rfind('/');
263
264 // Handle the corner cases
265 if (pos == std::string::npos)
266 return path;
267
268 // If the last character is a slash
269 if (pos == path.length()-1) {
270 // Find the second to last slash
271 size_t pos2 = path.rfind('/', pos-1);
272 if (pos2 == std::string::npos)
273 return path.substr(0,pos);
274 else
275 return path.substr(pos2+1,pos-pos2-1);
276 }
277 // Return everything after the last slash
278 return path.substr(pos+1);
279}
280
Jeff Cohen626e38e2004-12-14 05:26:43 +0000281void
282Path::getStatusInfo(StatusInfo& info) const {
283 WIN32_FILE_ATTRIBUTE_DATA fi;
284 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
285 ThrowError(std::string(path) + ": Can't get status: ");
286
287 info.fileSize = fi.nFileSizeHigh;
288 info.fileSize <<= 32;
289 info.fileSize += fi.nFileSizeLow;
290
291 info.mode = 0777; // Not applicable to Windows, so...
292 info.user = 9999; // Not applicable to Windows, so...
293 info.group = 9999; // Not applicable to Windows, so...
294
295 __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
296 info.modTime.fromWin32Time(ft);
297
298 info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
299 if (info.isDir && path[path.length() - 1] != '/')
300 path += '/';
301 else if (!info.isDir && path[path.length() - 1] == '/')
302 path.erase(path.length() - 1);
303}
304
Reid Spencer77cc91d2004-12-13 19:59:50 +0000305void Path::makeReadable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000306 // All files are readable on Windows (ignoring security attributes).
Reid Spencer77cc91d2004-12-13 19:59:50 +0000307}
308
309void Path::makeWriteable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000310 DWORD attr = GetFileAttributes(path.c_str());
311
312 // If it doesn't exist, we're done.
313 if (attr == INVALID_FILE_ATTRIBUTES)
314 return;
315
316 if (attr & FILE_ATTRIBUTE_READONLY) {
317 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
318 ThrowError(std::string(path) + ": Can't make file writable: ");
319 }
Reid Spencer77cc91d2004-12-13 19:59:50 +0000320}
321
322void Path::makeExecutable() {
Jeff Cohen626e38e2004-12-14 05:26:43 +0000323 // All files are executable on Windows (ignoring security attributes).
Reid Spencer77cc91d2004-12-13 19:59:50 +0000324}
325
Reid Spencerb016a372004-09-15 05:49:50 +0000326bool
Reid Spencer07adb282004-11-05 22:15:36 +0000327Path::setDirectory(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000328 if (a_path.size() == 0)
329 return false;
330 Path save(*this);
331 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000332 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000333 size_t last = a_path.size() -1;
Reid Spencerb0e18872004-12-13 07:51:52 +0000334 if (a_path[last] != '/')
Reid Spencerb016a372004-09-15 05:49:50 +0000335 path += '/';
Reid Spencer07adb282004-11-05 22:15:36 +0000336 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000337 path = save.path;
338 return false;
339 }
340 return true;
341}
342
343bool
Reid Spencer07adb282004-11-05 22:15:36 +0000344Path::setFile(const std::string& a_path) {
Reid Spencerb016a372004-09-15 05:49:50 +0000345 if (a_path.size() == 0)
346 return false;
347 Path save(*this);
348 path = a_path;
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000349 FlipBackSlashes(path);
Reid Spencerb016a372004-09-15 05:49:50 +0000350 size_t last = a_path.size() - 1;
351 while (last > 0 && a_path[last] == '/')
352 last--;
353 path.erase(last+1);
Reid Spencer07adb282004-11-05 22:15:36 +0000354 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000355 path = save.path;
356 return false;
357 }
358 return true;
359}
360
361bool
Reid Spencer07adb282004-11-05 22:15:36 +0000362Path::appendDirectory(const std::string& dir) {
363 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000364 return false;
365 Path save(*this);
366 path += dir;
367 path += "/";
Reid Spencer07adb282004-11-05 22:15:36 +0000368 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000369 path = save.path;
370 return false;
371 }
372 return true;
373}
374
375bool
Reid Spencer07adb282004-11-05 22:15:36 +0000376Path::elideDirectory() {
377 if (isFile())
Reid Spencerb016a372004-09-15 05:49:50 +0000378 return false;
379 size_t slashpos = path.rfind('/',path.size());
380 if (slashpos == 0 || slashpos == std::string::npos)
381 return false;
382 if (slashpos == path.size() - 1)
383 slashpos = path.rfind('/',slashpos-1);
384 if (slashpos == std::string::npos)
385 return false;
386 path.erase(slashpos);
387 return true;
388}
389
390bool
Reid Spencer07adb282004-11-05 22:15:36 +0000391Path::appendFile(const std::string& file) {
392 if (!isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000393 return false;
394 Path save(*this);
395 path += file;
Reid Spencer07adb282004-11-05 22:15:36 +0000396 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000397 path = save.path;
398 return false;
399 }
400 return true;
401}
402
403bool
Reid Spencer07adb282004-11-05 22:15:36 +0000404Path::elideFile() {
405 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000406 return false;
407 size_t slashpos = path.rfind('/',path.size());
408 if (slashpos == std::string::npos)
409 return false;
410 path.erase(slashpos+1);
411 return true;
412}
413
414bool
Reid Spencer07adb282004-11-05 22:15:36 +0000415Path::appendSuffix(const std::string& suffix) {
416 if (isDirectory())
Reid Spencerb016a372004-09-15 05:49:50 +0000417 return false;
418 Path save(*this);
419 path.append(".");
420 path.append(suffix);
Reid Spencer07adb282004-11-05 22:15:36 +0000421 if (!isValid()) {
Reid Spencerb016a372004-09-15 05:49:50 +0000422 path = save.path;
423 return false;
424 }
425 return true;
426}
427
428bool
Reid Spencer07adb282004-11-05 22:15:36 +0000429Path::elideSuffix() {
430 if (isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000431 size_t dotpos = path.rfind('.',path.size());
432 size_t slashpos = path.rfind('/',path.size());
433 if (slashpos != std::string::npos && dotpos != std::string::npos &&
434 dotpos > slashpos) {
435 path.erase(dotpos, path.size()-dotpos);
436 return true;
437 }
438 return false;
439}
440
441
442bool
Reid Spencer07adb282004-11-05 22:15:36 +0000443Path::createDirectory( bool create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000444 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000445 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000446
447 // Get a writeable copy of the path name
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000448 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000449 path.copy(pathname,path.length());
450 pathname[path.length()] = 0;
Reid Spencerb016a372004-09-15 05:49:50 +0000451
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000452 // Determine starting point for initial / search.
453 char *next = pathname;
454 if (pathname[0] == '/' && pathname[1] == '/') {
455 // Skip host name.
456 next = strchr(pathname+2, '/');
457 if (next == NULL)
458 throw std::string(pathname) + ": badly formed remote directory";
459 // Skip share name.
460 next = strchr(next+1, '/');
461 if (next == NULL)
462 throw std::string(pathname) + ": badly formed remote directory";
463 next++;
464 if (*next == 0)
465 throw std::string(pathname) + ": badly formed remote directory";
466 } else {
467 if (pathname[1] == ':')
468 next += 2; // skip drive letter
469 if (*next == '/')
470 next++; // skip root directory
471 }
Reid Spencerb016a372004-09-15 05:49:50 +0000472
473 // If we're supposed to create intermediate directories
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000474 if (create_parents) {
Reid Spencerb016a372004-09-15 05:49:50 +0000475 // Loop through the directory components until we're done
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000476 while (*next) {
477 next = strchr(next, '/');
Reid Spencerb016a372004-09-15 05:49:50 +0000478 *next = 0;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000479 if (!CreateDirectory(pathname, NULL))
480 ThrowError(std::string(pathname) + ": Can't create directory: ");
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000481 *next++ = '/';
Reid Spencerb016a372004-09-15 05:49:50 +0000482 }
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000483 } else {
484 // Drop trailing slash.
485 pathname[path.size()-1] = 0;
486 if (!CreateDirectory(pathname, NULL)) {
487 ThrowError(std::string(pathname) + ": Can't create directory: ");
488 }
Reid Spencerb016a372004-09-15 05:49:50 +0000489 }
490 return true;
491}
492
493bool
Reid Spencer07adb282004-11-05 22:15:36 +0000494Path::createFile() {
Reid Spencerb016a372004-09-15 05:49:50 +0000495 // Make sure we're dealing with a file
Reid Spencer07adb282004-11-05 22:15:36 +0000496 if (!isFile()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000497
498 // Create the file
Reid Spencer6a0ec6f2004-09-29 00:01:17 +0000499 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000500 FILE_ATTRIBUTE_NORMAL, NULL);
501 if (h == INVALID_HANDLE_VALUE)
502 ThrowError(std::string(path.c_str()) + ": Can't create file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000503
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000504 CloseHandle(h);
Reid Spencerb016a372004-09-15 05:49:50 +0000505 return true;
506}
507
508bool
Reid Spencer00e89302004-12-15 23:02:10 +0000509Path::destroyDirectory(bool remove_contents) const {
Reid Spencerb016a372004-09-15 05:49:50 +0000510 // Make sure we're dealing with a directory
Reid Spencer07adb282004-11-05 22:15:36 +0000511 if (!isDirectory()) return false;
Reid Spencerb016a372004-09-15 05:49:50 +0000512
513 // If it doesn't exist, we're done.
514 if (!exists()) return true;
515
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000516 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
517 path.copy(pathname,path.length()+1);
518 int lastchar = path.length() - 1 ;
519 if (pathname[lastchar] == '/')
520 pathname[lastchar] = 0;
521
Reid Spencerb016a372004-09-15 05:49:50 +0000522 if (remove_contents) {
523 // Recursively descend the directory to remove its content
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000524 // FIXME: The correct way of doing this on Windows isn't pretty...
525 // but this may work if unix-like utils are present.
526 std::string cmd("rm -rf ");
Reid Spencerb016a372004-09-15 05:49:50 +0000527 cmd += path;
528 system(cmd.c_str());
529 } else {
530 // Otherwise, try to just remove the one directory
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000531 if (!RemoveDirectory(pathname))
532 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000533 }
534 return true;
535}
536
537bool
Reid Spencer00e89302004-12-15 23:02:10 +0000538Path::destroyFile() const {
Reid Spencer07adb282004-11-05 22:15:36 +0000539 if (!isFile()) return false;
Reid Spencerd0c9e0e2004-09-18 19:29:16 +0000540
541 DWORD attr = GetFileAttributes(path.c_str());
542
543 // If it doesn't exist, we're done.
544 if (attr == INVALID_FILE_ATTRIBUTES)
545 return true;
546
547 // Read-only files cannot be deleted on Windows. Must remove the read-only
548 // attribute first.
549 if (attr & FILE_ATTRIBUTE_READONLY) {
550 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
551 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
552 }
553
554 if (!DeleteFile(path.c_str()))
555 ThrowError(std::string(path.c_str()) + ": Can't destroy file: ");
Reid Spencerb016a372004-09-15 05:49:50 +0000556 return true;
557}
558
Reid Spencer3b0cc782004-12-14 18:42:13 +0000559bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
560 if (!isFile())
561 return false;
562 assert(len < 1024 && "Request for magic string too long");
563 char* buf = (char*) alloca(1 + len);
564 std::ofstream ofs(path.c_str(),std::ofstream::in);
565 if (!ofs.is_open())
566 return false;
567 std::ifstream ifs(path.c_str());
568 if (!ifs.is_open())
569 return false;
570 ifs.read(buf, len);
571 ofs.close();
572 ifs.close();
573 buf[len] = '\0';
574 Magic = buf;
575 return true;
576}
577
Reid Spencerc29befb2004-12-15 01:50:13 +0000578void
Reid Spencera36c9a42004-12-23 22:14:32 +0000579sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) {
Jeff Cohencb652552004-12-24 02:38:34 +0000580 // Can't use CopyFile macro defined in Windows.h because it would mess up the
581 // above line. We use the expansion it would have in a non-UNICODE build.
582 if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
Reid Spencerc29befb2004-12-15 01:50:13 +0000583 ThrowError("Can't copy '" + Src.toString() +
584 "' to '" + Dest.toString() + "'");
585}
586
587void
Jeff Cohencb652552004-12-24 02:38:34 +0000588Path::makeUnique(bool reuse_current) {
Reid Spencer07f9f4e2004-12-15 08:32:45 +0000589 if (reuse_current && !exists())
Reid Spencerc29befb2004-12-15 01:50:13 +0000590 return; // File doesn't exist already, just use it!
591
592 Path dir (*this);
593 dir.elideFile();
594 std::string fname = this->getLast();
595
Jeff Cohenab68df02004-12-15 04:08:15 +0000596 char newName[MAX_PATH + 1];
Reid Spencerc29befb2004-12-15 01:50:13 +0000597 if (!GetTempFileName(dir.c_str(), fname.c_str(), 0, newName))
598 ThrowError("Cannot make unique filename for '" + path + "'");
599
600 path = newName;
601}
602
Reid Spencer07f9f4e2004-12-15 08:32:45 +0000603bool
604Path::createTemporaryFile(bool reuse_current) {
605 // Make sure we're dealing with a file
606 if (!isFile())
607 return false;
608
609 // Make this into a unique file name
610 makeUnique( reuse_current );
Jeff Cohenf8cdb852004-12-18 06:42:15 +0000611 return true;
Reid Spencer07f9f4e2004-12-15 08:32:45 +0000612}
613
Reid Spencerb016a372004-09-15 05:49:50 +0000614}
Reid Spencercbad7012004-09-11 04:59:30 +0000615}
616
617// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
Reid Spencerb016a372004-09-15 05:49:50 +0000618