From 51b8d211f65cb227b302a2ef0a943ffca128fc54 Mon Sep 17 00:00:00 2001 From: Jeff Cohen Date: Fri, 31 Dec 2004 19:01:08 +0000 Subject: [PATCH] Mostly cleanup, but also some bug fixes, for win32/Path.cpp git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19202 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/System/Win32/Path.cpp | 119 ++++++++++++++++++++++++++------------ lib/System/Win32/Path.inc | 119 ++++++++++++++++++++++++++------------ 2 files changed, 162 insertions(+), 76 deletions(-) diff --git a/lib/System/Win32/Path.cpp b/lib/System/Win32/Path.cpp index 526dc8dce7c..5fa5a44b7bd 100644 --- a/lib/System/Win32/Path.cpp +++ b/lib/System/Win32/Path.cpp @@ -20,7 +20,6 @@ //===----------------------------------------------------------------------===// #include "Win32.h" -#include #include // We need to undo a macro defined in Windows.h, otherwise we won't compile: @@ -205,23 +204,18 @@ Path::getBasename() const { } bool Path::hasMagicNumber(const std::string &Magic) const { - size_t len = Magic.size(); - char *buf = reinterpret_cast(_alloca(len+1)); - std::ifstream f(path.c_str()); - f.read(buf, len); - buf[len] = '\0'; - return Magic == buf; + std::string actualMagic; + if (getMagicNumber(actualMagic, Magic.size())) + return Magic == actualMagic; + return false; } bool Path::isBytecodeFile() const { - char buffer[ 4]; - buffer[0] = 0; - std::ifstream f(path.c_str()); - f.read(buffer, 4); - if (f.bad()) - ThrowErrno("can't read file signature"); - return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4); + std::string actualMagic; + if (!getMagicNumber(actualMagic, 4)) + return false; + return actualMagic == "llvc" || actualMagic == "llvm"; } bool @@ -357,9 +351,12 @@ Path::getDirectoryContents(std::set& result) const { result.insert(aPath); } while (FindNextFile(h, &fd)); - CloseHandle(h); - if (GetLastError() != ERROR_NO_MORE_FILES) + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); ThrowError(path + ": Can't read directory: "); + } return true; } @@ -539,7 +536,7 @@ Path::createFile() { HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) - ThrowError(std::string(path.c_str()) + ": Can't create file: "); + ThrowError(path + ": Can't create file: "); CloseHandle(h); return true; @@ -560,17 +557,49 @@ Path::destroyDirectory(bool remove_contents) const { pathname[lastchar] = 0; if (remove_contents) { - // Recursively descend the directory to remove its content - // FIXME: The correct way of doing this on Windows isn't pretty... - // but this may work if unix-like utils are present. - std::string cmd("rm -rf "); - cmd += path; - system(cmd.c_str()); - } else { - // Otherwise, try to just remove the one directory - if (!RemoveDirectory(pathname)) - ThrowError(std::string(pathname) + ": Can't destroy directory: "); + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(path.c_str(), &fd); + + // It's a bad idea to alter the contents of a directory while enumerating + // its contents. So build a list of its contents first, then destroy them. + + if (h != INVALID_HANDLE_VALUE) { + std::vector list; + + do { + if (strcmp(fd.cFileName, ".") == 0) + continue; + if (strcmp(fd.cFileName, "..") == 0) + continue; + + Path aPath(path + &fd.cFileName[0]); + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + aPath.path += "/"; + list.push_back(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + ThrowError(path + ": Can't read directory: "); + } + + for (std::vector::iterator I = list.begin(); I != list.end(); ++I) { + Path &aPath = *I; + if (aPath.isDirectory()) + aPath.destroyDirectory(true); + else + aPath.destroyFile(); + } + } else { + if (GetLastError() != ERROR_NO_MORE_FILES) + ThrowError(path + ": Can't read directory: "); + } } + + if (!RemoveDirectory(pathname)) + ThrowError(std::string(pathname) + ": Can't destroy directory: "); return true; } @@ -588,11 +617,11 @@ Path::destroyFile() const { // attribute first. if (attr & FILE_ATTRIBUTE_READONLY) { if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) - ThrowError(std::string(path.c_str()) + ": Can't destroy file: "); + ThrowError(path + ": Can't destroy file: "); } if (!DeleteFile(path.c_str())) - ThrowError(std::string(path.c_str()) + ": Can't destroy file: "); + ThrowError(path + ": Can't destroy file: "); return true; } @@ -601,15 +630,24 @@ bool Path::getMagicNumber(std::string& Magic, unsigned len) const { return false; assert(len < 1024 && "Request for magic string too long"); char* buf = (char*) alloca(1 + len); - std::ofstream ofs(path.c_str(),std::ofstream::in); - if (!ofs.is_open()) + + HANDLE h = CreateFile(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) return false; - std::ifstream ifs(path.c_str()); - if (!ifs.is_open()) + + DWORD nRead = 0; + BOOL ret = ReadFile(h, buf, len, &nRead, NULL); + CloseHandle(h); + + if (!ret || nRead != len) return false; - ifs.read(buf, len); - ofs.close(); - ifs.close(); + buf[len] = '\0'; Magic = buf; return true; @@ -640,16 +678,21 @@ Path::setStatusInfo(const StatusInfo& si) const { BY_HANDLE_FILE_INFORMATION bhfi; if (!GetFileInformationByHandle(h, &bhfi)) { + DWORD err = GetLastError(); CloseHandle(h); + SetLastError(err); ThrowError(path + ": GetFileInformationByHandle: "); } FILETIME ft; (uint64_t&)ft = si.modTime.toWin32Time(); BOOL ret = SetFileTime(h, NULL, &ft, &ft); + DWORD err = GetLastError(); CloseHandle(h); - if (!ret) + if (!ret) { + SetLastError(err); ThrowError(path + ": SetFileTime: "); + } // Best we can do with Unix permission bits is to interpret the owner // writable bit. @@ -690,7 +733,7 @@ Path::makeUnique(bool reuse_current) { char newName[MAX_PATH + 1]; if (!GetTempFileName(dir.c_str(), fname.c_str(), 0, newName)) - ThrowError("Cannot make unique filename for '" + path + "'"); + ThrowError("Cannot make unique filename for '" + path + "': "); path = newName; } diff --git a/lib/System/Win32/Path.inc b/lib/System/Win32/Path.inc index 526dc8dce7c..5fa5a44b7bd 100644 --- a/lib/System/Win32/Path.inc +++ b/lib/System/Win32/Path.inc @@ -20,7 +20,6 @@ //===----------------------------------------------------------------------===// #include "Win32.h" -#include #include // We need to undo a macro defined in Windows.h, otherwise we won't compile: @@ -205,23 +204,18 @@ Path::getBasename() const { } bool Path::hasMagicNumber(const std::string &Magic) const { - size_t len = Magic.size(); - char *buf = reinterpret_cast(_alloca(len+1)); - std::ifstream f(path.c_str()); - f.read(buf, len); - buf[len] = '\0'; - return Magic == buf; + std::string actualMagic; + if (getMagicNumber(actualMagic, Magic.size())) + return Magic == actualMagic; + return false; } bool Path::isBytecodeFile() const { - char buffer[ 4]; - buffer[0] = 0; - std::ifstream f(path.c_str()); - f.read(buffer, 4); - if (f.bad()) - ThrowErrno("can't read file signature"); - return 0 == memcmp(buffer,"llvc",4) || 0 == memcmp(buffer,"llvm",4); + std::string actualMagic; + if (!getMagicNumber(actualMagic, 4)) + return false; + return actualMagic == "llvc" || actualMagic == "llvm"; } bool @@ -357,9 +351,12 @@ Path::getDirectoryContents(std::set& result) const { result.insert(aPath); } while (FindNextFile(h, &fd)); - CloseHandle(h); - if (GetLastError() != ERROR_NO_MORE_FILES) + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); ThrowError(path + ": Can't read directory: "); + } return true; } @@ -539,7 +536,7 @@ Path::createFile() { HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) - ThrowError(std::string(path.c_str()) + ": Can't create file: "); + ThrowError(path + ": Can't create file: "); CloseHandle(h); return true; @@ -560,17 +557,49 @@ Path::destroyDirectory(bool remove_contents) const { pathname[lastchar] = 0; if (remove_contents) { - // Recursively descend the directory to remove its content - // FIXME: The correct way of doing this on Windows isn't pretty... - // but this may work if unix-like utils are present. - std::string cmd("rm -rf "); - cmd += path; - system(cmd.c_str()); - } else { - // Otherwise, try to just remove the one directory - if (!RemoveDirectory(pathname)) - ThrowError(std::string(pathname) + ": Can't destroy directory: "); + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(path.c_str(), &fd); + + // It's a bad idea to alter the contents of a directory while enumerating + // its contents. So build a list of its contents first, then destroy them. + + if (h != INVALID_HANDLE_VALUE) { + std::vector list; + + do { + if (strcmp(fd.cFileName, ".") == 0) + continue; + if (strcmp(fd.cFileName, "..") == 0) + continue; + + Path aPath(path + &fd.cFileName[0]); + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + aPath.path += "/"; + list.push_back(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + ThrowError(path + ": Can't read directory: "); + } + + for (std::vector::iterator I = list.begin(); I != list.end(); ++I) { + Path &aPath = *I; + if (aPath.isDirectory()) + aPath.destroyDirectory(true); + else + aPath.destroyFile(); + } + } else { + if (GetLastError() != ERROR_NO_MORE_FILES) + ThrowError(path + ": Can't read directory: "); + } } + + if (!RemoveDirectory(pathname)) + ThrowError(std::string(pathname) + ": Can't destroy directory: "); return true; } @@ -588,11 +617,11 @@ Path::destroyFile() const { // attribute first. if (attr & FILE_ATTRIBUTE_READONLY) { if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) - ThrowError(std::string(path.c_str()) + ": Can't destroy file: "); + ThrowError(path + ": Can't destroy file: "); } if (!DeleteFile(path.c_str())) - ThrowError(std::string(path.c_str()) + ": Can't destroy file: "); + ThrowError(path + ": Can't destroy file: "); return true; } @@ -601,15 +630,24 @@ bool Path::getMagicNumber(std::string& Magic, unsigned len) const { return false; assert(len < 1024 && "Request for magic string too long"); char* buf = (char*) alloca(1 + len); - std::ofstream ofs(path.c_str(),std::ofstream::in); - if (!ofs.is_open()) + + HANDLE h = CreateFile(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) return false; - std::ifstream ifs(path.c_str()); - if (!ifs.is_open()) + + DWORD nRead = 0; + BOOL ret = ReadFile(h, buf, len, &nRead, NULL); + CloseHandle(h); + + if (!ret || nRead != len) return false; - ifs.read(buf, len); - ofs.close(); - ifs.close(); + buf[len] = '\0'; Magic = buf; return true; @@ -640,16 +678,21 @@ Path::setStatusInfo(const StatusInfo& si) const { BY_HANDLE_FILE_INFORMATION bhfi; if (!GetFileInformationByHandle(h, &bhfi)) { + DWORD err = GetLastError(); CloseHandle(h); + SetLastError(err); ThrowError(path + ": GetFileInformationByHandle: "); } FILETIME ft; (uint64_t&)ft = si.modTime.toWin32Time(); BOOL ret = SetFileTime(h, NULL, &ft, &ft); + DWORD err = GetLastError(); CloseHandle(h); - if (!ret) + if (!ret) { + SetLastError(err); ThrowError(path + ": SetFileTime: "); + } // Best we can do with Unix permission bits is to interpret the owner // writable bit. @@ -690,7 +733,7 @@ Path::makeUnique(bool reuse_current) { char newName[MAX_PATH + 1]; if (!GetTempFileName(dir.c_str(), fname.c_str(), 0, newName)) - ThrowError("Cannot make unique filename for '" + path + "'"); + ThrowError("Cannot make unique filename for '" + path + "': "); path = newName; }