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