Cleanup: Use exceptionless Range::* methods rather than ignoring exceptions.
[WebKit-https.git] / Source / WebCore / platform / wince / FileSystemWinCE.cpp
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
41 namespace WebCore {
42
43 static 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
57 static 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
72 static 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
80 static 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
87 bool 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
97 bool 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
107 bool 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
124 bool 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
135 bool deleteFile(const String& path)
136 {
137     String filename = path;
138     return !!DeleteFileW(filename.charactersWithNullTermination());
139 }
140
141
142 bool deleteEmptyDirectory(const String& path)
143 {
144     String filename = path;
145     return !!RemoveDirectoryW(filename.charactersWithNullTermination());
146 }
147
148 String 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
166 CString fileSystemRepresentation(const String&)
167 {
168     return "";
169 }
170
171 bool 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
192 String homeDirectoryPath()
193 {
194     notImplemented();
195     return "";
196 }
197
198 String 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
206 String 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
214 String 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
261 PlatformFileHandle 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
280 void closeFile(PlatformFileHandle& handle)
281 {
282     if (isHandleValid(handle)) {
283         ::CloseHandle(handle);
284         handle = invalidPlatformFileHandle;
285     }
286 }
287
288 int 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
301 bool unloadModule(PlatformModule module)
302 {
303     return ::FreeLibrary(module);
304 }
305
306 String localUserSpecificStorageDirectory()
307 {
308     return String(L"\\");
309 }
310
311 String roamingUserSpecificStorageDirectory()
312 {
313     return String(L"\\");
314 }
315
316 Vector<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