/* * Copyright (C) 2007 Apple Inc. All rights reserved. * Copyright (C) 2008 Collabora, Ltd. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. * * 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 Computer, 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 "NotImplemented.h" #include "PlatformString.h" #include #include #include namespace WebCore { static size_t reverseFindPathSeparator(const String& path, unsigned start = UINT_MAX) { size_t positionSlash = path.reverseFind('/', start); size_t positionBackslash = path.reverseFind('\\', start); if (positionSlash == notFound) return positionBackslash; if (positionBackslash == notFound) return positionSlash; return std::max(positionSlash, positionBackslash); } static bool getFileInfo(const String& path, BY_HANDLE_FILE_INFORMATION& fileInfo) { String filename = path; HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), GENERIC_READ, FILE_SHARE_READ, 0 , OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); if (hFile == INVALID_HANDLE_VALUE) return false; bool rtn = GetFileInformationByHandle(hFile, &fileInfo) ? true : false; CloseHandle(hFile); return rtn; } bool getFileSize(const String& path, long long& result) { BY_HANDLE_FILE_INFORMATION fileInformation; if (!getFileInfo(path, fileInformation)) return false; ULARGE_INTEGER fileSize; fileSize.LowPart = fileInformation.nFileSizeLow; fileSize.HighPart = fileInformation.nFileSizeHigh; result = fileSize.QuadPart; return true; } bool getFileModificationTime(const String& path, time_t& result) { BY_HANDLE_FILE_INFORMATION fileInformation; if (!getFileInfo(path, fileInformation)) return false; ULARGE_INTEGER t; memcpy(&t, &fileInformation.ftLastWriteTime, sizeof(t)); result = t.QuadPart * 0.0000001 - 11644473600.0; return true; } bool fileExists(const String& path) { String filename = path; HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE , 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); CloseHandle(hFile); return hFile != INVALID_HANDLE_VALUE; } bool deleteFile(const String& path) { String filename = path; return !!DeleteFileW(filename.charactersWithNullTermination()); } bool deleteEmptyDirectory(const String& path) { String filename = path; return !!RemoveDirectoryW(filename.charactersWithNullTermination()); } String pathByAppendingComponent(const String& path, const String& component) { if (component.isEmpty()) return path; Vector buffer; buffer.append(path.characters(), path.length()); if (buffer.last() != L'\\' && buffer.last() != L'/' && component[0] != L'\\' && component[0] != L'/') buffer.append(L'\\'); buffer.append(component.characters(), component.length()); return String(buffer.data(), buffer.size()); } CString fileSystemRepresentation(const String&) { return ""; } bool makeAllDirectories(const String& path) { size_t lastDivPos = reverseFindPathSeparator(path); unsigned endPos = path.length(); if (lastDivPos == endPos - 1) { --endPos; lastDivPos = reverseFindPathSeparator(path, lastDivPos); } if (lastDivPos != notFound) { if (!makeAllDirectories(path.substring(0, lastDivPos))) return false; } String folder(path.substring(0, endPos)); CreateDirectory(folder.charactersWithNullTermination(), 0); DWORD fileAttr = GetFileAttributes(folder.charactersWithNullTermination()); return fileAttr != 0xFFFFFFFF && (fileAttr & FILE_ATTRIBUTE_DIRECTORY); } String homeDirectoryPath() { notImplemented(); return ""; } String pathGetFileName(const String& path) { size_t pos = reverseFindPathSeparator(path); if (pos == notFound) return path; return path.substring(pos + 1); } String directoryName(const String& path) { size_t pos = reverseFindPathSeparator(path); if (pos == notFound) return String(); return path.left(pos); } String openTemporaryFile(const String&, PlatformFileHandle& handle) { handle = INVALID_HANDLE_VALUE; wchar_t tempPath[MAX_PATH]; int tempPathLength = ::GetTempPath(WTF_ARRAY_LENGTH(tempPath), tempPath); if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath)) return String(); HCRYPTPROV hCryptProv = 0; if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return String(); String proposedPath; while (1) { 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; if (!CryptGenRandom(hCryptProv, randomPartLength * 2, reinterpret_cast(tempFile))) break; // 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) * 2 == sizeof(tempFile) - 2); proposedPath = pathByAppendingComponent(String(tempPath), String(tempFile)); // use CREATE_NEW to avoid overwriting an existing file with the same name handle = CreateFile(proposedPath.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); if (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS) continue; break; } CryptReleaseContext(hCryptProv, 0); 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; case OpenForWrite: desiredAccess = GENERIC_WRITE; creationDisposition = CREATE_ALWAYS; default: ASSERT_NOT_REACHED(); } String destination = path; return CreateFile(destination.charactersWithNullTermination(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0); } void closeFile(PlatformFileHandle& handle) { if (isHandleValid(handle)) { ::CloseHandle(handle); handle = invalidPlatformFileHandle; } } 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(bytesWritten); } bool unloadModule(PlatformModule module) { return ::FreeLibrary(module); } String localUserSpecificStorageDirectory() { return String(L"\\"); } String roamingUserSpecificStorageDirectory() { return String(L"\\"); } Vector listDirectory(const String& path, const String& filter) { Vector entries; Vector pattern; pattern.append(path.characters(), path.length()); if (pattern.last() != L'/' && pattern.last() != L'\\') pattern.append(L'\\'); String root(pattern.data(), pattern.size()); pattern.append(filter.characters(), filter.length()); pattern.append(0); WIN32_FIND_DATA findData; HANDLE hFind = FindFirstFile(pattern.data(), &findData); if (INVALID_HANDLE_VALUE != hFind) { do { // FIXEME: should we also add the folders? This function // is so far only called by PluginDatabase.cpp to list // all plugins in a folder, where it's not supposed to list sub-folders. if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) entries.append(root + findData.cFileName); } while (FindNextFile(hFind, &findData)); FindClose(hFind); } return entries; } } // namespace WebCore