diff options
Diffstat (limited to 'Source/WebCore/platform/win/FileSystemWin.cpp')
-rw-r--r-- | Source/WebCore/platform/win/FileSystemWin.cpp | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/Source/WebCore/platform/win/FileSystemWin.cpp b/Source/WebCore/platform/win/FileSystemWin.cpp new file mode 100644 index 000000000..c2b93e438 --- /dev/null +++ b/Source/WebCore/platform/win/FileSystemWin.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FileSystem.h" + +#include "FileMetadata.h" +#include "NotImplemented.h" +#include "PathWalker.h" +#include <wtf/CryptographicallyRandomNumber.h> +#include <wtf/HashMap.h> +#include <wtf/text/CString.h> +#include <wtf/text/StringBuilder.h> + +#include <windows.h> +#include <shlobj.h> +#include <shlwapi.h> + +namespace WebCore { + +static const ULONGLONG kSecondsFromFileTimeToTimet = 11644473600; + +static bool getFindData(String path, WIN32_FIND_DATAW& findData) +{ + HANDLE handle = FindFirstFileW(path.charactersWithNullTermination().data(), &findData); + if (handle == INVALID_HANDLE_VALUE) + return false; + FindClose(handle); + return true; +} + +static bool getFileSizeFromFindData(const WIN32_FIND_DATAW& findData, long long& size) +{ + ULARGE_INTEGER fileSize; + fileSize.HighPart = findData.nFileSizeHigh; + fileSize.LowPart = findData.nFileSizeLow; + + if (fileSize.QuadPart > static_cast<ULONGLONG>(std::numeric_limits<long long>::max())) + return false; + + size = fileSize.QuadPart; + return true; +} + +static bool getFileSizeFromByHandleFileInformationStructure(const BY_HANDLE_FILE_INFORMATION& fileInformation, long long& size) +{ + ULARGE_INTEGER fileSize; + fileSize.HighPart = fileInformation.nFileSizeHigh; + fileSize.LowPart = fileInformation.nFileSizeLow; + + if (fileSize.QuadPart > static_cast<ULONGLONG>(std::numeric_limits<long long>::max())) + return false; + + size = fileSize.QuadPart; + return true; +} + +static void getFileCreationTimeFromFindData(const WIN32_FIND_DATAW& findData, time_t& time) +{ + ULARGE_INTEGER fileTime; + fileTime.HighPart = findData.ftCreationTime.dwHighDateTime; + fileTime.LowPart = findData.ftCreationTime.dwLowDateTime; + + // Information about converting time_t to FileTime is available at http://msdn.microsoft.com/en-us/library/ms724228%28v=vs.85%29.aspx + time = fileTime.QuadPart / 10000000 - kSecondsFromFileTimeToTimet; +} + + +static void getFileModificationTimeFromFindData(const WIN32_FIND_DATAW& findData, time_t& time) +{ + ULARGE_INTEGER fileTime; + fileTime.HighPart = findData.ftLastWriteTime.dwHighDateTime; + fileTime.LowPart = findData.ftLastWriteTime.dwLowDateTime; + + // Information about converting time_t to FileTime is available at http://msdn.microsoft.com/en-us/library/ms724228%28v=vs.85%29.aspx + time = fileTime.QuadPart / 10000000 - kSecondsFromFileTimeToTimet; +} + +bool getFileSize(const String& path, long long& size) +{ + WIN32_FIND_DATAW findData; + if (!getFindData(path, findData)) + return false; + + return getFileSizeFromFindData(findData, size); +} + +bool getFileSize(PlatformFileHandle fileHandle, long long& size) +{ + BY_HANDLE_FILE_INFORMATION fileInformation; + if (!::GetFileInformationByHandle(fileHandle, &fileInformation)) + return false; + + return getFileSizeFromByHandleFileInformationStructure(fileInformation, size); +} + +bool getFileModificationTime(const String& path, time_t& time) +{ + WIN32_FIND_DATAW findData; + if (!getFindData(path, findData)) + return false; + + getFileModificationTimeFromFindData(findData, time); + return true; +} + +bool getFileCreationTime(const String& path, time_t& time) +{ + WIN32_FIND_DATAW findData; + if (!getFindData(path, findData)) + return false; + + getFileCreationTimeFromFindData(findData, time); + return true; +} + +bool getFileMetadata(const String& path, FileMetadata& metadata) +{ + WIN32_FIND_DATAW findData; + if (!getFindData(path, findData)) + return false; + + if (!getFileSizeFromFindData(findData, metadata.length)) + return false; + + time_t modificationTime; + getFileModificationTimeFromFindData(findData, modificationTime); + metadata.modificationTime = modificationTime; + + metadata.type = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FileMetadata::TypeDirectory : FileMetadata::TypeFile; + + return true; +} + +bool fileExists(const String& path) +{ + WIN32_FIND_DATAW findData; + return getFindData(path, findData); +} + +bool deleteFile(const String& path) +{ + String filename = path; + return !!DeleteFileW(filename.charactersWithNullTermination().data()); +} + +bool deleteEmptyDirectory(const String& path) +{ + String filename = path; + return !!RemoveDirectoryW(filename.charactersWithNullTermination().data()); +} + +String pathByAppendingComponent(const String& path, const String& component) +{ + Vector<UChar> buffer(MAX_PATH); + + if (path.length() + 1 > buffer.size()) + return String(); + + StringView(path).getCharactersWithUpconvert(buffer.data()); + buffer[path.length()] = '\0'; + + if (!PathAppendW(buffer.data(), component.charactersWithNullTermination().data())) + return String(); + + buffer.shrink(wcslen(buffer.data())); + + return String::adopt(buffer); +} + +#if !USE(CF) + +CString fileSystemRepresentation(const String& path) +{ + auto upconvertedCharacters = path.upconvertedCharacters(); + + const UChar* characters = upconvertedCharacters; + int size = WideCharToMultiByte(CP_ACP, 0, characters, path.length(), 0, 0, 0, 0) - 1; + + char* buffer; + CString string = CString::newUninitialized(size, buffer); + + WideCharToMultiByte(CP_ACP, 0, characters, path.length(), buffer, size, 0, 0); + + return string; +} + +#endif // !USE(CF) + +bool makeAllDirectories(const String& path) +{ + String fullPath = path; + if (SHCreateDirectoryEx(0, fullPath.charactersWithNullTermination().data(), 0) != ERROR_SUCCESS) { + DWORD error = GetLastError(); + if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) { + LOG_ERROR("Failed to create path %s", path.ascii().data()); + return false; + } + } + return true; +} + +String homeDirectoryPath() +{ + notImplemented(); + return ""; +} + +String pathGetFileName(const String& path) +{ + return String(::PathFindFileName(String(path).charactersWithNullTermination().data())); +} + +String directoryName(const String& path) +{ + String name = path.left(path.length() - pathGetFileName(path).length()); + if (name.characterStartingAt(name.length() - 1) == '\\') { + // Remove any trailing "\". + name.truncate(name.length() - 1); + } + return name; +} + +static String bundleName() +{ + DEPRECATED_DEFINE_STATIC_LOCAL(String, name, (ASCIILiteral("WebKit"))); + +#if USE(CF) + static bool initialized; + + if (!initialized) { + initialized = true; + + if (CFBundleRef bundle = CFBundleGetMainBundle()) + if (CFTypeRef bundleExecutable = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey)) + if (CFGetTypeID(bundleExecutable) == CFStringGetTypeID()) + name = reinterpret_cast<CFStringRef>(bundleExecutable); + } +#endif + + return name; +} + +static String storageDirectory(DWORD pathIdentifier) +{ + Vector<UChar> buffer(MAX_PATH); + if (FAILED(SHGetFolderPathW(0, pathIdentifier | CSIDL_FLAG_CREATE, 0, 0, buffer.data()))) + return String(); + buffer.resize(wcslen(buffer.data())); + String directory = String::adopt(buffer); + + DEPRECATED_DEFINE_STATIC_LOCAL(String, companyNameDirectory, (ASCIILiteral("Apple Computer\\"))); + directory = pathByAppendingComponent(directory, companyNameDirectory + bundleName()); + if (!makeAllDirectories(directory)) + return String(); + + return directory; +} + +static String cachedStorageDirectory(DWORD pathIdentifier) +{ + static HashMap<DWORD, String> directories; + + HashMap<DWORD, String>::iterator it = directories.find(pathIdentifier); + if (it != directories.end()) + return it->value; + + String directory = storageDirectory(pathIdentifier); + directories.add(pathIdentifier, directory); + + return directory; +} + +String openTemporaryFile(const String&, PlatformFileHandle& handle) +{ + handle = INVALID_HANDLE_VALUE; + + wchar_t tempPath[MAX_PATH]; + int tempPathLength = ::GetTempPathW(WTF_ARRAY_LENGTH(tempPath), tempPath); + if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath)) + return String(); + + String proposedPath; + do { + wchar_t tempFile[] = L"XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names) + const int randomPartLength = 8; + cryptographicallyRandomValues(tempFile, randomPartLength * sizeof(wchar_t)); + + // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation. + // don't include both upper and lowercase since Windows file systems are typically not case sensitive. + const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + for (int i = 0; i < randomPartLength; ++i) + tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)]; + + ASSERT(wcslen(tempFile) == WTF_ARRAY_LENGTH(tempFile) - 1); + + proposedPath = pathByAppendingComponent(tempPath, tempFile); + if (proposedPath.isEmpty()) + break; + + // use CREATE_NEW to avoid overwriting an existing file with the same name + handle = ::CreateFileW(proposedPath.charactersWithNullTermination().data(), GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + } while (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS); + + if (!isHandleValid(handle)) + return String(); + + return proposedPath; +} + +PlatformFileHandle openFile(const String& path, FileOpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD creationDisposition = 0; + switch (mode) { + case OpenForRead: + desiredAccess = GENERIC_READ; + creationDisposition = OPEN_EXISTING; + break; + case OpenForWrite: + desiredAccess = GENERIC_WRITE; + creationDisposition = CREATE_ALWAYS; + break; + default: + ASSERT_NOT_REACHED(); + } + + String destination = path; + return CreateFile(destination.charactersWithNullTermination().data(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0); +} + +void closeFile(PlatformFileHandle& handle) +{ + if (isHandleValid(handle)) { + ::CloseHandle(handle); + handle = invalidPlatformFileHandle; + } +} + +long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin) +{ + DWORD moveMethod = FILE_BEGIN; + + if (origin == SeekFromCurrent) + moveMethod = FILE_CURRENT; + else if (origin == SeekFromEnd) + moveMethod = FILE_END; + + LARGE_INTEGER largeOffset; + largeOffset.QuadPart = offset; + + largeOffset.LowPart = SetFilePointer(handle, largeOffset.LowPart, &largeOffset.HighPart, moveMethod); + + if (largeOffset.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) + return -1; + + return largeOffset.QuadPart; +} + +int writeToFile(PlatformFileHandle handle, const char* data, int length) +{ + if (!isHandleValid(handle)) + return -1; + + DWORD bytesWritten; + bool success = WriteFile(handle, data, length, &bytesWritten, 0); + + if (!success) + return -1; + return static_cast<int>(bytesWritten); +} + +int readFromFile(PlatformFileHandle handle, char* data, int length) +{ + if (!isHandleValid(handle)) + return -1; + + DWORD bytesRead; + bool success = ::ReadFile(handle, data, length, &bytesRead, 0); + + if (!success) + return -1; + return static_cast<int>(bytesRead); +} + +bool hardLinkOrCopyFile(const String& source, const String& destination) +{ + return !!::CopyFile(source.charactersWithNullTermination().data(), destination.charactersWithNullTermination().data(), TRUE); +} + +bool unloadModule(PlatformModule module) +{ + return ::FreeLibrary(module); +} + +String localUserSpecificStorageDirectory() +{ + return cachedStorageDirectory(CSIDL_LOCAL_APPDATA); +} + +String roamingUserSpecificStorageDirectory() +{ + return cachedStorageDirectory(CSIDL_APPDATA); +} + +Vector<String> listDirectory(const String& directory, const String& filter) +{ + Vector<String> entries; + + PathWalker walker(directory, filter); + if (!walker.isValid()) + return entries; + + do { + if (walker.data().dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + entries.append(directory + "\\" + reinterpret_cast<const UChar*>(walker.data().cFileName)); + } while (walker.step()); + + return entries; +} + +} // namespace WebCore |