Home | History | Annotate | Download | only in gtk
      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. */
     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 
     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.
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    162 String homeDirectoryPath()
    163 {
    164     return filenameToString(g_get_home_dir());
    165 }
    166 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    315 bool unloadModule(PlatformModule module)
    316 {
    317     return g_module_close(module);
    318 }
    319 }
    320