• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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.
17  *
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.
28  */
29 
30 #include "config.h"
31 #include "FileSystem.h"
32 
33 #include "CString.h"
34 #include "NotImplemented.h"
35 #include "PlatformString.h"
36 
37 #include <windows.h>
38 #include <winbase.h>
39 #include <shlobj.h>
40 #include <shlwapi.h>
41 
42 namespace WebCore {
43 
statFile(String path,struct _stat64 & st)44 static bool statFile(String path, struct _stat64& st)
45 {
46     ASSERT_ARG(path, !path.isNull());
47     return !_wstat64(path.charactersWithNullTermination(), &st) && (st.st_mode & _S_IFMT) == _S_IFREG;
48 }
49 
getFileSize(const String & path,long long & result)50 bool getFileSize(const String& path, long long& result)
51 {
52     struct _stat64 sb;
53     if (!statFile(path, sb))
54         return false;
55     result = sb.st_size;
56     return true;
57 }
58 
getFileModificationTime(const String & path,time_t & result)59 bool getFileModificationTime(const String& path, time_t& result)
60 {
61     struct _stat64 st;
62     if (!statFile(path, st))
63         return false;
64     result = st.st_mtime;
65     return true;
66 }
67 
fileExists(const String & path)68 bool fileExists(const String& path)
69 {
70     struct _stat64 st;
71     return statFile(path, st);
72 }
73 
deleteFile(const String & path)74 bool deleteFile(const String& path)
75 {
76     String filename = path;
77     return !!DeleteFileW(filename.charactersWithNullTermination());
78 }
79 
deleteEmptyDirectory(const String & path)80 bool deleteEmptyDirectory(const String& path)
81 {
82     String filename = path;
83     return !!RemoveDirectoryW(filename.charactersWithNullTermination());
84 }
85 
pathByAppendingComponent(const String & path,const String & component)86 String pathByAppendingComponent(const String& path, const String& component)
87 {
88     Vector<UChar> buffer(MAX_PATH);
89 
90     if (path.length() + 1 > buffer.size())
91         return String();
92 
93     memcpy(buffer.data(), path.characters(), path.length() * sizeof(UChar));
94     buffer[path.length()] = '\0';
95 
96     String componentCopy = component;
97     if (!PathAppendW(buffer.data(), componentCopy.charactersWithNullTermination()))
98         return String();
99 
100     buffer.resize(wcslen(buffer.data()));
101 
102     return String::adopt(buffer);
103 }
104 
fileSystemRepresentation(const String &)105 CString fileSystemRepresentation(const String&)
106 {
107     return "";
108 }
109 
makeAllDirectories(const String & path)110 bool makeAllDirectories(const String& path)
111 {
112     String fullPath = path;
113     if (SHCreateDirectoryEx(0, fullPath.charactersWithNullTermination(), 0) != ERROR_SUCCESS) {
114         DWORD error = GetLastError();
115         if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) {
116             LOG_ERROR("Failed to create path %s", path.ascii().data());
117             return false;
118         }
119     }
120     return true;
121 }
122 
homeDirectoryPath()123 String homeDirectoryPath()
124 {
125     notImplemented();
126     return "";
127 }
128 
pathGetFileName(const String & path)129 String pathGetFileName(const String& path)
130 {
131     return String(::PathFindFileName(String(path).charactersWithNullTermination()));
132 }
133 
directoryName(const String & path)134 String directoryName(const String& path)
135 {
136     String fileName = pathGetFileName(path);
137     String dirName = String(path);
138     dirName.truncate(dirName.length() - pathGetFileName(path).length());
139     return dirName;
140 }
141 
bundleName()142 static String bundleName()
143 {
144     static bool initialized;
145     static String name = "WebKit";
146 
147     if (!initialized) {
148         initialized = true;
149 
150         if (CFBundleRef bundle = CFBundleGetMainBundle())
151             if (CFTypeRef bundleExecutable = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey))
152                 if (CFGetTypeID(bundleExecutable) == CFStringGetTypeID())
153                     name = reinterpret_cast<CFStringRef>(bundleExecutable);
154     }
155 
156     return name;
157 }
158 
storageDirectory(DWORD pathIdentifier)159 static String storageDirectory(DWORD pathIdentifier)
160 {
161     Vector<UChar> buffer(MAX_PATH);
162     if (FAILED(SHGetFolderPathW(0, pathIdentifier | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
163         return String();
164     buffer.resize(wcslen(buffer.data()));
165     String directory = String::adopt(buffer);
166 
167     static const String companyNameDirectory = "Apple Computer\\";
168     directory = pathByAppendingComponent(directory, companyNameDirectory + bundleName());
169     if (!makeAllDirectories(directory))
170         return String();
171 
172     return directory;
173 }
174 
cachedStorageDirectory(DWORD pathIdentifier)175 static String cachedStorageDirectory(DWORD pathIdentifier)
176 {
177     static HashMap<DWORD, String> directories;
178 
179     HashMap<DWORD, String>::iterator it = directories.find(pathIdentifier);
180     if (it != directories.end())
181         return it->second;
182 
183     String directory = storageDirectory(pathIdentifier);
184     directories.add(pathIdentifier, directory);
185 
186     return directory;
187 }
188 
openTemporaryFile(const char *,PlatformFileHandle & handle)189 CString openTemporaryFile(const char*, PlatformFileHandle& handle)
190 {
191     handle = INVALID_HANDLE_VALUE;
192 
193     char tempPath[MAX_PATH];
194     int tempPathLength = ::GetTempPathA(_countof(tempPath), tempPath);
195     if (tempPathLength <= 0 || tempPathLength > _countof(tempPath))
196         return CString();
197 
198     HCRYPTPROV hCryptProv = 0;
199     if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
200         return CString();
201 
202     char proposedPath[MAX_PATH];
203     while (1) {
204         char tempFile[] = "XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names)
205         const int randomPartLength = 8;
206         if (!CryptGenRandom(hCryptProv, randomPartLength, reinterpret_cast<BYTE*>(tempFile)))
207             break;
208 
209         // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation.
210         // don't include both upper and lowercase since Windows file systems are typically not case sensitive.
211         const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
212         for (int i = 0; i < randomPartLength; ++i)
213             tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)];
214 
215         ASSERT(strlen(tempFile) == sizeof(tempFile) - 1);
216 
217         if (!PathCombineA(proposedPath, tempPath, tempFile))
218             break;
219 
220         // use CREATE_NEW to avoid overwriting an existing file with the same name
221         handle = CreateFileA(proposedPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
222         if (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS)
223             continue;
224 
225         break;
226     }
227 
228     CryptReleaseContext(hCryptProv, 0);
229 
230     if (!isHandleValid(handle))
231         return CString();
232 
233     return proposedPath;
234 }
235 
closeFile(PlatformFileHandle & handle)236 void closeFile(PlatformFileHandle& handle)
237 {
238     if (isHandleValid(handle)) {
239         ::CloseHandle(handle);
240         handle = invalidPlatformFileHandle;
241     }
242 }
243 
writeToFile(PlatformFileHandle handle,const char * data,int length)244 int writeToFile(PlatformFileHandle handle, const char* data, int length)
245 {
246     if (!isHandleValid(handle))
247         return -1;
248 
249     DWORD bytesWritten;
250     bool success = WriteFile(handle, data, length, &bytesWritten, 0);
251 
252     if (!success)
253         return -1;
254     return static_cast<int>(bytesWritten);
255 }
256 
unloadModule(PlatformModule module)257 bool unloadModule(PlatformModule module)
258 {
259     return ::FreeLibrary(module);
260 }
261 
localUserSpecificStorageDirectory()262 String localUserSpecificStorageDirectory()
263 {
264     return cachedStorageDirectory(CSIDL_LOCAL_APPDATA);
265 }
266 
roamingUserSpecificStorageDirectory()267 String roamingUserSpecificStorageDirectory()
268 {
269     return cachedStorageDirectory(CSIDL_APPDATA);
270 }
271 
safeCreateFile(const String & path,CFDataRef data)272 bool safeCreateFile(const String& path, CFDataRef data)
273 {
274     // Create a temporary file.
275     WCHAR tempDirPath[MAX_PATH];
276     if (!GetTempPathW(ARRAYSIZE(tempDirPath), tempDirPath))
277         return false;
278 
279     WCHAR tempPath[MAX_PATH];
280     if (!GetTempFileNameW(tempDirPath, L"WEBKIT", 0, tempPath))
281         return false;
282 
283     HANDLE tempFileHandle = CreateFileW(tempPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
284     if (tempFileHandle == INVALID_HANDLE_VALUE)
285         return false;
286 
287     // Write the data to this temp file.
288     DWORD written;
289     if (!WriteFile(tempFileHandle, CFDataGetBytePtr(data), static_cast<DWORD>(CFDataGetLength(data)), &written, 0))
290         return false;
291 
292     CloseHandle(tempFileHandle);
293 
294     // Copy the temp file to the destination file.
295     String destination = path;
296     if (!MoveFileExW(tempPath, destination.charactersWithNullTermination(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
297         return false;
298 
299     return true;
300 }
301 
listDirectory(const String & path,const String & filter)302 Vector<String> listDirectory(const String& path, const String& filter)
303 {
304     Vector<String> entries;
305     notImplemented();
306     return entries;
307 }
308 
309 } // namespace WebCore
310