Fix preload instruction isel. Only v7 supports pli, and only v7 with mp extension...
[oota-llvm.git] / lib / System / Win32 / Path.inc
1 //===- llvm/System/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 // Modified by Henrik Bach to comply with at least MinGW.
9 // Ported to Win32 by Jeff Cohen.
10 //
11 //===----------------------------------------------------------------------===//
12 //
13 // This file provides the Win32 specific implementation of the Path class.
14 //
15 //===----------------------------------------------------------------------===//
16
17 //===----------------------------------------------------------------------===//
18 //=== WARNING: Implementation here must contain only generic Win32 code that
19 //===          is guaranteed to work on *all* Win32 variants.
20 //===----------------------------------------------------------------------===//
21
22 #include "Win32.h"
23 #include <malloc.h>
24 #include <cstdio>
25
26 // We need to undo a macro defined in Windows.h, otherwise we won't compile:
27 #undef CopyFile
28 #undef GetCurrentDirectory
29
30 // Windows happily accepts either forward or backward slashes, though any path
31 // returned by a Win32 API will have backward slashes.  As LLVM code basically
32 // assumes forward slashes are used, backward slashs are converted where they
33 // can be introduced into a path.
34 //
35 // Another invariant is that a path ends with a slash if and only if the path
36 // is a root directory.  Any other use of a trailing slash is stripped.  Unlike
37 // in Unix, Windows has a rather complicated notion of a root path and this
38 // invariant helps simply the code.
39
40 static void FlipBackSlashes(std::string& s) {
41   for (size_t i = 0; i < s.size(); i++)
42     if (s[i] == '\\')
43       s[i] = '/';
44 }
45
46 namespace llvm {
47 namespace sys {
48
49 const char PathSeparator = ';';
50
51 StringRef Path::GetEXESuffix() {
52   return "exe";
53 }
54
55 Path::Path(llvm::StringRef p)
56   : path(p) {
57   FlipBackSlashes(path);
58 }
59
60 Path::Path(const char *StrStart, unsigned StrLen)
61   : path(StrStart, StrLen) {
62   FlipBackSlashes(path);
63 }
64
65 Path&
66 Path::operator=(StringRef that) {
67   path.assign(that.data(), that.size());
68   FlipBackSlashes(path);
69   return *this;
70 }
71
72 // push_back 0 on create, and pop_back on delete.
73 struct ScopedNullTerminator {
74   std::string &str;
75   ScopedNullTerminator(std::string &s) : str(s) { str.push_back(0); }
76   ~ScopedNullTerminator() {
77     // str.pop_back(); But wait, C++03 doesn't have this...
78     assert(!str.empty() && str[str.size() - 1] == 0
79       && "Null char not present!");
80     str.resize(str.size() - 1);
81   }
82 };
83
84 bool
85 Path::isValid() const {
86   if (path.empty())
87     return false;
88
89   // If there is a colon, it must be the second character, preceded by a letter
90   // and followed by something.
91   size_t len = path.size();
92   // This code assumes that path is null terminated, so make sure it is.
93   ScopedNullTerminator snt(path);
94   size_t pos = path.rfind(':',len);
95   size_t rootslash = 0;
96   if (pos != std::string::npos) {
97     if (pos != 1 || !isalpha(path[0]) || len < 3)
98       return false;
99       rootslash = 2;
100   }
101
102   // Look for a UNC path, and if found adjust our notion of the root slash.
103   if (len > 3 && path[0] == '/' && path[1] == '/') {
104     rootslash = path.find('/', 2);
105     if (rootslash == std::string::npos)
106       rootslash = 0;
107   }
108
109   // Check for illegal characters.
110   if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
111                          "\013\014\015\016\017\020\021\022\023\024\025\026"
112                          "\027\030\031\032\033\034\035\036\037")
113       != std::string::npos)
114     return false;
115
116   // Remove trailing slash, unless it's a root slash.
117   if (len > rootslash+1 && path[len-1] == '/')
118     path.erase(--len);
119
120   // Check each component for legality.
121   for (pos = 0; pos < len; ++pos) {
122     // A component may not end in a space.
123     if (path[pos] == ' ') {
124       if (path[pos+1] == '/' || path[pos+1] == '\0')
125         return false;
126     }
127
128     // A component may not end in a period.
129     if (path[pos] == '.') {
130       if (path[pos+1] == '/' || path[pos+1] == '\0') {
131         // Unless it is the pseudo-directory "."...
132         if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
133           return true;
134         // or "..".
135         if (pos > 0 && path[pos-1] == '.') {
136           if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
137             return true;
138         }
139         return false;
140       }
141     }
142   }
143
144   return true;
145 }
146
147 void Path::makeAbsolute() {
148   TCHAR  FullPath[MAX_PATH + 1] = {0};
149   LPTSTR FilePart = NULL;
150
151   DWORD RetLength = ::GetFullPathNameA(path.c_str(),
152                         sizeof(FullPath)/sizeof(FullPath[0]),
153                         FullPath, &FilePart);
154
155   if (0 == RetLength) {
156     // FIXME: Report the error GetLastError()
157     assert(0 && "Unable to make absolute path!");
158   } else if (RetLength > MAX_PATH) {
159     // FIXME: Report too small buffer (needed RetLength bytes).
160     assert(0 && "Unable to make absolute path!");
161   } else {
162     path = FullPath;
163   }
164 }
165
166 bool
167 Path::isAbsolute(const char *NameStart, unsigned NameLen) {
168   assert(NameStart);
169   // FIXME: This does not handle correctly an absolute path starting from
170   // a drive letter or in UNC format.
171   switch (NameLen) {
172   case 0:
173     return false;
174   case 1:
175   case 2:
176     return NameStart[0] == '/';
177   default:
178     return
179       (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) ||
180       (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\'));
181   }
182 }
183
184 bool
185 Path::isAbsolute() const {
186   // FIXME: This does not handle correctly an absolute path starting from
187   // a drive letter or in UNC format.
188   switch (path.length()) {
189     case 0:
190       return false;
191     case 1:
192     case 2:
193       return path[0] == '/';
194     default:
195       return path[0] == '/' || (path[1] == ':' && path[2] == '/');
196   }
197 }
198
199 static Path *TempDirectory;
200
201 Path
202 Path::GetTemporaryDirectory(std::string* ErrMsg) {
203   if (TempDirectory)
204     return *TempDirectory;
205
206   char pathname[MAX_PATH];
207   if (!GetTempPath(MAX_PATH, pathname)) {
208     if (ErrMsg)
209       *ErrMsg = "Can't determine temporary directory";
210     return Path();
211   }
212
213   Path result;
214   result.set(pathname);
215
216   // Append a subdirectory passed on our process id so multiple LLVMs don't
217   // step on each other's toes.
218 #ifdef __MINGW32__
219   // Mingw's Win32 header files are broken.
220   sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId()));
221 #else
222   sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
223 #endif
224   result.appendComponent(pathname);
225
226   // If there's a directory left over from a previous LLVM execution that
227   // happened to have the same process id, get rid of it.
228   result.eraseFromDisk(true);
229
230   // And finally (re-)create the empty directory.
231   result.createDirectoryOnDisk(false);
232   TempDirectory = new Path(result);
233   return *TempDirectory;
234 }
235
236 // FIXME: the following set of functions don't map to Windows very well.
237 Path
238 Path::GetRootDirectory() {
239   Path result;
240   result.set("C:/");
241   return result;
242 }
243
244 void
245 Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
246   Paths.push_back(sys::Path("C:/WINDOWS/SYSTEM32"));
247   Paths.push_back(sys::Path("C:/WINDOWS"));
248 }
249
250 void
251 Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
252   char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
253   if (env_var != 0) {
254     getPathList(env_var,Paths);
255   }
256 #ifdef LLVM_LIBDIR
257   {
258     Path tmpPath;
259     if (tmpPath.set(LLVM_LIBDIR))
260       if (tmpPath.canRead())
261         Paths.push_back(tmpPath);
262   }
263 #endif
264   GetSystemLibraryPaths(Paths);
265 }
266
267 Path
268 Path::GetLLVMDefaultConfigDir() {
269   // TODO: this isn't going to fly on Windows
270   return Path("/etc/llvm");
271 }
272
273 Path
274 Path::GetUserHomeDirectory() {
275   // TODO: Typical Windows setup doesn't define HOME.
276   const char* home = getenv("HOME");
277   if (home) {
278     Path result;
279     if (result.set(home))
280       return result;
281   }
282   return GetRootDirectory();
283 }
284
285 Path
286 Path::GetCurrentDirectory() {
287   char pathname[MAX_PATH];
288   ::GetCurrentDirectoryA(MAX_PATH,pathname);
289   return Path(pathname);
290 }
291
292 /// GetMainExecutable - Return the path to the main executable, given the
293 /// value of argv[0] from program startup.
294 Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
295   char pathname[MAX_PATH];
296   DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH);
297   return ret != MAX_PATH ? Path(pathname) : Path();
298 }
299
300
301 // FIXME: the above set of functions don't map to Windows very well.
302
303
304 StringRef Path::getDirname() const {
305   return getDirnameCharSep(path, "/");
306 }
307
308 StringRef
309 Path::getBasename() const {
310   // Find the last slash
311   size_t slash = path.rfind('/');
312   if (slash == std::string::npos)
313     slash = 0;
314   else
315     slash++;
316
317   size_t dot = path.rfind('.');
318   if (dot == std::string::npos || dot < slash)
319     return StringRef(path).substr(slash);
320   else
321     return StringRef(path).substr(slash, dot - slash);
322 }
323
324 StringRef
325 Path::getSuffix() const {
326   // Find the last slash
327   size_t slash = path.rfind('/');
328   if (slash == std::string::npos)
329     slash = 0;
330   else
331     slash++;
332
333   size_t dot = path.rfind('.');
334   if (dot == std::string::npos || dot < slash)
335     return StringRef("");
336   else
337     return StringRef(path).substr(dot + 1);
338 }
339
340 bool
341 Path::exists() const {
342   DWORD attr = GetFileAttributes(path.c_str());
343   return attr != INVALID_FILE_ATTRIBUTES;
344 }
345
346 bool
347 Path::isDirectory() const {
348   DWORD attr = GetFileAttributes(path.c_str());
349   return (attr != INVALID_FILE_ATTRIBUTES) &&
350          (attr & FILE_ATTRIBUTE_DIRECTORY);
351 }
352
353 bool
354 Path::canRead() const {
355   // FIXME: take security attributes into account.
356   DWORD attr = GetFileAttributes(path.c_str());
357   return attr != INVALID_FILE_ATTRIBUTES;
358 }
359
360 bool
361 Path::canWrite() const {
362   // FIXME: take security attributes into account.
363   DWORD attr = GetFileAttributes(path.c_str());
364   return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
365 }
366
367 bool
368 Path::canExecute() const {
369   // FIXME: take security attributes into account.
370   DWORD attr = GetFileAttributes(path.c_str());
371   return attr != INVALID_FILE_ATTRIBUTES;
372 }
373
374 bool
375 Path::isRegularFile() const {
376   if (isDirectory())
377     return false;
378   return true;
379 }
380
381 StringRef
382 Path::getLast() const {
383   // Find the last slash
384   size_t pos = path.rfind('/');
385
386   // Handle the corner cases
387   if (pos == std::string::npos)
388     return path;
389
390   // If the last character is a slash, we have a root directory
391   if (pos == path.length()-1)
392     return path;
393
394   // Return everything after the last slash
395   return StringRef(path).substr(pos+1);
396 }
397
398 const FileStatus *
399 PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
400   if (!fsIsValid || update) {
401     WIN32_FILE_ATTRIBUTE_DATA fi;
402     if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
403       MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
404                       ": Can't get status: ");
405       return 0;
406     }
407
408     status.fileSize = fi.nFileSizeHigh;
409     status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
410     status.fileSize += fi.nFileSizeLow;
411
412     status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
413     status.user = 9999;    // Not applicable to Windows, so...
414     status.group = 9999;   // Not applicable to Windows, so...
415
416     // FIXME: this is only unique if the file is accessed by the same file path.
417     // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
418     // numbers, but the concept doesn't exist in Windows.
419     status.uniqueID = 0;
420     for (unsigned i = 0; i < path.length(); ++i)
421       status.uniqueID += path[i];
422
423     ULARGE_INTEGER ui;
424     ui.LowPart = fi.ftLastWriteTime.dwLowDateTime;
425     ui.HighPart = fi.ftLastWriteTime.dwHighDateTime;
426     status.modTime.fromWin32Time(ui.QuadPart);
427
428     status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
429     fsIsValid = true;
430   }
431   return &status;
432 }
433
434 bool Path::makeReadableOnDisk(std::string* ErrMsg) {
435   // All files are readable on Windows (ignoring security attributes).
436   return false;
437 }
438
439 bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
440   DWORD attr = GetFileAttributes(path.c_str());
441
442   // If it doesn't exist, we're done.
443   if (attr == INVALID_FILE_ATTRIBUTES)
444     return false;
445
446   if (attr & FILE_ATTRIBUTE_READONLY) {
447     if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
448       MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
449       return true;
450     }
451   }
452   return false;
453 }
454
455 bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
456   // All files are executable on Windows (ignoring security attributes).
457   return false;
458 }
459
460 bool
461 Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
462   WIN32_FILE_ATTRIBUTE_DATA fi;
463   if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
464     MakeErrMsg(ErrMsg, path + ": can't get status of file");
465     return true;
466   }
467
468   if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
469     if (ErrMsg)
470       *ErrMsg = path + ": not a directory";
471     return true;
472   }
473
474   result.clear();
475   WIN32_FIND_DATA fd;
476   std::string searchpath = path;
477   if (path.size() == 0 || searchpath[path.size()-1] == '/')
478     searchpath += "*";
479   else
480     searchpath += "/*";
481
482   HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
483   if (h == INVALID_HANDLE_VALUE) {
484     if (GetLastError() == ERROR_FILE_NOT_FOUND)
485       return true; // not really an error, now is it?
486     MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
487     return true;
488   }
489
490   do {
491     if (fd.cFileName[0] == '.')
492       continue;
493     Path aPath(path);
494     aPath.appendComponent(&fd.cFileName[0]);
495     result.insert(aPath);
496   } while (FindNextFile(h, &fd));
497
498   DWORD err = GetLastError();
499   FindClose(h);
500   if (err != ERROR_NO_MORE_FILES) {
501     SetLastError(err);
502     MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
503     return true;
504   }
505   return false;
506 }
507
508 bool
509 Path::set(StringRef a_path) {
510   if (a_path.empty())
511     return false;
512   std::string save(path);
513   path = a_path;
514   FlipBackSlashes(path);
515   if (!isValid()) {
516     path = save;
517     return false;
518   }
519   return true;
520 }
521
522 bool
523 Path::appendComponent(StringRef name) {
524   if (name.empty())
525     return false;
526   std::string save(path);
527   if (!path.empty()) {
528     size_t last = path.size() - 1;
529     if (path[last] != '/')
530       path += '/';
531   }
532   path += name;
533   if (!isValid()) {
534     path = save;
535     return false;
536   }
537   return true;
538 }
539
540 bool
541 Path::eraseComponent() {
542   size_t slashpos = path.rfind('/',path.size());
543   if (slashpos == path.size() - 1 || slashpos == std::string::npos)
544     return false;
545   std::string save(path);
546   path.erase(slashpos);
547   if (!isValid()) {
548     path = save;
549     return false;
550   }
551   return true;
552 }
553
554 bool
555 Path::eraseSuffix() {
556   size_t dotpos = path.rfind('.',path.size());
557   size_t slashpos = path.rfind('/',path.size());
558   if (dotpos != std::string::npos) {
559     if (slashpos == std::string::npos || dotpos > slashpos+1) {
560       std::string save(path);
561       path.erase(dotpos, path.size()-dotpos);
562       if (!isValid()) {
563         path = save;
564         return false;
565       }
566       return true;
567     }
568   }
569   return false;
570 }
571
572 inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
573   if (ErrMsg)
574     *ErrMsg = std::string(pathname) + ": " + std::string(msg);
575   return true;
576 }
577
578 bool
579 Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
580   // Get a writeable copy of the path name
581   size_t len = path.length();
582   char *pathname = reinterpret_cast<char *>(_alloca(len+2));
583   path.copy(pathname, len);
584   pathname[len] = 0;
585
586   // Make sure it ends with a slash.
587   if (len == 0 || pathname[len - 1] != '/') {
588     pathname[len] = '/';
589     pathname[++len] = 0;
590   }
591
592   // Determine starting point for initial / search.
593   char *next = pathname;
594   if (pathname[0] == '/' && pathname[1] == '/') {
595     // Skip host name.
596     next = strchr(pathname+2, '/');
597     if (next == NULL)
598       return PathMsg(ErrMsg, pathname, "badly formed remote directory");
599
600     // Skip share name.
601     next = strchr(next+1, '/');
602     if (next == NULL)
603       return PathMsg(ErrMsg, pathname,"badly formed remote directory");
604
605     next++;
606     if (*next == 0)
607       return PathMsg(ErrMsg, pathname, "badly formed remote directory");
608
609   } else {
610     if (pathname[1] == ':')
611       next += 2;    // skip drive letter
612     if (*next == '/')
613       next++;       // skip root directory
614   }
615
616   // If we're supposed to create intermediate directories
617   if (create_parents) {
618     // Loop through the directory components until we're done
619     while (*next) {
620       next = strchr(next, '/');
621       *next = 0;
622       if (!CreateDirectory(pathname, NULL) &&
623           GetLastError() != ERROR_ALREADY_EXISTS)
624           return MakeErrMsg(ErrMsg,
625             std::string(pathname) + ": Can't create directory: ");
626       *next++ = '/';
627     }
628   } else {
629     // Drop trailing slash.
630     pathname[len-1] = 0;
631     if (!CreateDirectory(pathname, NULL) &&
632         GetLastError() != ERROR_ALREADY_EXISTS) {
633       return MakeErrMsg(ErrMsg, std::string(pathname) +
634                         ": Can't create directory: ");
635     }
636   }
637   return false;
638 }
639
640 bool
641 Path::createFileOnDisk(std::string* ErrMsg) {
642   // Create the file
643   HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
644                         FILE_ATTRIBUTE_NORMAL, NULL);
645   if (h == INVALID_HANDLE_VALUE)
646     return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
647
648   CloseHandle(h);
649   return false;
650 }
651
652 bool
653 Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
654   WIN32_FILE_ATTRIBUTE_DATA fi;
655   if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
656     return true;
657
658   if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
659     // If it doesn't exist, we're done.
660     if (!exists())
661       return false;
662
663     char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
664     int lastchar = path.length() - 1 ;
665     path.copy(pathname, lastchar+1);
666
667     // Make path end with '/*'.
668     if (pathname[lastchar] != '/')
669       pathname[++lastchar] = '/';
670     pathname[lastchar+1] = '*';
671     pathname[lastchar+2] = 0;
672
673     if (remove_contents) {
674       WIN32_FIND_DATA fd;
675       HANDLE h = FindFirstFile(pathname, &fd);
676
677       // It's a bad idea to alter the contents of a directory while enumerating
678       // its contents. So build a list of its contents first, then destroy them.
679
680       if (h != INVALID_HANDLE_VALUE) {
681         std::vector<Path> list;
682
683         do {
684           if (strcmp(fd.cFileName, ".") == 0)
685             continue;
686           if (strcmp(fd.cFileName, "..") == 0)
687             continue;
688
689           Path aPath(path);
690           aPath.appendComponent(&fd.cFileName[0]);
691           list.push_back(aPath);
692         } while (FindNextFile(h, &fd));
693
694         DWORD err = GetLastError();
695         FindClose(h);
696         if (err != ERROR_NO_MORE_FILES) {
697           SetLastError(err);
698           return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
699         }
700
701         for (std::vector<Path>::iterator I = list.begin(); I != list.end();
702              ++I) {
703           Path &aPath = *I;
704           aPath.eraseFromDisk(true);
705         }
706       } else {
707         if (GetLastError() != ERROR_FILE_NOT_FOUND)
708           return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
709       }
710     }
711
712     pathname[lastchar] = 0;
713     if (!RemoveDirectory(pathname))
714       return MakeErrMsg(ErrStr,
715         std::string(pathname) + ": Can't destroy directory: ");
716     return false;
717   } else {
718     // Read-only files cannot be deleted on Windows.  Must remove the read-only
719     // attribute first.
720     if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
721       if (!SetFileAttributes(path.c_str(),
722                              fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
723         return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
724     }
725
726     if (!DeleteFile(path.c_str()))
727       return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
728     return false;
729   }
730 }
731
732 bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
733   assert(len < 1024 && "Request for magic string too long");
734   char* buf = reinterpret_cast<char*>(alloca(len));
735
736   HANDLE h = CreateFile(path.c_str(),
737                         GENERIC_READ,
738                         FILE_SHARE_READ,
739                         NULL,
740                         OPEN_EXISTING,
741                         FILE_ATTRIBUTE_NORMAL,
742                         NULL);
743   if (h == INVALID_HANDLE_VALUE)
744     return false;
745
746   DWORD nRead = 0;
747   BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
748   CloseHandle(h);
749
750   if (!ret || nRead != len)
751     return false;
752
753   Magic = std::string(buf, len);
754   return true;
755 }
756
757 bool
758 Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
759   if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
760     return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
761         + "': ");
762   return false;
763 }
764
765 bool
766 Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
767   // FIXME: should work on directories also.
768   if (!si.isFile) {
769     return true;
770   }
771
772   HANDLE h = CreateFile(path.c_str(),
773                         FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
774                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
775                         NULL,
776                         OPEN_EXISTING,
777                         FILE_ATTRIBUTE_NORMAL,
778                         NULL);
779   if (h == INVALID_HANDLE_VALUE)
780     return true;
781
782   BY_HANDLE_FILE_INFORMATION bhfi;
783   if (!GetFileInformationByHandle(h, &bhfi)) {
784     DWORD err = GetLastError();
785     CloseHandle(h);
786     SetLastError(err);
787     return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
788   }
789
790   ULARGE_INTEGER ui;
791   ui.QuadPart = si.modTime.toWin32Time();
792   FILETIME ft;
793   ft.dwLowDateTime = ui.LowPart;
794   ft.dwHighDateTime = ui.HighPart;
795   BOOL ret = SetFileTime(h, NULL, &ft, &ft);
796   DWORD err = GetLastError();
797   CloseHandle(h);
798   if (!ret) {
799     SetLastError(err);
800     return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
801   }
802
803   // Best we can do with Unix permission bits is to interpret the owner
804   // writable bit.
805   if (si.mode & 0200) {
806     if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
807       if (!SetFileAttributes(path.c_str(),
808               bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
809         return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
810     }
811   } else {
812     if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
813       if (!SetFileAttributes(path.c_str(),
814               bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
815         return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
816     }
817   }
818
819   return false;
820 }
821
822 bool
823 CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) {
824   // Can't use CopyFile macro defined in Windows.h because it would mess up the
825   // above line.  We use the expansion it would have in a non-UNICODE build.
826   if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
827     return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() +
828                "' to '" + Dest.str() + "': ");
829   return false;
830 }
831
832 bool
833 Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
834   if (reuse_current && !exists())
835     return false; // File doesn't exist already, just use it!
836
837   // Reserve space for -XXXXXX at the end.
838   char *FNBuffer = (char*) alloca(path.size()+8);
839   unsigned offset = path.size();
840   path.copy(FNBuffer, offset);
841
842   // Find a numeric suffix that isn't used by an existing file.  Assume there
843   // won't be more than 1 million files with the same prefix.  Probably a safe
844   // bet.
845   static unsigned FCounter = 0;
846   do {
847     sprintf(FNBuffer+offset, "-%06u", FCounter);
848     if (++FCounter > 999999)
849       FCounter = 0;
850     path = FNBuffer;
851   } while (exists());
852   return false;
853 }
854
855 bool
856 Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
857   // Make this into a unique file name
858   makeUnique(reuse_current, ErrMsg);
859
860   // Now go and create it
861   HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
862                         FILE_ATTRIBUTE_NORMAL, NULL);
863   if (h == INVALID_HANDLE_VALUE)
864     return MakeErrMsg(ErrMsg, path + ": can't create file");
865
866   CloseHandle(h);
867   return false;
868 }
869
870 /// MapInFilePages - Not yet implemented on win32.
871 const char *Path::MapInFilePages(int FD, uint64_t FileSize) {
872   return 0;
873 }
874
875 /// MapInFilePages - Not yet implemented on win32.
876 void Path::UnMapFilePages(const char *Base, uint64_t FileSize) {
877   assert(0 && "NOT IMPLEMENTED");
878 }
879
880 }
881 }