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