[GLIB] Use GUniquePtr instead of GOwnPtr
[WebKit-https.git] / Source / WebCore / platform / gtk / FileSystemGtk.cpp
1 /*
2  * Copyright (C) 2007, 2009 Holger Hans Peter Freyther
3  * Copyright (C) 2008 Collabora, Ltd.
4  * Copyright (C) 2008 Apple Inc. All rights reserved.
5  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24 #include "FileSystem.h"
25
26 #include "FileMetadata.h"
27 #include "UUID.h"
28 #include <gio/gio.h>
29 #include <glib.h>
30 #include <glib/gstdio.h>
31 #include <wtf/gobject/GOwnPtr.h>
32 #include <wtf/gobject/GRefPtr.h>
33 #include <wtf/gobject/GUniquePtr.h>
34 #include <wtf/gobject/GlibUtilities.h>
35 #include <wtf/text/CString.h>
36 #include <wtf/text/WTFString.h>
37
38 namespace WebCore {
39
40 /* On linux file names are just raw bytes, so also strings that cannot be encoded in any way
41  * are valid file names. This mean that we cannot just store a file name as-is in a String
42  * but we have to escape it.
43  * On Windows the GLib file name encoding is always UTF-8 so we can optimize this case. */
44 String filenameToString(const char* filename)
45 {
46     if (!filename)
47         return String();
48
49 #if OS(WINDOWS)
50     return String::fromUTF8(filename);
51 #else
52     GUniquePtr<gchar> escapedString(g_uri_escape_string(filename, "/:", false));
53     return escapedString.get();
54 #endif
55 }
56
57 CString fileSystemRepresentation(const String& path)
58 {
59 #if OS(WINDOWS)
60     return path.utf8();
61 #else
62     GUniquePtr<gchar> filename(g_uri_unescape_string(path.utf8().data(), 0));
63     return filename.get();
64 #endif
65 }
66
67 // Converts a string to something suitable to be displayed to the user.
68 String filenameForDisplay(const String& string)
69 {
70 #if OS(WINDOWS)
71     return string;
72 #else
73     CString filename = fileSystemRepresentation(string);
74     GUniquePtr<gchar> display(g_filename_to_utf8(filename.data(), 0, 0, 0, 0));
75     if (!display)
76         return string;
77
78     return String::fromUTF8(display.get());
79 #endif
80 }
81
82 bool fileExists(const String& path)
83 {
84     bool result = false;
85     CString filename = fileSystemRepresentation(path);
86
87     if (!filename.isNull())
88         result = g_file_test(filename.data(), G_FILE_TEST_EXISTS);
89
90     return result;
91 }
92
93 bool deleteFile(const String& path)
94 {
95     bool result = false;
96     CString filename = fileSystemRepresentation(path);
97
98     if (!filename.isNull())
99         result = g_remove(filename.data()) == 0;
100
101     return result;
102 }
103
104 bool deleteEmptyDirectory(const String& path)
105 {
106     bool result = false;
107     CString filename = fileSystemRepresentation(path);
108
109     if (!filename.isNull())
110         result = g_rmdir(filename.data()) == 0;
111
112     return result;
113 }
114
115 bool getFileSize(const String& path, long long& resultSize)
116 {
117     CString filename = fileSystemRepresentation(path);
118     if (filename.isNull())
119         return false;
120
121     GStatBuf statResult;
122     gint result = g_stat(filename.data(), &statResult);
123     if (result != 0)
124         return false;
125
126     resultSize = statResult.st_size;
127     return true;
128 }
129
130 bool getFileModificationTime(const String& path, time_t& modifiedTime)
131 {
132     CString filename = fileSystemRepresentation(path);
133     if (filename.isNull())
134         return false;
135
136     GStatBuf statResult;
137     gint result = g_stat(filename.data(), &statResult);
138     if (result != 0)
139         return false;
140
141     modifiedTime = statResult.st_mtime;
142     return true;
143
144 }
145
146 bool getFileMetadata(const String& path, FileMetadata& metadata)
147 {
148     CString filename = fileSystemRepresentation(path);
149     if (filename.isNull())
150         return false;
151
152     struct stat statResult;
153     gint result = g_stat(filename.data(), &statResult);
154     if (result)
155         return false;
156
157     metadata.modificationTime = statResult.st_mtime;
158     metadata.length = statResult.st_size;
159     metadata.type = S_ISDIR(statResult.st_mode) ? FileMetadata::TypeDirectory : FileMetadata::TypeFile;
160     return true;
161
162 }
163
164 String pathByAppendingComponent(const String& path, const String& component)
165 {
166     if (path.endsWith(G_DIR_SEPARATOR_S))
167         return path + component;
168     else
169         return path + G_DIR_SEPARATOR_S + component;
170 }
171
172 bool makeAllDirectories(const String& path)
173 {
174     CString filename = fileSystemRepresentation(path);
175     if (filename.isNull())
176         return false;
177
178     gint result = g_mkdir_with_parents(filename.data(), S_IRWXU);
179
180     return result == 0;
181 }
182
183 String homeDirectoryPath()
184 {
185     return filenameToString(g_get_home_dir());
186 }
187
188 String pathGetFileName(const String& pathName)
189 {
190     if (pathName.isEmpty())
191         return pathName;
192
193     CString tmpFilename = fileSystemRepresentation(pathName);
194     GUniquePtr<gchar> baseName(g_path_get_basename(tmpFilename.data()));
195     return String::fromUTF8(baseName.get());
196 }
197
198 CString applicationDirectoryPath()
199 {
200     CString path = getCurrentExecutablePath();
201     if (!path.isNull())
202         return path;
203
204     // If the above fails, check the PATH env variable.
205     GUniquePtr<char> currentExePath(g_find_program_in_path(g_get_prgname()));
206     if (!currentExePath.get())
207         return CString();
208
209     GUniquePtr<char> dirname(g_path_get_dirname(currentExePath.get()));
210     return dirname.get();
211 }
212
213 CString sharedResourcesPath()
214 {
215     static CString cachedPath;
216     if (!cachedPath.isNull())
217         return cachedPath;
218
219 #if OS(WINDOWS)
220     HMODULE hmodule = 0;
221     GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(sharedResourcesPath), &hmodule);
222
223     GUniquePtr<gchar> runtimeDir(g_win32_get_package_installation_directory_of_module(hmodule));
224     GUniquePtr<gchar> dataPath(g_build_filename(runtimeDir.get(), "share", "webkitgtk-" WEBKITGTK_API_VERSION_STRING, NULL));
225 #else
226     GUniquePtr<gchar> dataPath(g_build_filename(DATA_DIR, "webkitgtk-" WEBKITGTK_API_VERSION_STRING, NULL));
227 #endif
228
229     cachedPath = dataPath.get();
230     return cachedPath;
231 }
232
233 uint64_t getVolumeFreeSizeForPath(const char* path)
234 {
235     GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(path));
236     GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_filesystem_info(file.get(), G_FILE_ATTRIBUTE_FILESYSTEM_FREE, 0, 0));
237     if (!fileInfo)
238         return 0;
239
240     return g_file_info_get_attribute_uint64(fileInfo.get(), G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
241 }
242
243 String directoryName(const String& path)
244 {
245     /* No null checking needed */
246     GUniquePtr<char> dirname(g_path_get_dirname(fileSystemRepresentation(path).data()));
247     return String::fromUTF8(dirname.get());
248 }
249
250 Vector<String> listDirectory(const String& path, const String& filter)
251 {
252     Vector<String> entries;
253
254     CString filename = fileSystemRepresentation(path);
255     GUniquePtr<GDir> dir(g_dir_open(filename.data(), 0, nullptr));
256     if (!dir)
257         return entries;
258
259     GUniquePtr<GPatternSpec> pspec(g_pattern_spec_new((filter.utf8()).data()));
260     while (const char* name = g_dir_read_name(dir.get())) {
261         if (!g_pattern_match_string(pspec.get(), name))
262             continue;
263
264         GUniquePtr<gchar> entry(g_build_filename(filename.data(), name, NULL));
265         entries.append(filenameToString(entry.get()));
266     }
267
268     return entries;
269 }
270
271 String openTemporaryFile(const String& prefix, PlatformFileHandle& handle)
272 {
273     GUniquePtr<gchar> filename(g_strdup_printf("%s%s", prefix.utf8().data(), createCanonicalUUIDString().utf8().data()));
274     GUniquePtr<gchar> tempPath(g_build_filename(g_get_tmp_dir(), filename.get(), NULL));
275     GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(tempPath.get()));
276
277     handle = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
278     if (!isHandleValid(handle))
279         return String();
280     return String::fromUTF8(tempPath.get());
281 }
282
283 PlatformFileHandle openFile(const String& path, FileOpenMode mode)
284 {
285     CString fsRep = fileSystemRepresentation(path);
286     if (fsRep.isNull())
287         return invalidPlatformFileHandle;
288
289     GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(fsRep.data()));
290     GFileIOStream* ioStream = 0;
291     if (mode == OpenForRead)
292         ioStream = g_file_open_readwrite(file.get(), 0, 0);
293     else if (mode == OpenForWrite) {
294         if (g_file_test(fsRep.data(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)))
295             ioStream = g_file_open_readwrite(file.get(), 0, 0);
296         else
297             ioStream = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
298     }
299
300     return ioStream;
301 }
302
303 void closeFile(PlatformFileHandle& handle)
304 {
305     if (!isHandleValid(handle))
306         return;
307
308     g_io_stream_close(G_IO_STREAM(handle), 0, 0);
309     g_object_unref(handle);
310     handle = invalidPlatformFileHandle;
311 }
312
313 long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin)
314 {
315     GSeekType seekType = G_SEEK_SET;
316     switch (origin) {
317     case SeekFromBeginning:
318         seekType = G_SEEK_SET;
319         break;
320     case SeekFromCurrent:
321         seekType = G_SEEK_CUR;
322         break;
323     case SeekFromEnd:
324         seekType = G_SEEK_END;
325         break;
326     default:
327         ASSERT_NOT_REACHED();
328     }
329
330     if (!g_seekable_seek(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))),
331                          offset, seekType, 0, 0))
332         return -1;
333     return g_seekable_tell(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))));
334 }
335
336 int writeToFile(PlatformFileHandle handle, const char* data, int length)
337 {
338     gsize bytesWritten;
339     g_output_stream_write_all(g_io_stream_get_output_stream(G_IO_STREAM(handle)),
340                               data, length, &bytesWritten, 0, 0);
341     return bytesWritten;
342 }
343
344 int readFromFile(PlatformFileHandle handle, char* data, int length)
345 {
346     GOwnPtr<GError> error;
347     do {
348         gssize bytesRead = g_input_stream_read(g_io_stream_get_input_stream(G_IO_STREAM(handle)),
349                                                data, length, 0, &error.outPtr());
350         if (bytesRead >= 0)
351             return bytesRead;
352     } while (error && error->code == G_FILE_ERROR_INTR);
353     return -1;
354 }
355
356 bool unloadModule(PlatformModule module)
357 {
358 #if OS(WINDOWS)
359     return ::FreeLibrary(module);
360 #else
361     return g_module_close(module);
362 #endif
363 }
364 }