LLVM API Documentation
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 }