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