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 "GOwnPtr.h"
27 #include "PlatformString.h"
28 #include "UUID.h"
29 #include <gio/gio.h>
30 #include <glib.h>
31 #include <glib/gstdio.h>
32 #include <wtf/gobject/GRefPtr.h>
33 #include <wtf/text/CString.h>
34
35 namespace WebCore {
36
37 /* On linux file names are just raw bytes, so also strings that cannot be encoded in any way
38 * are valid file names. This mean that we cannot just store a file name as-is in a String
39 * but we have to escape it.
40 * On Windows the GLib file name encoding is always UTF-8 so we can optimize this case. */
filenameToString(const char * filename)41 String filenameToString(const char* filename)
42 {
43 if (!filename)
44 return String();
45
46 #if OS(WINDOWS)
47 return String::fromUTF8(filename);
48 #else
49 GOwnPtr<gchar> escapedString(g_uri_escape_string(filename, "/:", false));
50 return escapedString.get();
51 #endif
52 }
53
fileSystemRepresentation(const String & path)54 CString fileSystemRepresentation(const String& path)
55 {
56 #if OS(WINDOWS)
57 return path.utf8();
58 #else
59 GOwnPtr<gchar> filename(g_uri_unescape_string(path.utf8().data(), 0));
60 return filename.get();
61 #endif
62 }
63
64 // Converts a string to something suitable to be displayed to the user.
filenameForDisplay(const String & string)65 String filenameForDisplay(const String& string)
66 {
67 #if OS(WINDOWS)
68 return string;
69 #else
70 CString filename = fileSystemRepresentation(string);
71 GOwnPtr<gchar> display(g_filename_to_utf8(filename.data(), 0, 0, 0, 0));
72 if (!display)
73 return string;
74
75 return String::fromUTF8(display.get());
76 #endif
77 }
78
fileExists(const String & path)79 bool fileExists(const String& path)
80 {
81 bool result = false;
82 CString filename = fileSystemRepresentation(path);
83
84 if (!filename.isNull())
85 result = g_file_test(filename.data(), G_FILE_TEST_EXISTS);
86
87 return result;
88 }
89
deleteFile(const String & path)90 bool deleteFile(const String& path)
91 {
92 bool result = false;
93 CString filename = fileSystemRepresentation(path);
94
95 if (!filename.isNull())
96 result = g_remove(filename.data()) == 0;
97
98 return result;
99 }
100
deleteEmptyDirectory(const String & path)101 bool deleteEmptyDirectory(const String& path)
102 {
103 bool result = false;
104 CString filename = fileSystemRepresentation(path);
105
106 if (!filename.isNull())
107 result = g_rmdir(filename.data()) == 0;
108
109 return result;
110 }
111
getFileSize(const String & path,long long & resultSize)112 bool getFileSize(const String& path, long long& resultSize)
113 {
114 CString filename = fileSystemRepresentation(path);
115 if (filename.isNull())
116 return false;
117
118 struct stat statResult;
119 gint result = g_stat(filename.data(), &statResult);
120 if (result != 0)
121 return false;
122
123 resultSize = statResult.st_size;
124 return true;
125 }
126
getFileModificationTime(const String & path,time_t & modifiedTime)127 bool getFileModificationTime(const String& path, time_t& modifiedTime)
128 {
129 CString filename = fileSystemRepresentation(path);
130 if (filename.isNull())
131 return false;
132
133 struct stat statResult;
134 gint result = g_stat(filename.data(), &statResult);
135 if (result != 0)
136 return false;
137
138 modifiedTime = statResult.st_mtime;
139 return true;
140
141 }
142
pathByAppendingComponent(const String & path,const String & component)143 String pathByAppendingComponent(const String& path, const String& component)
144 {
145 if (path.endsWith(G_DIR_SEPARATOR_S))
146 return path + component;
147 else
148 return path + G_DIR_SEPARATOR_S + component;
149 }
150
makeAllDirectories(const String & path)151 bool makeAllDirectories(const String& path)
152 {
153 CString filename = fileSystemRepresentation(path);
154 if (filename.isNull())
155 return false;
156
157 gint result = g_mkdir_with_parents(filename.data(), S_IRWXU);
158
159 return result == 0;
160 }
161
homeDirectoryPath()162 String homeDirectoryPath()
163 {
164 return filenameToString(g_get_home_dir());
165 }
166
pathGetFileName(const String & pathName)167 String pathGetFileName(const String& pathName)
168 {
169 if (pathName.isEmpty())
170 return pathName;
171
172 CString tmpFilename = fileSystemRepresentation(pathName);
173 GOwnPtr<gchar> baseName(g_path_get_basename(tmpFilename.data()));
174 return String::fromUTF8(baseName.get());
175 }
176
applicationDirectoryPath()177 CString applicationDirectoryPath()
178 {
179 #if OS(LINUX)
180 // Handle the /proc filesystem case.
181 char pathFromProc[PATH_MAX] = {0};
182 if (readlink("/proc/self/exe", pathFromProc, sizeof(pathFromProc) - 1) == -1)
183 return CString();
184
185 GOwnPtr<char> dirname(g_path_get_dirname(pathFromProc));
186 return dirname.get();
187 #elif OS(UNIX)
188 // If the above fails, check the PATH env variable.
189 GOwnPtr<char> currentExePath(g_find_program_in_path(g_get_prgname()));
190 if (!currentExePath.get())
191 return CString();
192
193 GOwnPtr<char> dirname(g_path_get_dirname(currentExePath.get()));
194 return dirname.get();
195 #else
196 return CString();
197 #endif
198 }
199
directoryName(const String & path)200 String directoryName(const String& path)
201 {
202 /* No null checking needed */
203 GOwnPtr<char> dirname(g_path_get_dirname(fileSystemRepresentation(path).data()));
204 return String::fromUTF8(dirname.get());
205 }
206
listDirectory(const String & path,const String & filter)207 Vector<String> listDirectory(const String& path, const String& filter)
208 {
209 Vector<String> entries;
210
211 CString filename = fileSystemRepresentation(path);
212 GDir* dir = g_dir_open(filename.data(), 0, 0);
213 if (!dir)
214 return entries;
215
216 GPatternSpec *pspec = g_pattern_spec_new((filter.utf8()).data());
217 while (const char* name = g_dir_read_name(dir)) {
218 if (!g_pattern_match_string(pspec, name))
219 continue;
220
221 GOwnPtr<gchar> entry(g_build_filename(filename.data(), name, NULL));
222 entries.append(filenameToString(entry.get()));
223 }
224 g_pattern_spec_free(pspec);
225 g_dir_close(dir);
226
227 return entries;
228 }
229
openTemporaryFile(const String & prefix,PlatformFileHandle & handle)230 String openTemporaryFile(const String& prefix, PlatformFileHandle& handle)
231 {
232 GOwnPtr<gchar> filename(g_strdup_printf("%s%s", prefix.utf8().data(), createCanonicalUUIDString().utf8().data()));
233 GOwnPtr<gchar> tempPath(g_build_filename(g_get_tmp_dir(), filename.get(), NULL));
234 GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(tempPath.get()));
235
236 handle = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
237 if (!isHandleValid(handle))
238 return String();
239 return String::fromUTF8(tempPath.get());
240 }
241
openFile(const String & path,FileOpenMode mode)242 PlatformFileHandle openFile(const String& path, FileOpenMode mode)
243 {
244 CString fsRep = fileSystemRepresentation(path);
245 if (fsRep.isNull())
246 return invalidPlatformFileHandle;
247
248 GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(fsRep.data()));
249 GFileIOStream* ioStream = 0;
250 if (mode == OpenForRead)
251 ioStream = g_file_open_readwrite(file.get(), 0, 0);
252 else if (mode == OpenForWrite) {
253 if (g_file_test(fsRep.data(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)))
254 ioStream = g_file_open_readwrite(file.get(), 0, 0);
255 else
256 ioStream = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
257 }
258
259 return ioStream;
260 }
261
closeFile(PlatformFileHandle & handle)262 void closeFile(PlatformFileHandle& handle)
263 {
264 if (!isHandleValid(handle))
265 return;
266
267 g_io_stream_close(G_IO_STREAM(handle), 0, 0);
268 g_object_unref(handle);
269 handle = invalidPlatformFileHandle;
270 }
271
seekFile(PlatformFileHandle handle,long long offset,FileSeekOrigin origin)272 long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin)
273 {
274 GSeekType seekType = G_SEEK_SET;
275 switch (origin) {
276 case SeekFromBeginning:
277 seekType = G_SEEK_SET;
278 break;
279 case SeekFromCurrent:
280 seekType = G_SEEK_CUR;
281 break;
282 case SeekFromEnd:
283 seekType = G_SEEK_END;
284 break;
285 default:
286 ASSERT_NOT_REACHED();
287 }
288
289 if (!g_seekable_seek(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))),
290 offset, seekType, 0, 0))
291 return -1;
292 return g_seekable_tell(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))));
293 }
294
writeToFile(PlatformFileHandle handle,const char * data,int length)295 int writeToFile(PlatformFileHandle handle, const char* data, int length)
296 {
297 gsize bytesWritten;
298 g_output_stream_write_all(g_io_stream_get_output_stream(G_IO_STREAM(handle)),
299 data, length, &bytesWritten, 0, 0);
300 return bytesWritten;
301 }
302
readFromFile(PlatformFileHandle handle,char * data,int length)303 int readFromFile(PlatformFileHandle handle, char* data, int length)
304 {
305 GOwnPtr<GError> error;
306 do {
307 gssize bytesRead = g_input_stream_read(g_io_stream_get_input_stream(G_IO_STREAM(handle)),
308 data, length, 0, &error.outPtr());
309 if (bytesRead >= 0)
310 return bytesRead;
311 } while (error && error->code == G_FILE_ERROR_INTR);
312 return -1;
313 }
314
unloadModule(PlatformModule module)315 bool unloadModule(PlatformModule module)
316 {
317 return g_module_close(module);
318 }
319 }
320