2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "FileSystem.h"
33 #include "NotImplemented.h"
34 #include "PathWalker.h"
35 #include "PlatformString.h"
36 #include <wtf/HashMap.h>
37 #include <wtf/text/CString.h>
38 #include <wtf/text/StringConcatenate.h>
47 static bool statFile(String path, struct _stat64& st)
49 ASSERT_ARG(path, !path.isNull());
50 return !_wstat64(path.charactersWithNullTermination(), &st) && (st.st_mode & _S_IFMT) == _S_IFREG;
53 bool getFileSize(const String& path, long long& result)
56 if (!statFile(path, sb))
62 bool getFileModificationTime(const String& path, time_t& result)
65 if (!statFile(path, st))
71 bool fileExists(const String& path)
74 return statFile(path, st);
77 bool deleteFile(const String& path)
79 String filename = path;
80 return !!DeleteFileW(filename.charactersWithNullTermination());
83 bool deleteEmptyDirectory(const String& path)
85 String filename = path;
86 return !!RemoveDirectoryW(filename.charactersWithNullTermination());
89 String pathByAppendingComponent(const String& path, const String& component)
91 Vector<UChar> buffer(MAX_PATH);
93 if (path.length() + 1 > buffer.size())
96 memcpy(buffer.data(), path.characters(), path.length() * sizeof(UChar));
97 buffer[path.length()] = '\0';
99 String componentCopy = component;
100 if (!PathAppendW(buffer.data(), componentCopy.charactersWithNullTermination()))
103 buffer.resize(wcslen(buffer.data()));
105 return String::adopt(buffer);
108 CString fileSystemRepresentation(const String&)
113 bool makeAllDirectories(const String& path)
115 String fullPath = path;
116 if (SHCreateDirectoryEx(0, fullPath.charactersWithNullTermination(), 0) != ERROR_SUCCESS) {
117 DWORD error = GetLastError();
118 if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) {
119 LOG_ERROR("Failed to create path %s", path.ascii().data());
126 String homeDirectoryPath()
132 String pathGetFileName(const String& path)
134 return String(::PathFindFileName(String(path).charactersWithNullTermination()));
137 String directoryName(const String& path)
139 String name = path.left(path.length() - pathGetFileName(path).length());
140 if (name.characterStartingAt(name.length() - 1) == '\\') {
141 // Remove any trailing "\".
142 name.truncate(name.length() - 1);
147 static String bundleName()
149 static bool initialized;
150 static String name = "WebKit";
155 if (CFBundleRef bundle = CFBundleGetMainBundle())
156 if (CFTypeRef bundleExecutable = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey))
157 if (CFGetTypeID(bundleExecutable) == CFStringGetTypeID())
158 name = reinterpret_cast<CFStringRef>(bundleExecutable);
164 static String storageDirectory(DWORD pathIdentifier)
166 Vector<UChar> buffer(MAX_PATH);
167 if (FAILED(SHGetFolderPathW(0, pathIdentifier | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
169 buffer.resize(wcslen(buffer.data()));
170 String directory = String::adopt(buffer);
172 static const String companyNameDirectory = "Apple Computer\\";
173 directory = pathByAppendingComponent(directory, companyNameDirectory + bundleName());
174 if (!makeAllDirectories(directory))
180 static String cachedStorageDirectory(DWORD pathIdentifier)
182 static HashMap<DWORD, String> directories;
184 HashMap<DWORD, String>::iterator it = directories.find(pathIdentifier);
185 if (it != directories.end())
188 String directory = storageDirectory(pathIdentifier);
189 directories.add(pathIdentifier, directory);
194 String openTemporaryFile(const String&, PlatformFileHandle& handle)
196 handle = INVALID_HANDLE_VALUE;
198 char tempPath[MAX_PATH];
199 int tempPathLength = ::GetTempPathA(WTF_ARRAY_LENGTH(tempPath), tempPath);
200 if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath))
203 HCRYPTPROV hCryptProv = 0;
204 if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
207 char proposedPath[MAX_PATH];
209 char tempFile[] = "XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names)
210 const int randomPartLength = 8;
211 if (!CryptGenRandom(hCryptProv, randomPartLength, reinterpret_cast<BYTE*>(tempFile)))
214 // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation.
215 // don't include both upper and lowercase since Windows file systems are typically not case sensitive.
216 const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
217 for (int i = 0; i < randomPartLength; ++i)
218 tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)];
220 ASSERT(strlen(tempFile) == sizeof(tempFile) - 1);
222 if (!PathCombineA(proposedPath, tempPath, tempFile))
225 // use CREATE_NEW to avoid overwriting an existing file with the same name
226 handle = CreateFileA(proposedPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
227 if (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS)
233 CryptReleaseContext(hCryptProv, 0);
235 if (!isHandleValid(handle))
238 return String::fromUTF8(proposedPath);
241 PlatformFileHandle openFile(const String& path, FileOpenMode mode)
243 DWORD desiredAccess = 0;
244 DWORD creationDisposition = 0;
247 desiredAccess = GENERIC_READ;
248 creationDisposition = OPEN_EXISTING;
251 desiredAccess = GENERIC_WRITE;
252 creationDisposition = CREATE_ALWAYS;
255 ASSERT_NOT_REACHED();
258 String destination = path;
259 return CreateFile(destination.charactersWithNullTermination(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
262 void closeFile(PlatformFileHandle& handle)
264 if (isHandleValid(handle)) {
265 ::CloseHandle(handle);
266 handle = invalidPlatformFileHandle;
270 int writeToFile(PlatformFileHandle handle, const char* data, int length)
272 if (!isHandleValid(handle))
276 bool success = WriteFile(handle, data, length, &bytesWritten, 0);
280 return static_cast<int>(bytesWritten);
283 bool unloadModule(PlatformModule module)
285 return ::FreeLibrary(module);
288 String localUserSpecificStorageDirectory()
290 return cachedStorageDirectory(CSIDL_LOCAL_APPDATA);
293 String roamingUserSpecificStorageDirectory()
295 return cachedStorageDirectory(CSIDL_APPDATA);
298 bool safeCreateFile(const String& path, CFDataRef data)
300 // Create a temporary file.
301 WCHAR tempDirPath[MAX_PATH];
302 if (!GetTempPathW(WTF_ARRAY_LENGTH(tempDirPath), tempDirPath))
305 WCHAR tempPath[MAX_PATH];
306 if (!GetTempFileNameW(tempDirPath, L"WEBKIT", 0, tempPath))
309 HANDLE tempFileHandle = CreateFileW(tempPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
310 if (tempFileHandle == INVALID_HANDLE_VALUE)
313 // Write the data to this temp file.
315 if (!WriteFile(tempFileHandle, CFDataGetBytePtr(data), static_cast<DWORD>(CFDataGetLength(data)), &written, 0))
318 CloseHandle(tempFileHandle);
320 // Copy the temp file to the destination file.
321 String destination = path;
322 if (!MoveFileExW(tempPath, destination.charactersWithNullTermination(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
328 Vector<String> listDirectory(const String& directory, const String& filter)
330 Vector<String> entries;
332 PathWalker walker(directory, filter);
333 if (!walker.isValid())
337 if (walker.data().dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
340 entries.append(makeString(directory, "\\", reinterpret_cast<const UChar*>(walker.data().cFileName)));
341 } while (walker.step());
346 } // namespace WebCore