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