• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
reverseFindPathSeparator(const String & path,unsigned start=UINT_MAX)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 
getFileInfo(const String & path,BY_HANDLE_FILE_INFORMATION & fileInfo)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 
getFileSize(const String & path,long long & result)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 
getFileModificationTime(const String & path,time_t & result)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 
fileExists(const String & path)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 
deleteFile(const String & path)111 bool deleteFile(const String& path)
112 {
113     String filename = path;
114     return !!DeleteFileW(filename.charactersWithNullTermination());
115 }
116 
117 
deleteEmptyDirectory(const String & path)118 bool deleteEmptyDirectory(const String& path)
119 {
120     String filename = path;
121     return !!RemoveDirectoryW(filename.charactersWithNullTermination());
122 }
123 
pathByAppendingComponent(const String & path,const String & component)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 
fileSystemRepresentation(const String &)142 CString fileSystemRepresentation(const String&)
143 {
144     return "";
145 }
146 
makeAllDirectories(const String & path)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 
homeDirectoryPath()168 String homeDirectoryPath()
169 {
170     notImplemented();
171     return "";
172 }
173 
pathGetFileName(const String & path)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 
directoryName(const String & path)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 
openTemporaryFile(const String &,PlatformFileHandle & handle)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 
openFile(const String & path,FileOpenMode mode)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 
closeFile(PlatformFileHandle & handle)256 void closeFile(PlatformFileHandle& handle)
257 {
258     if (isHandleValid(handle)) {
259         ::CloseHandle(handle);
260         handle = invalidPlatformFileHandle;
261     }
262 }
263 
writeToFile(PlatformFileHandle handle,const char * data,int length)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 
unloadModule(PlatformModule module)277 bool unloadModule(PlatformModule module)
278 {
279     return ::FreeLibrary(module);
280 }
281 
localUserSpecificStorageDirectory()282 String localUserSpecificStorageDirectory()
283 {
284     return String(L"\\");
285 }
286 
roamingUserSpecificStorageDirectory()287 String roamingUserSpecificStorageDirectory()
288 {
289     return String(L"\\");
290 }
291 
listDirectory(const String & path,const String & filter)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