1/* 2 * Copyright (C) 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Collabora, Ltd. All rights reserved. 4 * Copyright (C) 2007-2009 Torch Mobile, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "FileSystem.h" 33 34#include "FileMetadata.h" 35#include "NotImplemented.h" 36#include <wincrypt.h> 37#include <windows.h> 38#include <wtf/text/CString.h> 39#include <wtf/text/WTFString.h> 40 41namespace WebCore { 42 43static size_t reverseFindPathSeparator(const String& path, unsigned start = UINT_MAX) 44{ 45 size_t positionSlash = path.reverseFind('/', start); 46 size_t positionBackslash = path.reverseFind('\\', start); 47 48 if (positionSlash == notFound) 49 return positionBackslash; 50 51 if (positionBackslash == notFound) 52 return positionSlash; 53 54 return std::max(positionSlash, positionBackslash); 55} 56 57static bool getFileInfo(const String& path, BY_HANDLE_FILE_INFORMATION& fileInfo) 58{ 59 String filename = path; 60 HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), GENERIC_READ, FILE_SHARE_READ, 0 61 , OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); 62 63 if (hFile == INVALID_HANDLE_VALUE) 64 return false; 65 66 bool rtn = GetFileInformationByHandle(hFile, &fileInfo) ? true : false; 67 68 CloseHandle(hFile); 69 return rtn; 70} 71 72static void getFileSizeFromFileInfo(const BY_HANDLE_FILE_INFORMATION& fileInfo, long long& size) 73{ 74 ULARGE_INTEGER fileSize; 75 fileSize.LowPart = fileInfo.nFileSizeLow; 76 fileSize.HighPart = fileInfo.nFileSizeHigh; 77 size = fileSize.QuadPart; 78} 79 80static void getFileModificationTimeFromFileInfo(const BY_HANDLE_FILE_INFORMATION& fileInfo, time_t& time) 81{ 82 ULARGE_INTEGER t; 83 memcpy(&t, &fileInfo.ftLastWriteTime, sizeof(t)); 84 time = t.QuadPart * 0.0000001 - 11644473600.0; 85} 86 87bool getFileSize(const String& path, long long& size) 88{ 89 BY_HANDLE_FILE_INFORMATION fileInformation; 90 if (!getFileInfo(path, fileInformation)) 91 return false; 92 93 getFileSizeFromFileInfo(fileInformation, size); 94 return true; 95} 96 97bool getFileModificationTime(const String& path, time_t& time) 98{ 99 BY_HANDLE_FILE_INFORMATION fileInformation; 100 if (!getFileInfo(path, fileInformation)) 101 return false; 102 103 getFileModificationTimeFromFileInfo(fileInformation, time); 104 return true; 105} 106 107bool getFileMetadata(const String& path, FileMetadata& metadata) 108{ 109 BY_HANDLE_FILE_INFORMATION fileInformation; 110 if (!getFileInfo(path, fileInformation)) 111 return false; 112 113 getFileSizeFromFileInfo(fileInformation, metadata.length); 114 115 time_t modificationTime; 116 getFileModificationTimeFromFileInfo(fileInformation, modificationTime); 117 metadata.modificationTime = modificationTime; 118 119 metadata.type = (fileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FileMetadata::TypeDirectory : FileMetadata::TypeFile; 120 121 return true; 122} 123 124bool fileExists(const String& path) 125{ 126 String filename = path; 127 HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE 128 , 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); 129 130 CloseHandle(hFile); 131 132 return hFile != INVALID_HANDLE_VALUE; 133} 134 135bool deleteFile(const String& path) 136{ 137 String filename = path; 138 return !!DeleteFileW(filename.charactersWithNullTermination()); 139} 140 141 142bool deleteEmptyDirectory(const String& path) 143{ 144 String filename = path; 145 return !!RemoveDirectoryW(filename.charactersWithNullTermination()); 146} 147 148String pathByAppendingComponent(const String& path, const String& component) 149{ 150 if (component.isEmpty()) 151 return path; 152 153 Vector<UChar, MAX_PATH> buffer; 154 155 buffer.append(path.characters(), path.length()); 156 157 if (buffer.last() != L'\\' && buffer.last() != L'/' 158 && component[0] != L'\\' && component[0] != L'/') 159 buffer.append(L'\\'); 160 161 buffer.append(component.characters(), component.length()); 162 163 return String(buffer.data(), buffer.size()); 164} 165 166CString fileSystemRepresentation(const String&) 167{ 168 return ""; 169} 170 171bool makeAllDirectories(const String& path) 172{ 173 size_t lastDivPos = reverseFindPathSeparator(path); 174 unsigned endPos = path.length(); 175 if (lastDivPos == endPos - 1) { 176 --endPos; 177 lastDivPos = reverseFindPathSeparator(path, lastDivPos); 178 } 179 180 if (lastDivPos != notFound) { 181 if (!makeAllDirectories(path.substring(0, lastDivPos))) 182 return false; 183 } 184 185 String folder(path.substring(0, endPos)); 186 CreateDirectory(folder.charactersWithNullTermination(), 0); 187 188 DWORD fileAttr = GetFileAttributes(folder.charactersWithNullTermination()); 189 return fileAttr != 0xFFFFFFFF && (fileAttr & FILE_ATTRIBUTE_DIRECTORY); 190} 191 192String homeDirectoryPath() 193{ 194 notImplemented(); 195 return ""; 196} 197 198String pathGetFileName(const String& path) 199{ 200 size_t pos = reverseFindPathSeparator(path); 201 if (pos == notFound) 202 return path; 203 return path.substring(pos + 1); 204} 205 206String directoryName(const String& path) 207{ 208 size_t pos = reverseFindPathSeparator(path); 209 if (pos == notFound) 210 return String(); 211 return path.left(pos); 212} 213 214String openTemporaryFile(const String&, PlatformFileHandle& handle) 215{ 216 handle = INVALID_HANDLE_VALUE; 217 218 wchar_t tempPath[MAX_PATH]; 219 int tempPathLength = ::GetTempPath(WTF_ARRAY_LENGTH(tempPath), tempPath); 220 if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath)) 221 return String(); 222 223 HCRYPTPROV hCryptProv = 0; 224 if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 225 return String(); 226 227 String proposedPath; 228 while (1) { 229 230 wchar_t tempFile[] = L"XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names) 231 const int randomPartLength = 8; 232 if (!CryptGenRandom(hCryptProv, randomPartLength * 2, reinterpret_cast<BYTE*>(tempFile))) 233 break; 234 235 // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation. 236 // don't include both upper and lowercase since Windows file systems are typically not case sensitive. 237 const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 238 for (int i = 0; i < randomPartLength; ++i) 239 tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)]; 240 241 ASSERT(wcslen(tempFile) * 2 == sizeof(tempFile) - 2); 242 243 proposedPath = pathByAppendingComponent(String(tempPath), String(tempFile)); 244 245 // use CREATE_NEW to avoid overwriting an existing file with the same name 246 handle = CreateFile(proposedPath.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); 247 if (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS) 248 continue; 249 250 break; 251 } 252 253 CryptReleaseContext(hCryptProv, 0); 254 255 if (!isHandleValid(handle)) 256 return String(); 257 258 return proposedPath; 259} 260 261PlatformFileHandle openFile(const String& path, FileOpenMode mode) 262{ 263 DWORD desiredAccess = 0; 264 DWORD creationDisposition = 0; 265 switch (mode) { 266 case OpenForRead: 267 desiredAccess = GENERIC_READ; 268 creationDisposition = OPEN_EXISTING; 269 case OpenForWrite: 270 desiredAccess = GENERIC_WRITE; 271 creationDisposition = CREATE_ALWAYS; 272 default: 273 ASSERT_NOT_REACHED(); 274 } 275 276 String destination = path; 277 return CreateFile(destination.charactersWithNullTermination(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0); 278} 279 280void closeFile(PlatformFileHandle& handle) 281{ 282 if (isHandleValid(handle)) { 283 ::CloseHandle(handle); 284 handle = invalidPlatformFileHandle; 285 } 286} 287 288int writeToFile(PlatformFileHandle handle, const char* data, int length) 289{ 290 if (!isHandleValid(handle)) 291 return -1; 292 293 DWORD bytesWritten; 294 bool success = WriteFile(handle, data, length, &bytesWritten, 0); 295 296 if (!success) 297 return -1; 298 return static_cast<int>(bytesWritten); 299} 300 301bool unloadModule(PlatformModule module) 302{ 303 return ::FreeLibrary(module); 304} 305 306String localUserSpecificStorageDirectory() 307{ 308 return String(L"\\"); 309} 310 311String roamingUserSpecificStorageDirectory() 312{ 313 return String(L"\\"); 314} 315 316Vector<String> listDirectory(const String& path, const String& filter) 317{ 318 Vector<String> entries; 319 320 Vector<UChar, 256> pattern; 321 pattern.append(path.characters(), path.length()); 322 if (pattern.last() != L'/' && pattern.last() != L'\\') 323 pattern.append(L'\\'); 324 325 String root(pattern.data(), pattern.size()); 326 pattern.append(filter.characters(), filter.length()); 327 pattern.append(0); 328 329 WIN32_FIND_DATA findData; 330 HANDLE hFind = FindFirstFile(pattern.data(), &findData); 331 if (INVALID_HANDLE_VALUE != hFind) { 332 do { 333 // FIXEME: should we also add the folders? This function 334 // is so far only called by PluginDatabase.cpp to list 335 // all plugins in a folder, where it's not supposed to list sub-folders. 336 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 337 entries.append(root + String(findData.cFileName)); 338 } while (FindNextFile(hFind, &findData)); 339 FindClose(hFind); 340 } 341 342 return entries; 343} 344 345} // namespace WebCore 346