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 "NotImplemented.h" 35 #include "PlatformString.h" 36 #include <wincrypt.h> 37 #include <windows.h> 38 #include <wtf/text/CString.h> 39 40 namespace WebCore { 41 42 static size_t reverseFindPathSeparator(const String& path, unsigned start = UINT_MAX) 43 { 44 size_t positionSlash = path.reverseFind('/', start); 45 size_t positionBackslash = path.reverseFind('\\', start); 46 47 if (positionSlash == notFound) 48 return positionBackslash; 49 50 if (positionBackslash == notFound) 51 return positionSlash; 52 53 return std::max(positionSlash, positionBackslash); 54 } 55 56 static bool getFileInfo(const String& path, BY_HANDLE_FILE_INFORMATION& fileInfo) 57 { 58 String filename = path; 59 HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), GENERIC_READ, FILE_SHARE_READ, 0 60 , OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); 61 62 if (hFile == INVALID_HANDLE_VALUE) 63 return false; 64 65 bool rtn = GetFileInformationByHandle(hFile, &fileInfo) ? true : false; 66 67 CloseHandle(hFile); 68 return rtn; 69 } 70 71 bool getFileSize(const String& path, long long& result) 72 { 73 BY_HANDLE_FILE_INFORMATION fileInformation; 74 if (!getFileInfo(path, fileInformation)) 75 return false; 76 77 ULARGE_INTEGER fileSize; 78 fileSize.LowPart = fileInformation.nFileSizeLow; 79 fileSize.HighPart = fileInformation.nFileSizeHigh; 80 81 result = fileSize.QuadPart; 82 83 return true; 84 } 85 86 bool getFileModificationTime(const String& path, time_t& result) 87 { 88 BY_HANDLE_FILE_INFORMATION fileInformation; 89 if (!getFileInfo(path, fileInformation)) 90 return false; 91 92 ULARGE_INTEGER t; 93 memcpy(&t, &fileInformation.ftLastWriteTime, sizeof(t)); 94 95 result = t.QuadPart * 0.0000001 - 11644473600.0; 96 97 return true; 98 } 99 100 bool fileExists(const String& path) 101 { 102 String filename = path; 103 HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE 104 , 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); 105 106 CloseHandle(hFile); 107 108 return hFile != INVALID_HANDLE_VALUE; 109 } 110 111 bool deleteFile(const String& path) 112 { 113 String filename = path; 114 return !!DeleteFileW(filename.charactersWithNullTermination()); 115 } 116 117 118 bool deleteEmptyDirectory(const String& path) 119 { 120 String filename = path; 121 return !!RemoveDirectoryW(filename.charactersWithNullTermination()); 122 } 123 124 String pathByAppendingComponent(const String& path, const String& component) 125 { 126 if (component.isEmpty()) 127 return path; 128 129 Vector<UChar, MAX_PATH> buffer; 130 131 buffer.append(path.characters(), path.length()); 132 133 if (buffer.last() != L'\\' && buffer.last() != L'/' 134 && component[0] != L'\\' && component[0] != L'/') 135 buffer.append(L'\\'); 136 137 buffer.append(component.characters(), component.length()); 138 139 return String(buffer.data(), buffer.size()); 140 } 141 142 CString fileSystemRepresentation(const String&) 143 { 144 return ""; 145 } 146 147 bool makeAllDirectories(const String& path) 148 { 149 size_t lastDivPos = reverseFindPathSeparator(path); 150 unsigned endPos = path.length(); 151 if (lastDivPos == endPos - 1) { 152 --endPos; 153 lastDivPos = reverseFindPathSeparator(path, lastDivPos); 154 } 155 156 if (lastDivPos != notFound) { 157 if (!makeAllDirectories(path.substring(0, lastDivPos))) 158 return false; 159 } 160 161 String folder(path.substring(0, endPos)); 162 CreateDirectory(folder.charactersWithNullTermination(), 0); 163 164 DWORD fileAttr = GetFileAttributes(folder.charactersWithNullTermination()); 165 return fileAttr != 0xFFFFFFFF && (fileAttr & FILE_ATTRIBUTE_DIRECTORY); 166 } 167 168 String homeDirectoryPath() 169 { 170 notImplemented(); 171 return ""; 172 } 173 174 String pathGetFileName(const String& path) 175 { 176 size_t pos = reverseFindPathSeparator(path); 177 if (pos == notFound) 178 return path; 179 return path.substring(pos + 1); 180 } 181 182 String directoryName(const String& path) 183 { 184 size_t pos = reverseFindPathSeparator(path); 185 if (pos == notFound) 186 return String(); 187 return path.left(pos); 188 } 189 190 String openTemporaryFile(const String&, PlatformFileHandle& handle) 191 { 192 handle = INVALID_HANDLE_VALUE; 193 194 wchar_t tempPath[MAX_PATH]; 195 int tempPathLength = ::GetTempPath(WTF_ARRAY_LENGTH(tempPath), tempPath); 196 if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath)) 197 return String(); 198 199 HCRYPTPROV hCryptProv = 0; 200 if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 201 return String(); 202 203 String proposedPath; 204 while (1) { 205 206 wchar_t tempFile[] = L"XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names) 207 const int randomPartLength = 8; 208 if (!CryptGenRandom(hCryptProv, randomPartLength * 2, reinterpret_cast<BYTE*>(tempFile))) 209 break; 210 211 // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation. 212 // don't include both upper and lowercase since Windows file systems are typically not case sensitive. 213 const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 214 for (int i = 0; i < randomPartLength; ++i) 215 tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)]; 216 217 ASSERT(wcslen(tempFile) * 2 == sizeof(tempFile) - 2); 218 219 proposedPath = pathByAppendingComponent(String(tempPath), String(tempFile)); 220 221 // use CREATE_NEW to avoid overwriting an existing file with the same name 222 handle = CreateFile(proposedPath.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); 223 if (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS) 224 continue; 225 226 break; 227 } 228 229 CryptReleaseContext(hCryptProv, 0); 230 231 if (!isHandleValid(handle)) 232 return String(); 233 234 return proposedPath; 235 } 236 237 PlatformFileHandle openFile(const String& path, FileOpenMode mode) 238 { 239 DWORD desiredAccess = 0; 240 DWORD creationDisposition = 0; 241 switch (mode) { 242 case OpenForRead: 243 desiredAccess = GENERIC_READ; 244 creationDisposition = OPEN_EXISTING; 245 case OpenForWrite: 246 desiredAccess = GENERIC_WRITE; 247 creationDisposition = CREATE_ALWAYS; 248 default: 249 ASSERT_NOT_REACHED(); 250 } 251 252 String destination = path; 253 return CreateFile(destination.charactersWithNullTermination(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0); 254 } 255 256 void closeFile(PlatformFileHandle& handle) 257 { 258 if (isHandleValid(handle)) { 259 ::CloseHandle(handle); 260 handle = invalidPlatformFileHandle; 261 } 262 } 263 264 int writeToFile(PlatformFileHandle handle, const char* data, int length) 265 { 266 if (!isHandleValid(handle)) 267 return -1; 268 269 DWORD bytesWritten; 270 bool success = WriteFile(handle, data, length, &bytesWritten, 0); 271 272 if (!success) 273 return -1; 274 return static_cast<int>(bytesWritten); 275 } 276 277 bool unloadModule(PlatformModule module) 278 { 279 return ::FreeLibrary(module); 280 } 281 282 String localUserSpecificStorageDirectory() 283 { 284 return String(L"\\"); 285 } 286 287 String roamingUserSpecificStorageDirectory() 288 { 289 return String(L"\\"); 290 } 291 292 Vector<String> listDirectory(const String& path, const String& filter) 293 { 294 Vector<String> entries; 295 296 Vector<UChar, 256> pattern; 297 pattern.append(path.characters(), path.length()); 298 if (pattern.last() != L'/' && pattern.last() != L'\\') 299 pattern.append(L'\\'); 300 301 String root(pattern.data(), pattern.size()); 302 pattern.append(filter.characters(), filter.length()); 303 pattern.append(0); 304 305 WIN32_FIND_DATA findData; 306 HANDLE hFind = FindFirstFile(pattern.data(), &findData); 307 if (INVALID_HANDLE_VALUE != hFind) { 308 do { 309 // FIXEME: should we also add the folders? This function 310 // is so far only called by PluginDatabase.cpp to list 311 // all plugins in a folder, where it's not supposed to list sub-folders. 312 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 313 entries.append(root + findData.cFileName); 314 } while (FindNextFile(hFind, &findData)); 315 FindClose(hFind); 316 } 317 318 return entries; 319 } 320 321 } // namespace WebCore 322