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.
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.
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.
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.
24 #include "FileSystem.h"
26 #include "FileMetadata.h"
27 #include "NotImplemented.h"
30 #include <glib/gstdio.h>
32 #include <wtf/glib/GLibUtilities.h>
33 #include <wtf/glib/GRefPtr.h>
34 #include <wtf/glib/GUniquePtr.h>
35 #include <wtf/text/CString.h>
36 #include <wtf/text/WTFString.h>
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 stringFromFileSystemRepresentation(const char* fileSystemRepresentation)
46 if (!fileSystemRepresentation)
50 return String::fromUTF8(fileSystemRepresentation);
52 GUniquePtr<gchar> escapedString(g_uri_escape_string(fileSystemRepresentation, "/:", FALSE));
53 return escapedString.get();
57 static GUniquePtr<char> unescapedFilename(const String& path)
62 return GUniquePtr<char>(g_strdup(path.utf8().data()));
64 return GUniquePtr<char>(g_uri_unescape_string(path.utf8().data(), nullptr));
68 CString fileSystemRepresentation(const String& path)
73 GUniquePtr<gchar> filename = unescapedFilename(path);
74 return filename.get();
78 // Converts a string to something suitable to be displayed to the user.
79 String filenameForDisplay(const String& string)
84 GUniquePtr<gchar> filename = unescapedFilename(string);
88 GUniquePtr<gchar> display(g_filename_to_utf8(filename.get(), -1, nullptr, nullptr, nullptr));
92 return String::fromUTF8(display.get());
96 bool fileExists(const String& path)
98 GUniquePtr<gchar> filename = unescapedFilename(path);
99 return filename ? g_file_test(filename.get(), G_FILE_TEST_EXISTS) : false;
102 bool deleteFile(const String& path)
104 GUniquePtr<gchar> filename = unescapedFilename(path);
105 return filename ? g_remove(filename.get()) != -1 : false;
108 bool deleteEmptyDirectory(const String& path)
110 GUniquePtr<gchar> filename = unescapedFilename(path);
111 return filename ? g_rmdir(filename.get()) != -1 : false;
114 static bool getFileStat(const String& path, GStatBuf* statBuffer)
116 GUniquePtr<gchar> filename = unescapedFilename(path);
120 return g_stat(filename.get(), statBuffer) != -1;
123 bool getFileSize(const String& path, long long& resultSize)
126 if (!getFileStat(path, &statResult))
129 resultSize = statResult.st_size;
133 bool getFileSize(PlatformFileHandle, long long&)
139 bool getFileCreationTime(const String&, time_t&)
141 // FIXME: Is there a way to retrieve file creation time with Gtk on platforms that support it?
145 bool getFileModificationTime(const String& path, time_t& modifiedTime)
148 if (!getFileStat(path, &statResult))
151 modifiedTime = statResult.st_mtime;
155 bool getFileMetadata(const String& path, FileMetadata& metadata)
158 if (!getFileStat(path, &statResult))
161 metadata.modificationTime = statResult.st_mtime;
162 metadata.length = statResult.st_size;
163 metadata.type = S_ISDIR(statResult.st_mode) ? FileMetadata::TypeDirectory : FileMetadata::TypeFile;
167 String pathByAppendingComponent(const String& path, const String& component)
169 if (path.endsWith(G_DIR_SEPARATOR_S))
170 return path + component;
171 return path + G_DIR_SEPARATOR_S + component;
174 bool makeAllDirectories(const String& path)
176 GUniquePtr<gchar> filename = unescapedFilename(path);
177 return filename ? g_mkdir_with_parents(filename.get(), S_IRWXU) != -1 : false;
180 String homeDirectoryPath()
182 return stringFromFileSystemRepresentation(g_get_home_dir());
185 String pathGetFileName(const String& pathName)
187 GUniquePtr<gchar> tmpFilename = unescapedFilename(pathName);
191 GUniquePtr<gchar> baseName(g_path_get_basename(tmpFilename.get()));
192 return String::fromUTF8(baseName.get());
195 CString applicationDirectoryPath()
197 CString path = getCurrentExecutablePath();
201 // If the above fails, check the PATH env variable.
202 GUniquePtr<char> currentExePath(g_find_program_in_path(g_get_prgname()));
203 if (!currentExePath.get())
206 GUniquePtr<char> dirname(g_path_get_dirname(currentExePath.get()));
207 return dirname.get();
210 CString sharedResourcesPath()
212 static CString cachedPath;
213 if (!cachedPath.isNull())
217 GUniquePtr<gchar> dataPath(g_build_filename(DATA_DIR, "wpe", nullptr));
221 GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(sharedResourcesPath), &hmodule);
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));
226 GUniquePtr<gchar> dataPath(g_build_filename(DATA_DIR, "webkitgtk-" WEBKITGTK_API_VERSION_STRING, NULL));
230 cachedPath = dataPath.get();
234 bool getVolumeFreeSpace(const String& path, uint64_t& freeSpace)
236 GUniquePtr<gchar> filename = unescapedFilename(path);
240 GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(filename.get()));
241 GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_filesystem_info(file.get(), G_FILE_ATTRIBUTE_FILESYSTEM_FREE, 0, 0));
245 freeSpace = g_file_info_get_attribute_uint64(fileInfo.get(), G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
249 String directoryName(const String& path)
251 GUniquePtr<gchar> filename = unescapedFilename(path);
255 GUniquePtr<char> dirname(g_path_get_dirname(filename.get()));
256 return String::fromUTF8(dirname.get());
259 Vector<String> listDirectory(const String& path, const String& filter)
261 Vector<String> entries;
263 GUniquePtr<gchar> filename = unescapedFilename(path);
267 GUniquePtr<GDir> dir(g_dir_open(filename.get(), 0, nullptr));
271 GUniquePtr<GPatternSpec> pspec(g_pattern_spec_new((filter.utf8()).data()));
272 while (const char* name = g_dir_read_name(dir.get())) {
273 if (!g_pattern_match_string(pspec.get(), name))
276 GUniquePtr<gchar> entry(g_build_filename(filename.get(), name, nullptr));
277 entries.append(stringFromFileSystemRepresentation(entry.get()));
283 String openTemporaryFile(const String& prefix, PlatformFileHandle& handle)
285 GUniquePtr<gchar> filename(g_strdup_printf("%s%s", prefix.utf8().data(), createCanonicalUUIDString().utf8().data()));
286 GUniquePtr<gchar> tempPath(g_build_filename(g_get_tmp_dir(), filename.get(), NULL));
287 GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(tempPath.get()));
289 handle = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
290 if (!isHandleValid(handle))
292 return String::fromUTF8(tempPath.get());
295 PlatformFileHandle openFile(const String& path, FileOpenMode mode)
297 GUniquePtr<gchar> filename = unescapedFilename(path);
299 return invalidPlatformFileHandle;
301 GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(filename.get()));
302 GFileIOStream* ioStream = 0;
303 if (mode == OpenForRead)
304 ioStream = g_file_open_readwrite(file.get(), 0, 0);
305 else if (mode == OpenForWrite) {
306 if (g_file_test(filename.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)))
307 ioStream = g_file_open_readwrite(file.get(), 0, 0);
309 ioStream = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
315 void closeFile(PlatformFileHandle& handle)
317 if (!isHandleValid(handle))
320 g_io_stream_close(G_IO_STREAM(handle), 0, 0);
321 g_object_unref(handle);
322 handle = invalidPlatformFileHandle;
325 long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin)
327 GSeekType seekType = G_SEEK_SET;
329 case SeekFromBeginning:
330 seekType = G_SEEK_SET;
332 case SeekFromCurrent:
333 seekType = G_SEEK_CUR;
336 seekType = G_SEEK_END;
339 ASSERT_NOT_REACHED();
342 if (!g_seekable_seek(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))),
343 offset, seekType, 0, 0))
347 return g_seekable_tell(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))));
350 int writeToFile(PlatformFileHandle handle, const char* data, int length)
353 g_output_stream_write_all(g_io_stream_get_output_stream(G_IO_STREAM(handle)),
354 data, length, &bytesWritten, 0, 0);
358 int readFromFile(PlatformFileHandle handle, char* data, int length)
360 GUniqueOutPtr<GError> error;
362 gssize bytesRead = g_input_stream_read(g_io_stream_get_input_stream(G_IO_STREAM(handle)),
363 data, length, 0, &error.outPtr());
366 } while (error && error->code == G_FILE_ERROR_INTR);
370 bool moveFile(const String& oldPath, const String& newPath)
372 GUniquePtr<gchar> oldFilename = unescapedFilename(oldPath);
376 GUniquePtr<gchar> newFilename = unescapedFilename(newPath);
380 return g_rename(oldFilename.get(), newFilename.get()) != -1;
383 bool hardLinkOrCopyFile(const String& source, const String& destination)
386 return !!::CopyFile(source.charactersWithNullTermination().data(), destination.charactersWithNullTermination().data(), TRUE);
388 GUniquePtr<gchar> sourceFilename = unescapedFilename(source);
392 GUniquePtr<gchar> destinationFilename = unescapedFilename(destination);
393 if (!destinationFilename)
396 if (!link(sourceFilename.get(), destinationFilename.get()))
399 // Hard link failed. Perform a copy instead.
400 GRefPtr<GFile> sourceFile = adoptGRef(g_file_new_for_path(sourceFilename.get()));
401 GRefPtr<GFile> destinationFile = adoptGRef(g_file_new_for_path(destinationFilename.get()));
402 return g_file_copy(sourceFile.get(), destinationFile.get(), G_FILE_COPY_NONE, nullptr, nullptr, nullptr, nullptr);
406 std::optional<int32_t> getFileDeviceId(const CString& fsFile)
408 GUniquePtr<gchar> filename = unescapedFilename(fsFile.data());
412 GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(filename.get()));
413 GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_filesystem_info(file.get(), G_FILE_ATTRIBUTE_UNIX_DEVICE, nullptr, nullptr));
417 return g_file_info_get_attribute_uint32(fileInfo.get(), G_FILE_ATTRIBUTE_UNIX_DEVICE);