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