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", unsigned(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_FILE_NOT_FOUND) { 00226 ThrowError("isFile(): " + std::string(path) + ": Can't get status: "); 00227 } 00228 return false; 00229 } 00230 00231 bool 00232 Path::isDirectory() const { 00233 WIN32_FILE_ATTRIBUTE_DATA fi; 00234 BOOL rc = GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi); 00235 if (rc) 00236 return fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; 00237 else if (GetLastError() != ERROR_FILE_NOT_FOUND) 00238 ThrowError("isDirectory(): " + std::string(path) + ": Can't get status: "); 00239 return false; 00240 } 00241 00242 bool 00243 Path::isHidden() const { 00244 WIN32_FILE_ATTRIBUTE_DATA fi; 00245 BOOL rc = GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi); 00246 if (rc) 00247 return fi.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN; 00248 else if (GetLastError() != ERROR_FILE_NOT_FOUND) 00249 ThrowError("isHidden(): " + std::string(path) + ": Can't get status: "); 00250 return false; 00251 } 00252 00253 bool 00254 Path::isRootDirectory() const { 00255 size_t len = path.size(); 00256 return len > 0 && path[len-1] == '/'; 00257 } 00258 00259 std::string 00260 Path::getBasename() const { 00261 // Find the last slash 00262 size_t slash = path.rfind('/'); 00263 if (slash == std::string::npos) 00264 slash = 0; 00265 else 00266 slash++; 00267 00268 size_t dot = path.rfind('.'); 00269 if (dot == std::string::npos || dot < slash) 00270 return path.substr(slash); 00271 else 00272 return path.substr(slash, dot - slash); 00273 } 00274 00275 bool Path::hasMagicNumber(const std::string &Magic) const { 00276 std::string actualMagic; 00277 if (getMagicNumber(actualMagic, Magic.size())) 00278 return Magic == actualMagic; 00279 return false; 00280 } 00281 00282 bool 00283 Path::isBytecodeFile() const { 00284 if (!isFile()) 00285 return false; 00286 std::string actualMagic; 00287 if (!getMagicNumber(actualMagic, 4)) 00288 return false; 00289 return actualMagic == "llvc" || actualMagic == "llvm"; 00290 } 00291 00292 bool 00293 Path::exists() const { 00294 DWORD attr = GetFileAttributes(path.c_str()); 00295 return attr != INVALID_FILE_ATTRIBUTES; 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 void 00337 Path::getStatusInfo(StatusInfo& info) const { 00338 WIN32_FILE_ATTRIBUTE_DATA fi; 00339 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) 00340 ThrowError("getStatusInfo():" + std::string(path) + ": Can't get status: "); 00341 00342 info.fileSize = fi.nFileSizeHigh; 00343 info.fileSize <<= sizeof(fi.nFileSizeHigh)*8; 00344 info.fileSize += fi.nFileSizeLow; 00345 00346 info.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777; 00347 info.user = 9999; // Not applicable to Windows, so... 00348 info.group = 9999; // Not applicable to Windows, so... 00349 00350 __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime); 00351 info.modTime.fromWin32Time(ft); 00352 00353 info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; 00354 } 00355 00356 static bool AddPermissionBits(const std::string& Filename, int bits) { 00357 DWORD attr = GetFileAttributes(Filename.c_str()); 00358 00359 // If it doesn't exist, we're done. 00360 if (attr == INVALID_FILE_ATTRIBUTES) 00361 return false; 00362 00363 // The best we can do to interpret Unix permission bits is to use 00364 // the owner writable bit. 00365 if ((attr & FILE_ATTRIBUTE_READONLY) && (bits & 0200)) { 00366 if (!SetFileAttributes(Filename.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) 00367 ThrowError(Filename + ": SetFileAttributes: "); 00368 } 00369 return true; 00370 } 00371 00372 void Path::makeReadableOnDisk() { 00373 // All files are readable on Windows (ignoring security attributes). 00374 } 00375 00376 void Path::makeWriteableOnDisk() { 00377 DWORD attr = GetFileAttributes(path.c_str()); 00378 00379 // If it doesn't exist, we're done. 00380 if (attr == INVALID_FILE_ATTRIBUTES) 00381 return; 00382 00383 if (attr & FILE_ATTRIBUTE_READONLY) { 00384 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) 00385 ThrowError(std::string(path) + ": Can't make file writable: "); 00386 } 00387 } 00388 00389 void Path::makeExecutableOnDisk() { 00390 // All files are executable on Windows (ignoring security attributes). 00391 } 00392 00393 bool 00394 Path::getDirectoryContents(std::set<Path>& result) const { 00395 if (!isDirectory()) 00396 return false; 00397 00398 result.clear(); 00399 WIN32_FIND_DATA fd; 00400 std::string searchpath = path; 00401 if (path.size() == 0 || searchpath[path.size()-1] == '/') 00402 searchpath += "*"; 00403 else 00404 searchpath += "/*"; 00405 00406 HANDLE h = FindFirstFile(searchpath.c_str(), &fd); 00407 if (h == INVALID_HANDLE_VALUE) { 00408 if (GetLastError() == ERROR_FILE_NOT_FOUND) 00409 return true; // not really an error, now is it? 00410 ThrowError(path + ": Can't read directory: "); 00411 } 00412 00413 do { 00414 if (fd.cFileName[0] == '.') 00415 continue; 00416 Path aPath(path); 00417 aPath.appendComponent(&fd.cFileName[0]); 00418 result.insert(aPath); 00419 } while (FindNextFile(h, &fd)); 00420 00421 DWORD err = GetLastError(); 00422 FindClose(h); 00423 if (err != ERROR_NO_MORE_FILES) { 00424 SetLastError(err); 00425 ThrowError(path + ": Can't read directory: "); 00426 } 00427 return true; 00428 } 00429 00430 bool 00431 Path::set(const std::string& a_path) { 00432 if (a_path.size() == 0) 00433 return false; 00434 std::string save(path); 00435 path = a_path; 00436 FlipBackSlashes(path); 00437 if (!isValid()) { 00438 path = save; 00439 return false; 00440 } 00441 return true; 00442 } 00443 00444 bool 00445 Path::appendComponent(const std::string& name) { 00446 if (name.empty()) 00447 return false; 00448 std::string save(path); 00449 if (!path.empty()) { 00450 size_t last = path.size() - 1; 00451 if (path[last] != '/') 00452 path += '/'; 00453 } 00454 path += name; 00455 if (!isValid()) { 00456 path = save; 00457 return false; 00458 } 00459 return true; 00460 } 00461 00462 bool 00463 Path::eraseComponent() { 00464 size_t slashpos = path.rfind('/',path.size()); 00465 if (slashpos == path.size() - 1 || slashpos == std::string::npos) 00466 return false; 00467 std::string save(path); 00468 path.erase(slashpos); 00469 if (!isValid()) { 00470 path = save; 00471 return false; 00472 } 00473 return true; 00474 } 00475 00476 bool 00477 Path::appendSuffix(const std::string& suffix) { 00478 std::string save(path); 00479 path.append("."); 00480 path.append(suffix); 00481 if (!isValid()) { 00482 path = save; 00483 return false; 00484 } 00485 return true; 00486 } 00487 00488 bool 00489 Path::eraseSuffix() { 00490 size_t dotpos = path.rfind('.',path.size()); 00491 size_t slashpos = path.rfind('/',path.size()); 00492 if (dotpos != std::string::npos) { 00493 if (slashpos == std::string::npos || dotpos > slashpos+1) { 00494 std::string save(path); 00495 path.erase(dotpos, path.size()-dotpos); 00496 if (!isValid()) { 00497 path = save; 00498 return false; 00499 } 00500 return true; 00501 } 00502 } 00503 return false; 00504 } 00505 00506 bool 00507 Path::createDirectoryOnDisk(bool create_parents) { 00508 // Get a writeable copy of the path name 00509 size_t len = path.length(); 00510 char *pathname = reinterpret_cast<char *>(_alloca(len+2)); 00511 path.copy(pathname, len); 00512 pathname[len] = 0; 00513 00514 // Make sure it ends with a slash. 00515 if (len == 0 || pathname[len - 1] != '/') { 00516 pathname[len] = '/'; 00517 pathname[++len] = 0; 00518 } 00519 00520 // Determine starting point for initial / search. 00521 char *next = pathname; 00522 if (pathname[0] == '/' && pathname[1] == '/') { 00523 // Skip host name. 00524 next = strchr(pathname+2, '/'); 00525 if (next == NULL) 00526 throw std::string(pathname) + ": badly formed remote directory"; 00527 // Skip share name. 00528 next = strchr(next+1, '/'); 00529 if (next == NULL) 00530 throw std::string(pathname) + ": badly formed remote directory"; 00531 next++; 00532 if (*next == 0) 00533 throw std::string(pathname) + ": badly formed remote directory"; 00534 } else { 00535 if (pathname[1] == ':') 00536 next += 2; // skip drive letter 00537 if (*next == '/') 00538 next++; // skip root directory 00539 } 00540 00541 // If we're supposed to create intermediate directories 00542 if (create_parents) { 00543 // Loop through the directory components until we're done 00544 while (*next) { 00545 next = strchr(next, '/'); 00546 *next = 0; 00547 if (!CreateDirectory(pathname, NULL)) 00548 ThrowError(std::string(pathname) + ": Can't create directory: "); 00549 *next++ = '/'; 00550 } 00551 } else { 00552 // Drop trailing slash. 00553 pathname[len-1] = 0; 00554 if (!CreateDirectory(pathname, NULL)) { 00555 ThrowError(std::string(pathname) + ": Can't create directory: "); 00556 } 00557 } 00558 return true; 00559 } 00560 00561 bool 00562 Path::createFileOnDisk() { 00563 // Create the file 00564 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, 00565 FILE_ATTRIBUTE_NORMAL, NULL); 00566 if (h == INVALID_HANDLE_VALUE) 00567 ThrowError(path + ": Can't create file: "); 00568 00569 CloseHandle(h); 00570 return true; 00571 } 00572 00573 bool 00574 Path::eraseFromDisk(bool remove_contents) const { 00575 if (isFile()) { 00576 DWORD attr = GetFileAttributes(path.c_str()); 00577 00578 // If it doesn't exist, we're done. 00579 if (attr == INVALID_FILE_ATTRIBUTES) 00580 return true; 00581 00582 // Read-only files cannot be deleted on Windows. Must remove the read-only 00583 // attribute first. 00584 if (attr & FILE_ATTRIBUTE_READONLY) { 00585 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) 00586 ThrowError(path + ": Can't destroy file: "); 00587 } 00588 00589 if (!DeleteFile(path.c_str())) 00590 ThrowError(path + ": Can't destroy file: "); 00591 return true; 00592 } else if (isDirectory()) { 00593 // If it doesn't exist, we're done. 00594 if (!exists()) 00595 return true; 00596 00597 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3)); 00598 int lastchar = path.length() - 1 ; 00599 path.copy(pathname, lastchar+1); 00600 00601 // Make path end with '/*'. 00602 if (pathname[lastchar] != '/') 00603 pathname[++lastchar] = '/'; 00604 pathname[lastchar+1] = '*'; 00605 pathname[lastchar+2] = 0; 00606 00607 if (remove_contents) { 00608 WIN32_FIND_DATA fd; 00609 HANDLE h = FindFirstFile(pathname, &fd); 00610 00611 // It's a bad idea to alter the contents of a directory while enumerating 00612 // its contents. So build a list of its contents first, then destroy them. 00613 00614 if (h != INVALID_HANDLE_VALUE) { 00615 std::vector<Path> list; 00616 00617 do { 00618 if (strcmp(fd.cFileName, ".") == 0) 00619 continue; 00620 if (strcmp(fd.cFileName, "..") == 0) 00621 continue; 00622 00623 Path aPath(path); 00624 aPath.appendComponent(&fd.cFileName[0]); 00625 list.push_back(aPath); 00626 } while (FindNextFile(h, &fd)); 00627 00628 DWORD err = GetLastError(); 00629 FindClose(h); 00630 if (err != ERROR_NO_MORE_FILES) { 00631 SetLastError(err); 00632 ThrowError(path + ": Can't read directory: "); 00633 } 00634 00635 for (std::vector<Path>::iterator I = list.begin(); I != list.end(); 00636 ++I) { 00637 Path &aPath = *I; 00638 aPath.eraseFromDisk(true); 00639 } 00640 } else { 00641 if (GetLastError() != ERROR_FILE_NOT_FOUND) 00642 ThrowError(path + ": Can't read directory: "); 00643 } 00644 } 00645 00646 pathname[lastchar] = 0; 00647 if (!RemoveDirectory(pathname)) 00648 ThrowError(std::string(pathname) + ": Can't destroy directory: "); 00649 return true; 00650 } else { 00651 // It appears the path doesn't exist. 00652 return false; 00653 } 00654 } 00655 00656 bool Path::getMagicNumber(std::string& Magic, unsigned len) const { 00657 if (!isFile()) 00658 return false; 00659 assert(len < 1024 && "Request for magic string too long"); 00660 char* buf = (char*) alloca(1 + len); 00661 00662 HANDLE h = CreateFile(path.c_str(), 00663 GENERIC_READ, 00664 FILE_SHARE_READ, 00665 NULL, 00666 OPEN_EXISTING, 00667 FILE_ATTRIBUTE_NORMAL, 00668 NULL); 00669 if (h == INVALID_HANDLE_VALUE) 00670 return false; 00671 00672 DWORD nRead = 0; 00673 BOOL ret = ReadFile(h, buf, len, &nRead, NULL); 00674 CloseHandle(h); 00675 00676 if (!ret || nRead != len) 00677 return false; 00678 00679 buf[len] = '\0'; 00680 Magic = buf; 00681 return true; 00682 } 00683 00684 bool 00685 Path::renamePathOnDisk(const Path& newName) { 00686 if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING)) 00687 ThrowError("Can't move '" + path + 00688 "' to '" + newName.path + "': "); 00689 return true; 00690 } 00691 00692 bool 00693 Path::setStatusInfoOnDisk(const StatusInfo& si) const { 00694 // FIXME: should work on directories also. 00695 if (!isFile()) return false; 00696 00697 HANDLE h = CreateFile(path.c_str(), 00698 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 00699 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 00700 NULL, 00701 OPEN_EXISTING, 00702 FILE_ATTRIBUTE_NORMAL, 00703 NULL); 00704 if (h == INVALID_HANDLE_VALUE) 00705 return false; 00706 00707 BY_HANDLE_FILE_INFORMATION bhfi; 00708 if (!GetFileInformationByHandle(h, &bhfi)) { 00709 DWORD err = GetLastError(); 00710 CloseHandle(h); 00711 SetLastError(err); 00712 ThrowError(path + ": GetFileInformationByHandle: "); 00713 } 00714 00715 FILETIME ft; 00716 (uint64_t&)ft = si.modTime.toWin32Time(); 00717 BOOL ret = SetFileTime(h, NULL, &ft, &ft); 00718 DWORD err = GetLastError(); 00719 CloseHandle(h); 00720 if (!ret) { 00721 SetLastError(err); 00722 ThrowError(path + ": SetFileTime: "); 00723 } 00724 00725 // Best we can do with Unix permission bits is to interpret the owner 00726 // writable bit. 00727 if (si.mode & 0200) { 00728 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { 00729 if (!SetFileAttributes(path.c_str(), 00730 bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) 00731 ThrowError(path + ": SetFileAttributes: "); 00732 } 00733 } else { 00734 if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { 00735 if (!SetFileAttributes(path.c_str(), 00736 bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) 00737 ThrowError(path + ": SetFileAttributes: "); 00738 } 00739 } 00740 00741 return true; 00742 } 00743 00744 void 00745 CopyFile(const sys::Path &Dest, const sys::Path &Src) { 00746 // Can't use CopyFile macro defined in Windows.h because it would mess up the 00747 // above line. We use the expansion it would have in a non-UNICODE build. 00748 if (!::CopyFileA(Src.c_str(), Dest.c_str(), false)) 00749 ThrowError("Can't copy '" + Src.toString() + 00750 "' to '" + Dest.toString() + "': "); 00751 } 00752 00753 void 00754 Path::makeUnique(bool reuse_current) { 00755 if (reuse_current && !exists()) 00756 return; // File doesn't exist already, just use it! 00757 00758 // Reserve space for -XXXXXX at the end. 00759 char *FNBuffer = (char*) alloca(path.size()+8); 00760 unsigned offset = path.size(); 00761 path.copy(FNBuffer, offset); 00762 00763 // Find a numeric suffix that isn't used by an existing file. Assume there 00764 // won't be more than 1 million files with the same prefix. Probably a safe 00765 // bet. 00766 static unsigned FCounter = 0; 00767 do { 00768 sprintf(FNBuffer+offset, "-%06u", FCounter); 00769 if (++FCounter > 999999) 00770 FCounter = 0; 00771 path = FNBuffer; 00772 } while (exists()); 00773 } 00774 00775 bool 00776 Path::createTemporaryFileOnDisk(bool reuse_current) { 00777 // Make this into a unique file name 00778 makeUnique(reuse_current); 00779 00780 // Now go and create it 00781 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, 00782 FILE_ATTRIBUTE_NORMAL, NULL); 00783 if (h == INVALID_HANDLE_VALUE) 00784 return false; 00785 00786 CloseHandle(h); 00787 return true; 00788 } 00789 00790 } 00791 } 00792 00793