LLVM API Documentation

Win32/Path.inc

Go to the documentation of this file.
00001 //===- llvm/System/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 // Modified by Henrik Bach to comply with at least MinGW.
00009 // Ported to Win32 by Jeff Cohen.
00010 //
00011 //===----------------------------------------------------------------------===//
00012 //
00013 // This file provides the Win32 specific implementation of the Path class.
00014 //
00015 //===----------------------------------------------------------------------===//
00016 
00017 //===----------------------------------------------------------------------===//
00018 //=== WARNING: Implementation here must contain only generic Win32 code that
00019 //===          is guaranteed to work on *all* Win32 variants.
00020 //===----------------------------------------------------------------------===//
00021 
00022 #include "Win32.h"
00023 #include <malloc.h>
00024 
00025 // We need to undo a macro defined in Windows.h, otherwise we won't compile:
00026 #undef CopyFile
00027 #undef GetCurrentDirectory
00028 
00029 // Windows happily accepts either forward or backward slashes, though any path
00030 // returned by a Win32 API will have backward slashes.  As LLVM code basically
00031 // assumes forward slashes are used, backward slashs are converted where they
00032 // can be introduced into a path.
00033 //
00034 // Another invariant is that a path ends with a slash if and only if the path
00035 // is a root directory.  Any other use of a trailing slash is stripped.  Unlike
00036 // in Unix, Windows has a rather complicated notion of a root path and this
00037 // invariant helps simply the code.
00038 
00039 static void FlipBackSlashes(std::string& s) {
00040   for (size_t i = 0; i < s.size(); i++)
00041     if (s[i] == '\\')
00042       s[i] = '/';
00043 }
00044 
00045 namespace llvm {
00046 namespace sys {
00047 const char PathSeparator = ';';
00048 
00049 Path::Path(const std::string& p)
00050   : path(p) {
00051   FlipBackSlashes(path);
00052 }
00053 
00054 Path::Path(const char *StrStart, unsigned StrLen)
00055   : path(StrStart, StrLen) {
00056   FlipBackSlashes(path);
00057 }
00058 
00059 Path&
00060 Path::operator=(const std::string &that) {
00061   path = that;
00062   FlipBackSlashes(path);
00063   return *this;
00064 }
00065 
00066 bool
00067 Path::isValid() const {
00068   if (path.empty())
00069     return false;
00070 
00071   // If there is a colon, it must be the second character, preceded by a letter
00072   // and followed by something.
00073   size_t len = path.size();
00074   size_t pos = path.rfind(':',len);
00075   size_t rootslash = 0;
00076   if (pos != std::string::npos) {
00077     if (pos != 1 || !isalpha(path[0]) || len < 3)
00078       return false;
00079       rootslash = 2;
00080   }
00081 
00082   // Look for a UNC path, and if found adjust our notion of the root slash.
00083   if (len > 3 && path[0] == '/' && path[1] == '/') {
00084     rootslash = path.find('/', 2);
00085     if (rootslash == std::string::npos)
00086       rootslash = 0;
00087   }
00088 
00089   // Check for illegal characters.
00090   if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
00091                          "\013\014\015\016\017\020\021\022\023\024\025\026"
00092                          "\027\030\031\032\033\034\035\036\037")
00093       != std::string::npos)
00094     return false;
00095 
00096   // Remove trailing slash, unless it's a root slash.
00097   if (len > rootslash+1 && path[len-1] == '/')
00098     path.erase(--len);
00099 
00100   // Check each component for legality.
00101   for (pos = 0; pos < len; ++pos) {
00102     // A component may not end in a space.
00103     if (path[pos] == ' ') {
00104       if (path[pos+1] == '/' || path[pos+1] == '\0')
00105         return false;
00106     }
00107 
00108     // A component may not end in a period.
00109     if (path[pos] == '.') {
00110       if (path[pos+1] == '/' || path[pos+1] == '\0') {
00111         // Unless it is the pseudo-directory "."...
00112         if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
00113           return true;
00114         // or "..".
00115         if (pos > 0 && path[pos-1] == '.') {
00116           if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
00117             return true;
00118         }
00119         return false;
00120       }
00121     }
00122   }
00123 
00124   return true;
00125 }
00126 
00127 bool 
00128 Path::isAbsolute() const {
00129   switch (path.length()) {
00130     case 0:
00131       return false;
00132     case 1:
00133     case 2:
00134       return path[0] == '/';
00135     default:
00136       return path[0] == '/' || (path[1] == ':' && path[2] == '/');
00137   }
00138 } 
00139 
00140 static Path *TempDirectory = NULL;
00141 
00142 Path
00143 Path::GetTemporaryDirectory(std::string* ErrMsg) {
00144   if (TempDirectory)
00145     return *TempDirectory;
00146 
00147   char pathname[MAX_PATH];
00148   if (!GetTempPath(MAX_PATH, pathname)) {
00149     if (ErrMsg)
00150       *ErrMsg = "Can't determine temporary directory";
00151     return Path();
00152   }
00153 
00154   Path result;
00155   result.set(pathname);
00156 
00157   // Append a subdirectory passed on our process id so multiple LLVMs don't
00158   // step on each other's toes.
00159 #ifdef __MINGW32__
00160   // Mingw's Win32 header files are broken.
00161   sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId()));
00162 #else
00163   sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
00164 #endif
00165   result.appendComponent(pathname);
00166 
00167   // If there's a directory left over from a previous LLVM execution that
00168   // happened to have the same process id, get rid of it.
00169   result.eraseFromDisk(true);
00170 
00171   // And finally (re-)create the empty directory.
00172   result.createDirectoryOnDisk(false);
00173   TempDirectory = new Path(result);
00174   return *TempDirectory;
00175 }
00176 
00177 // FIXME: the following set of functions don't map to Windows very well.
00178 Path
00179 Path::GetRootDirectory() {
00180   Path result;
00181   result.set("C:/");
00182   return result;
00183 }
00184 
00185 void
00186 Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
00187   Paths.push_back(sys::Path("C:/WINDOWS/SYSTEM32"));
00188   Paths.push_back(sys::Path("C:/WINDOWS"));
00189 }
00190 
00191 void
00192 Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
00193   char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
00194   if (env_var != 0) {
00195     getPathList(env_var,Paths);
00196   }
00197 #ifdef LLVM_LIBDIR
00198   {
00199     Path tmpPath;
00200     if (tmpPath.set(LLVM_LIBDIR))
00201       if (tmpPath.canRead())
00202         Paths.push_back(tmpPath);
00203   }
00204 #endif
00205   GetSystemLibraryPaths(Paths);
00206 }
00207 
00208 Path
00209 Path::GetLLVMDefaultConfigDir() {
00210   // TODO: this isn't going to fly on Windows
00211   return Path("/etc/llvm");
00212 }
00213 
00214 Path
00215 Path::GetUserHomeDirectory() {
00216   // TODO: Typical Windows setup doesn't define HOME.
00217   const char* home = getenv("HOME");
00218   if (home) {
00219     Path result;
00220     if (result.set(home))
00221       return result;
00222   }
00223   return GetRootDirectory();
00224 }
00225 
00226 Path
00227 Path::GetCurrentDirectory() {
00228   char pathname[MAX_PATH];
00229   ::GetCurrentDirectoryA(MAX_PATH,pathname);
00230   return Path(pathname);  
00231 }
00232 
00233 /// GetMainExecutable - Return the path to the main executable, given the
00234 /// value of argv[0] from program startup.
00235 Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
00236   return Path();
00237 }
00238 
00239 
00240 // FIXME: the above set of functions don't map to Windows very well.
00241 
00242 
00243 bool
00244 Path::isRootDirectory() const {
00245   size_t len = path.size();
00246   return len > 0 && path[len-1] == '/';
00247 }
00248 
00249 std::string Path::getDirname() const {
00250   return getDirnameCharSep(path, '/');
00251 }
00252 
00253 std::string
00254 Path::getBasename() const {
00255   // Find the last slash
00256   size_t slash = path.rfind('/');
00257   if (slash == std::string::npos)
00258     slash = 0;
00259   else
00260     slash++;
00261 
00262   size_t dot = path.rfind('.');
00263   if (dot == std::string::npos || dot < slash)
00264     return path.substr(slash);
00265   else
00266     return path.substr(slash, dot - slash);
00267 }
00268 
00269 std::string
00270 Path::getSuffix() const {
00271   // Find the last slash
00272   size_t slash = path.rfind('/');
00273   if (slash == std::string::npos)
00274     slash = 0;
00275   else
00276     slash++;
00277 
00278   size_t dot = path.rfind('.');
00279   if (dot == std::string::npos || dot < slash)
00280     return std::string();
00281   else
00282     return path.substr(dot + 1);
00283 }
00284 
00285 bool
00286 Path::exists() const {
00287   DWORD attr = GetFileAttributes(path.c_str());
00288   return attr != INVALID_FILE_ATTRIBUTES;
00289 }
00290 
00291 bool
00292 Path::isDirectory() const {
00293   DWORD attr = GetFileAttributes(path.c_str());
00294   return (attr != INVALID_FILE_ATTRIBUTES) &&
00295          (attr & FILE_ATTRIBUTE_DIRECTORY);
00296 }
00297 
00298 bool
00299 Path::canRead() const {
00300   // FIXME: take security attributes into account.
00301   DWORD attr = GetFileAttributes(path.c_str());
00302   return attr != INVALID_FILE_ATTRIBUTES;
00303 }
00304 
00305 bool
00306 Path::canWrite() const {
00307   // FIXME: take security attributes into account.
00308   DWORD attr = GetFileAttributes(path.c_str());
00309   return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
00310 }
00311 
00312 bool
00313 Path::canExecute() const {
00314   // FIXME: take security attributes into account.
00315   DWORD attr = GetFileAttributes(path.c_str());
00316   return attr != INVALID_FILE_ATTRIBUTES;
00317 }
00318 
00319 std::string
00320 Path::getLast() const {
00321   // Find the last slash
00322   size_t pos = path.rfind('/');
00323 
00324   // Handle the corner cases
00325   if (pos == std::string::npos)
00326     return path;
00327 
00328   // If the last character is a slash, we have a root directory
00329   if (pos == path.length()-1)
00330     return path;
00331 
00332   // Return everything after the last slash
00333   return path.substr(pos+1);
00334 }
00335 
00336 const FileStatus *
00337 PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
00338   if (!fsIsValid || update) {
00339     WIN32_FILE_ATTRIBUTE_DATA fi;
00340     if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
00341       MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
00342                       ": Can't get status: ");
00343       return 0;
00344     }
00345 
00346     status.fileSize = fi.nFileSizeHigh;
00347     status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
00348     status.fileSize += fi.nFileSizeLow;
00349 
00350     status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
00351     status.user = 9999;    // Not applicable to Windows, so...
00352     status.group = 9999;   // Not applicable to Windows, so...
00353 
00354     // FIXME: this is only unique if the file is accessed by the same file path.
00355     // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
00356     // numbers, but the concept doesn't exist in Windows.
00357     status.uniqueID = 0;
00358     for (unsigned i = 0; i < path.length(); ++i)
00359       status.uniqueID += path[i];
00360 
00361     __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
00362     status.modTime.fromWin32Time(ft);
00363 
00364     status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
00365     fsIsValid = true;
00366   }
00367   return &status;
00368 }
00369 
00370 bool Path::makeReadableOnDisk(std::string* ErrMsg) {
00371   // All files are readable on Windows (ignoring security attributes).
00372   return false;
00373 }
00374 
00375 bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
00376   DWORD attr = GetFileAttributes(path.c_str());
00377 
00378   // If it doesn't exist, we're done.
00379   if (attr == INVALID_FILE_ATTRIBUTES)
00380     return false;
00381 
00382   if (attr & FILE_ATTRIBUTE_READONLY) {
00383     if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
00384       MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
00385       return true;
00386     }
00387   }
00388   return false;
00389 }
00390 
00391 bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
00392   // All files are executable on Windows (ignoring security attributes).
00393   return false;
00394 }
00395 
00396 bool
00397 Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
00398   WIN32_FILE_ATTRIBUTE_DATA fi;
00399   if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
00400     MakeErrMsg(ErrMsg, path + ": can't get status of file");
00401     return true;
00402   }
00403     
00404   if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
00405     if (ErrMsg)
00406       *ErrMsg = path + ": not a directory";
00407     return true;
00408   }
00409 
00410   result.clear();
00411   WIN32_FIND_DATA fd;
00412   std::string searchpath = path;
00413   if (path.size() == 0 || searchpath[path.size()-1] == '/')
00414     searchpath += "*";
00415   else
00416     searchpath += "/*";
00417 
00418   HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
00419   if (h == INVALID_HANDLE_VALUE) {
00420     if (GetLastError() == ERROR_FILE_NOT_FOUND)
00421       return true; // not really an error, now is it?
00422     MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
00423     return true;
00424   }
00425 
00426   do {
00427     if (fd.cFileName[0] == '.')
00428       continue;
00429     Path aPath(path);
00430     aPath.appendComponent(&fd.cFileName[0]);
00431     result.insert(aPath);
00432   } while (FindNextFile(h, &fd));
00433 
00434   DWORD err = GetLastError();
00435   FindClose(h);
00436   if (err != ERROR_NO_MORE_FILES) {
00437     SetLastError(err);
00438     MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
00439     return true;
00440   }
00441   return false;
00442 }
00443 
00444 bool
00445 Path::set(const std::string& a_path) {
00446   if (a_path.empty())
00447     return false;
00448   std::string save(path);
00449   path = a_path;
00450   FlipBackSlashes(path);
00451   if (!isValid()) {
00452     path = save;
00453     return false;
00454   }
00455   return true;
00456 }
00457 
00458 bool
00459 Path::appendComponent(const std::string& name) {
00460   if (name.empty())
00461     return false;
00462   std::string save(path);
00463   if (!path.empty()) {
00464     size_t last = path.size() - 1;
00465     if (path[last] != '/')
00466       path += '/';
00467   }
00468   path += name;
00469   if (!isValid()) {
00470     path = save;
00471     return false;
00472   }
00473   return true;
00474 }
00475 
00476 bool
00477 Path::eraseComponent() {
00478   size_t slashpos = path.rfind('/',path.size());
00479   if (slashpos == path.size() - 1 || slashpos == std::string::npos)
00480     return false;
00481   std::string save(path);
00482   path.erase(slashpos);
00483   if (!isValid()) {
00484     path = save;
00485     return false;
00486   }
00487   return true;
00488 }
00489 
00490 bool
00491 Path::appendSuffix(const std::string& suffix) {
00492   std::string save(path);
00493   path.append(".");
00494   path.append(suffix);
00495   if (!isValid()) {
00496     path = save;
00497     return false;
00498   }
00499   return true;
00500 }
00501 
00502 bool
00503 Path::eraseSuffix() {
00504   size_t dotpos = path.rfind('.',path.size());
00505   size_t slashpos = path.rfind('/',path.size());
00506   if (dotpos != std::string::npos) {
00507     if (slashpos == std::string::npos || dotpos > slashpos+1) {
00508       std::string save(path);
00509       path.erase(dotpos, path.size()-dotpos);
00510       if (!isValid()) {
00511         path = save;
00512         return false;
00513       }
00514       return true;
00515     }
00516   }
00517   return false;
00518 }
00519 
00520 inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
00521   if (ErrMsg)
00522     *ErrMsg = std::string(pathname) + ": " + std::string(msg);
00523   return true;
00524 }
00525 
00526 bool
00527 Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
00528   // Get a writeable copy of the path name
00529   size_t len = path.length();
00530   char *pathname = reinterpret_cast<char *>(_alloca(len+2));
00531   path.copy(pathname, len);
00532   pathname[len] = 0;
00533 
00534   // Make sure it ends with a slash.
00535   if (len == 0 || pathname[len - 1] != '/') {
00536     pathname[len] = '/';
00537     pathname[++len] = 0;
00538   }
00539 
00540   // Determine starting point for initial / search.
00541   char *next = pathname;
00542   if (pathname[0] == '/' && pathname[1] == '/') {
00543     // Skip host name.
00544     next = strchr(pathname+2, '/');
00545     if (next == NULL)
00546       return PathMsg(ErrMsg, pathname, "badly formed remote directory");
00547 
00548     // Skip share name.
00549     next = strchr(next+1, '/');
00550     if (next == NULL)
00551       return PathMsg(ErrMsg, pathname,"badly formed remote directory");
00552 
00553     next++;
00554     if (*next == 0)
00555       return PathMsg(ErrMsg, pathname, "badly formed remote directory");
00556 
00557   } else {
00558     if (pathname[1] == ':')
00559       next += 2;    // skip drive letter
00560     if (*next == '/')
00561       next++;       // skip root directory
00562   }
00563 
00564   // If we're supposed to create intermediate directories
00565   if (create_parents) {
00566     // Loop through the directory components until we're done
00567     while (*next) {
00568       next = strchr(next, '/');
00569       *next = 0;
00570       if (!CreateDirectory(pathname, NULL))
00571           return MakeErrMsg(ErrMsg, 
00572             std::string(pathname) + ": Can't create directory: ");
00573       *next++ = '/';
00574     }
00575   } else {
00576     // Drop trailing slash.
00577     pathname[len-1] = 0;
00578     if (!CreateDirectory(pathname, NULL)) {
00579       return MakeErrMsg(ErrMsg, std::string(pathname) + ": Can't create directory: ");
00580     }
00581   }
00582   return false;
00583 }
00584 
00585 bool
00586 Path::createFileOnDisk(std::string* ErrMsg) {
00587   // Create the file
00588   HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
00589                         FILE_ATTRIBUTE_NORMAL, NULL);
00590   if (h == INVALID_HANDLE_VALUE)
00591     return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
00592 
00593   CloseHandle(h);
00594   return false;
00595 }
00596 
00597 bool
00598 Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
00599   WIN32_FILE_ATTRIBUTE_DATA fi;
00600   if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
00601     return true;
00602     
00603   if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
00604     // If it doesn't exist, we're done.
00605     if (!exists())
00606       return false;
00607 
00608     char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
00609     int lastchar = path.length() - 1 ;
00610     path.copy(pathname, lastchar+1);
00611 
00612     // Make path end with '/*'.
00613     if (pathname[lastchar] != '/')
00614       pathname[++lastchar] = '/';
00615     pathname[lastchar+1] = '*';
00616     pathname[lastchar+2] = 0;
00617 
00618     if (remove_contents) {
00619       WIN32_FIND_DATA fd;
00620       HANDLE h = FindFirstFile(pathname, &fd);
00621 
00622       // It's a bad idea to alter the contents of a directory while enumerating
00623       // its contents. So build a list of its contents first, then destroy them.
00624 
00625       if (h != INVALID_HANDLE_VALUE) {
00626         std::vector<Path> list;
00627 
00628         do {
00629           if (strcmp(fd.cFileName, ".") == 0)
00630             continue;
00631           if (strcmp(fd.cFileName, "..") == 0)
00632             continue;
00633 
00634           Path aPath(path);
00635           aPath.appendComponent(&fd.cFileName[0]);
00636           list.push_back(aPath);
00637         } while (FindNextFile(h, &fd));
00638 
00639         DWORD err = GetLastError();
00640         FindClose(h);
00641         if (err != ERROR_NO_MORE_FILES) {
00642           SetLastError(err);
00643           return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
00644         }
00645 
00646         for (std::vector<Path>::iterator I = list.begin(); I != list.end();
00647              ++I) {
00648           Path &aPath = *I;
00649           aPath.eraseFromDisk(true);
00650         }
00651       } else {
00652         if (GetLastError() != ERROR_FILE_NOT_FOUND)
00653           return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
00654       }
00655     }
00656 
00657     pathname[lastchar] = 0;
00658     if (!RemoveDirectory(pathname))
00659       return MakeErrMsg(ErrStr, 
00660         std::string(pathname) + ": Can't destroy directory: ");
00661     return false;
00662   } else {
00663     // Read-only files cannot be deleted on Windows.  Must remove the read-only
00664     // attribute first.
00665     if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
00666       if (!SetFileAttributes(path.c_str(),
00667                              fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
00668         return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
00669     }
00670 
00671     if (!DeleteFile(path.c_str()))
00672       return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
00673     return false;
00674   }
00675 }
00676 
00677 bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
00678   assert(len < 1024 && "Request for magic string too long");
00679   char* buf = (char*) alloca(1 + len);
00680 
00681   HANDLE h = CreateFile(path.c_str(),
00682                         GENERIC_READ,
00683                         FILE_SHARE_READ,
00684                         NULL,
00685                         OPEN_EXISTING,
00686                         FILE_ATTRIBUTE_NORMAL,
00687                         NULL);
00688   if (h == INVALID_HANDLE_VALUE)
00689     return false;
00690 
00691   DWORD nRead = 0;
00692   BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
00693   CloseHandle(h);
00694 
00695   if (!ret || nRead != len)
00696     return false;
00697 
00698   buf[len] = '\0';
00699   Magic = buf;
00700   return true;
00701 }
00702 
00703 bool
00704 Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
00705   if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
00706     return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path 
00707         + "': ");
00708   return false;
00709 }
00710 
00711 bool
00712 Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
00713   // FIXME: should work on directories also.
00714   if (!si.isFile) {
00715     return true;
00716   }
00717   
00718   HANDLE h = CreateFile(path.c_str(),
00719                         FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
00720                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
00721                         NULL,
00722                         OPEN_EXISTING,
00723                         FILE_ATTRIBUTE_NORMAL,
00724                         NULL);
00725   if (h == INVALID_HANDLE_VALUE)
00726     return true;
00727 
00728   BY_HANDLE_FILE_INFORMATION bhfi;
00729   if (!GetFileInformationByHandle(h, &bhfi)) {
00730     DWORD err = GetLastError();
00731     CloseHandle(h);
00732     SetLastError(err);
00733     return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
00734   }
00735 
00736   FILETIME ft;
00737   (uint64_t&)ft = si.modTime.toWin32Time();
00738   BOOL ret = SetFileTime(h, NULL, &ft, &ft);
00739   DWORD err = GetLastError();
00740   CloseHandle(h);
00741   if (!ret) {
00742     SetLastError(err);
00743     return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
00744   }
00745 
00746   // Best we can do with Unix permission bits is to interpret the owner
00747   // writable bit.
00748   if (si.mode & 0200) {
00749     if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
00750       if (!SetFileAttributes(path.c_str(),
00751               bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
00752         return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
00753     }
00754   } else {
00755     if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
00756       if (!SetFileAttributes(path.c_str(),
00757               bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
00758         return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
00759     }
00760   }
00761 
00762   return false;
00763 }
00764 
00765 bool
00766 CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) {
00767   // Can't use CopyFile macro defined in Windows.h because it would mess up the
00768   // above line.  We use the expansion it would have in a non-UNICODE build.
00769   if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
00770     return MakeErrMsg(ErrMsg, "Can't copy '" + Src.toString() +
00771                "' to '" + Dest.toString() + "': ");
00772   return false;
00773 }
00774 
00775 bool
00776 Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
00777   if (reuse_current && !exists())
00778     return false; // File doesn't exist already, just use it!
00779 
00780   // Reserve space for -XXXXXX at the end.
00781   char *FNBuffer = (char*) alloca(path.size()+8);
00782   unsigned offset = path.size();
00783   path.copy(FNBuffer, offset);
00784 
00785   // Find a numeric suffix that isn't used by an existing file.  Assume there
00786   // won't be more than 1 million files with the same prefix.  Probably a safe
00787   // bet.
00788   static unsigned FCounter = 0;
00789   do {
00790     sprintf(FNBuffer+offset, "-%06u", FCounter);
00791     if (++FCounter > 999999)
00792       FCounter = 0;
00793     path = FNBuffer;
00794   } while (exists());
00795   return false;
00796 }
00797 
00798 bool
00799 Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
00800   // Make this into a unique file name
00801   makeUnique(reuse_current, ErrMsg);
00802 
00803   // Now go and create it
00804   HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
00805                         FILE_ATTRIBUTE_NORMAL, NULL);
00806   if (h == INVALID_HANDLE_VALUE)
00807     return MakeErrMsg(ErrMsg, path + ": can't create file");
00808 
00809   CloseHandle(h);
00810   return false;
00811 }
00812 
00813 /// MapInFilePages - Not yet implemented on win32.
00814 const char *Path::MapInFilePages(int FD, uint64_t FileSize) {
00815   return 0;
00816 }
00817 
00818 /// MapInFilePages - Not yet implemented on win32.
00819 void Path::UnMapFilePages(const char *Base, uint64_t FileSize) {
00820   assert(0 && "NOT IMPLEMENTED");
00821 }
00822 
00823 }
00824 }