2008-04-24 Adele Peterson <adele@apple.com>
[WebKit-https.git] / WebCore / platform / win / FileSystemWin.cpp
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
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
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
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
68 bool fileExists(const String& path) 
69 {
70     struct _stat64 st;
71     return statFile(path, st);
72 }
73
74 bool deleteFile(const String& path)
75 {
76     String filename = path;
77     return !!DeleteFileW(filename.charactersWithNullTermination());
78 }
79
80 bool deleteEmptyDirectory(const String& path)
81 {
82     String filename = path;
83     return !!RemoveDirectoryW(filename.charactersWithNullTermination());
84 }
85
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
105 CString fileSystemRepresentation(const String&)
106 {
107     return "";
108 }
109
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
123 String homeDirectoryPath()
124 {
125     notImplemented();
126     return "";
127 }
128
129 String pathGetFileName(const String& path)
130 {
131     return String(::PathFindFileName(String(path).charactersWithNullTermination()));
132 }
133
134 static String bundleName()
135 {
136     static bool initialized;
137     static String name = "WebKit";
138
139     if (!initialized) {
140         initialized = true;
141
142         if (CFBundleRef bundle = CFBundleGetMainBundle())
143             if (CFTypeRef bundleExecutable = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey))
144                 if (CFGetTypeID(bundleExecutable) == CFStringGetTypeID())
145                     name = reinterpret_cast<CFStringRef>(bundleExecutable);
146     }
147
148     return name;
149 }
150
151 static String storageDirectory(DWORD pathIdentifier)
152 {
153     Vector<UChar> buffer(MAX_PATH);
154     if (FAILED(SHGetFolderPathW(0, pathIdentifier | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
155         return String();
156     buffer.resize(wcslen(buffer.data()));
157     String directory = String::adopt(buffer);
158
159     static const String companyNameDirectory = "Apple Computer\\";
160     directory = pathByAppendingComponent(directory, companyNameDirectory + bundleName());
161     if (!makeAllDirectories(directory))
162         return String();
163
164     return directory;
165 }
166
167 static String cachedStorageDirectory(DWORD pathIdentifier)
168 {
169     static HashMap<DWORD, String> directories;
170
171     HashMap<DWORD, String>::iterator it = directories.find(pathIdentifier);
172     if (it != directories.end())
173         return it->second;
174
175     String directory = storageDirectory(pathIdentifier);
176     directories.add(pathIdentifier, directory);
177
178     return directory;
179 }
180
181
182 CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
183 {
184     char tempPath[MAX_PATH];
185     int tempPathLength = ::GetTempPathA(_countof(tempPath), tempPath);
186     if (tempPathLength <= 0 || tempPathLength > _countof(tempPath))
187         return 0;
188
189     char tempFile[MAX_PATH];
190     if (::GetTempFileNameA(tempPath, prefix, 0, tempFile) > 0) {
191         HANDLE tempHandle = ::CreateFileA(tempFile, GENERIC_READ | GENERIC_WRITE, 0, 0, 
192             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
193
194         if (isHandleValid(tempHandle)) {
195             handle = tempHandle;
196             return tempFile;
197         }
198     }
199     return 0;
200 }
201
202 void closeFile(PlatformFileHandle& handle)
203 {
204     if (isHandleValid(handle)) {
205         ::CloseHandle(handle);
206         handle = invalidPlatformFileHandle;
207     }
208 }
209
210 int writeToFile(PlatformFileHandle handle, const char* data, int length)
211 {
212     if (!isHandleValid(handle))
213         return -1;
214
215     DWORD bytesWritten;
216     bool success = WriteFile(handle, data, length, &bytesWritten, 0);
217
218     if (!success)
219         return -1;
220     return static_cast<int>(bytesWritten);
221 }
222
223 bool unloadModule(PlatformModule module)
224 {
225     return ::FreeLibrary(module);
226 }
227
228 String localUserSpecificStorageDirectory()
229 {
230     return cachedStorageDirectory(CSIDL_LOCAL_APPDATA);
231 }
232
233 String roamingUserSpecificStorageDirectory()
234 {
235     return cachedStorageDirectory(CSIDL_APPDATA);
236 }
237
238 bool safeCreateFile(const String& path, CFDataRef data)
239 {
240     // Create a temporary file.
241     WCHAR tempDirPath[MAX_PATH];
242     if (!GetTempPathW(ARRAYSIZE(tempDirPath), tempDirPath))
243         return false;
244
245     WCHAR tempPath[MAX_PATH];
246     if (!GetTempFileNameW(tempDirPath, L"WEBKIT", 0, tempPath))
247         return false;
248
249     HANDLE tempFileHandle = CreateFileW(tempPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
250     if (tempFileHandle == INVALID_HANDLE_VALUE)
251         return false;
252
253     // Write the data to this temp file.
254     DWORD written;
255     if (!WriteFile(tempFileHandle, CFDataGetBytePtr(data), static_cast<DWORD>(CFDataGetLength(data)), &written, 0))
256         return false;
257
258     CloseHandle(tempFileHandle);
259
260     // Copy the temp file to the destination file.
261     String destination = path;
262     if (!MoveFileExW(tempPath, destination.charactersWithNullTermination(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
263         return false;
264
265     return true;
266 }
267
268 } // namespace WebCore