From 70438138096a47b2505ac55634cd94947ce378b6 Mon Sep 17 00:00:00 2001 From: Perberos Date: Wed, 9 Nov 2011 22:53:33 -0300 Subject: initial --- src/file-utils.c | 1395 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1395 insertions(+) create mode 100644 src/file-utils.c (limited to 'src/file-utils.c') diff --git a/src/file-utils.c b/src/file-utils.c new file mode 100644 index 0000000..9c3bff5 --- /dev/null +++ b/src/file-utils.c @@ -0,0 +1,1395 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * File-Roller + * + * Copyright (C) 2001, 2003 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "file-utils.h" +#include "glib-utils.h" +#include "main.h" + + +#ifndef HAVE_MKDTEMP +#include "mkdtemp.h" +#endif + +#define BUF_SIZE 4096 +#define FILE_PREFIX "file://" +#define FILE_PREFIX_L 7 +#define SPECIAL_DIR(x) ((strcmp ((x), "..") == 0) || (strcmp ((x), ".") == 0)) + + +gboolean +uri_exists (const char *uri) +{ + GFile *file; + gboolean exists; + + if (uri == NULL) + return FALSE; + + file = g_file_new_for_uri (uri); + exists = g_file_query_exists (file, NULL); + g_object_unref (file); + + return exists; +} + + +static gboolean +uri_is_filetype (const char *uri, + GFileType file_type) +{ + gboolean result = FALSE; + GFile *file; + GFileInfo *info; + GError *error = NULL; + + file = g_file_new_for_uri (uri); + + if (! g_file_query_exists (file, NULL)) { + g_object_unref (file); + return FALSE; + } + + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error); + if (error == NULL) { + result = (g_file_info_get_file_type (info) == file_type); + } + else { + g_warning ("Failed to get file type for uri %s: %s", uri, error->message); + g_error_free (error); + } + + g_object_unref (info); + g_object_unref (file); + + return result; +} + + +gboolean +uri_is_file (const char *uri) +{ + return uri_is_filetype (uri, G_FILE_TYPE_REGULAR); +} + + +gboolean +uri_is_dir (const char *uri) +{ + return uri_is_filetype (uri, G_FILE_TYPE_DIRECTORY); +} + + +gboolean +path_is_dir (const char *path) +{ + char *uri; + gboolean result; + + uri = g_filename_to_uri (path, NULL, NULL); + result = uri_is_dir (uri); + g_free (uri); + + return result; +} + +gboolean +uri_is_local (const char *uri) +{ + return strncmp (uri, "file://", 7) == 0; +} + + +gboolean +dir_is_empty (const char *uri) +{ + GFile *file; + GFileEnumerator *file_enum; + GFileInfo *info; + GError *error = NULL; + int n = 0; + + file = g_file_new_for_uri (uri); + + if (! g_file_query_exists (file, NULL)) { + g_object_unref (file); + return TRUE; + } + + file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error); + if (error != NULL) { + g_warning ("Failed to enumerate children of %s: %s", uri, error->message); + g_error_free (error); + g_object_unref (file_enum); + g_object_unref (file); + return TRUE; + } + + while ((n == 0) && ((info = g_file_enumerator_next_file (file_enum, NULL, &error)) != NULL)) { + if (error != NULL) { + g_warning ("Encountered error while enumerating children of %s (ignoring): %s", uri, error->message); + g_error_free (error); + } + else if (! SPECIAL_DIR (g_file_info_get_name (info))) + n++; + g_object_unref (info); + } + + g_object_unref (file); + g_object_unref (file_enum); + + return (n == 0); +} + + +gboolean +dir_contains_one_object (const char *uri) +{ + GFile *file; + GFileEnumerator *file_enum; + GFileInfo *info; + GError *err = NULL; + int n = 0; + + file = g_file_new_for_uri (uri); + + if (! g_file_query_exists (file, NULL)) { + g_object_unref (file); + return FALSE; + } + + file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &err); + if (err != NULL) { + g_warning ("Failed to enumerate children of %s: %s", uri, err->message); + g_error_free (err); + g_object_unref (file_enum); + g_object_unref (file); + return FALSE; + } + + while ((info = g_file_enumerator_next_file (file_enum, NULL, &err)) != NULL) { + const char *name; + + if (err != NULL) { + g_warning ("Encountered error while enumerating children of %s, ignoring: %s", uri, err->message); + g_error_free (err); + g_object_unref (info); + continue; + } + + name = g_file_info_get_name (info); + if (strcmp (name, ".") == 0 || strcmp (name, "..") == 0) { + g_object_unref (info); + continue; + } + + g_object_unref (info); + + if (++n > 1) + break; + } + + g_object_unref (file); + g_object_unref (file_enum); + + return (n == 1); +} + + +char * +get_dir_content_if_unique (const char *uri) +{ + GFile *file; + GFileEnumerator *file_enum; + GFileInfo *info; + GError *err = NULL; + char *content_uri = NULL; + + file = g_file_new_for_uri (uri); + + if (! g_file_query_exists (file, NULL)) { + g_object_unref (file); + return NULL; + } + + file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &err); + if (err != NULL) { + g_warning ("Failed to enumerate children of %s: %s", uri, err->message); + g_error_free (err); + return NULL; + } + + while ((info = g_file_enumerator_next_file (file_enum, NULL, &err)) != NULL) { + const char *name; + + if (err != NULL) { + g_warning ("Failed to get info while enumerating children: %s", err->message); + g_clear_error (&err); + g_object_unref (info); + continue; + } + + name = g_file_info_get_name (info); + if ((strcmp (name, ".") == 0) || (strcmp (name, "..") == 0)) { + g_object_unref (info); + continue; + } + + if (content_uri != NULL) { + g_free (content_uri); + g_object_unref (info); + content_uri = NULL; + break; + } + + content_uri = build_uri (uri, name, NULL); + g_object_unref (info); + } + + if (err != NULL) { + g_warning ("Failed to get info after enumerating children: %s", err->message); + g_clear_error (&err); + } + + g_object_unref (file_enum); + g_object_unref (file); + + return content_uri; +} + + +/* Check whether the dirname is contained in filename */ +gboolean +path_in_path (const char *dirname, + const char *filename) +{ + int dirname_l, filename_l, separator_position; + + if ((dirname == NULL) || (filename == NULL)) + return FALSE; + + dirname_l = strlen (dirname); + filename_l = strlen (filename); + + if ((dirname_l == filename_l + 1) + && (dirname[dirname_l - 1] == '/')) + return FALSE; + + if ((filename_l == dirname_l + 1) + && (filename[filename_l - 1] == '/')) + return FALSE; + + if (dirname[dirname_l - 1] == '/') + separator_position = dirname_l - 1; + else + separator_position = dirname_l; + + return ((filename_l > dirname_l) + && (strncmp (dirname, filename, dirname_l) == 0) + && (filename[separator_position] == '/')); +} + + +goffset +get_file_size (const char *uri) +{ + goffset size = 0; + GFile *file; + GFileInfo *info; + GError *err = NULL; + + if ((uri == NULL) || (*uri == '\0')) + return 0; + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, NULL, &err); + if (err == NULL) { + size = g_file_info_get_size (info); + } + else { + g_warning ("Failed to get file size for %s: %s", uri, err->message); + g_error_free (err); + } + + g_object_unref (info); + g_object_unref (file); + + return size; +} + + +goffset +get_file_size_for_path (const char *path) +{ + char *uri; + goffset result; + + uri = g_filename_to_uri (path, NULL, NULL); + result = get_file_size (uri); + g_free (uri); + + return result; +} + + +static time_t +get_file_time_type (const char *uri, + const char *type) +{ + time_t result = 0; + GFile *file; + GFileInfo *info; + GError *err = NULL; + + if ((uri == NULL) || (*uri == '\0')) + return 0; + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, type, 0, NULL, &err); + if (err == NULL) { + result = (time_t) g_file_info_get_attribute_uint64 (info, type); + } + else { + g_warning ("Failed to get %s: %s", type, err->message); + g_error_free (err); + result = 0; + } + + g_object_unref (info); + g_object_unref (file); + + return result; +} + + +time_t +get_file_mtime (const char *uri) +{ + return get_file_time_type (uri, G_FILE_ATTRIBUTE_TIME_MODIFIED); +} + + +time_t +get_file_mtime_for_path (const char *path) +{ + char *uri; + time_t result; + + uri = g_filename_to_uri (path, NULL, NULL); + result = get_file_mtime (uri); + g_free (uri); + + return result; +} + + +time_t +get_file_ctime (const char *uri) +{ + return get_file_time_type (uri, G_FILE_ATTRIBUTE_TIME_CREATED); +} + + +gboolean +file_is_hidden (const gchar *name) +{ + if (name[0] != '.') return FALSE; + if (name[1] == '\0') return FALSE; + if ((name[1] == '.') && (name[2] == '\0')) return FALSE; + + return TRUE; +} + + +/* like g_path_get_basename but does not warn about NULL and does not + * alloc a new string. */ +const gchar* file_name_from_path(const gchar *file_name) +{ + register char *base; + register gssize last_char; + + if (file_name == NULL) + return NULL; + + if (file_name[0] == '\0') + return ""; + + last_char = strlen (file_name) - 1; + + if (file_name [last_char] == G_DIR_SEPARATOR) + return ""; + + base = g_utf8_strrchr (file_name, -1, G_DIR_SEPARATOR); + if (! base) + return file_name; + + return base + 1; +} + + +char * +dir_name_from_path (const gchar *path) +{ + register gssize base; + register gssize last_char; + + if (path == NULL) + return NULL; + + if (path[0] == '\0') + return g_strdup (""); + + last_char = strlen (path) - 1; + if (path[last_char] == G_DIR_SEPARATOR) + last_char--; + + base = last_char; + while ((base >= 0) && (path[base] != G_DIR_SEPARATOR)) + base--; + + return g_strndup (path + base + 1, last_char - base); +} + + +gchar * +remove_level_from_path (const gchar *path) +{ + int p; + const char *ptr = path; + char *new_path; + + if (path == NULL) + return NULL; + + p = strlen (path) - 1; + if (p < 0) + return NULL; + + while ((p > 0) && (ptr[p] != '/')) + p--; + if ((p == 0) && (ptr[p] == '/')) + p++; + new_path = g_strndup (path, (guint)p); + + return new_path; +} + + +char * +remove_ending_separator (const char *path) +{ + gint len, copy_len; + + if (path == NULL) + return NULL; + + copy_len = len = strlen (path); + if ((len > 1) && (path[len - 1] == '/')) + copy_len--; + + return g_strndup (path, copy_len); +} + + +char * +build_uri (const char *base, ...) +{ + va_list args; + const char *child; + GString *uri; + + uri = g_string_new (base); + + va_start (args, base); + while ((child = va_arg (args, const char *)) != NULL) { + if (! g_str_has_suffix (uri->str, "/") && ! g_str_has_prefix (child, "/")) + g_string_append (uri, "/"); + g_string_append (uri, child); + } + va_end (args); + + return g_string_free (uri, FALSE); +} + + +gchar * +remove_extension_from_path (const gchar *path) +{ + int len; + int p; + const char *ptr = path; + char *new_path; + + if (! path) + return NULL; + + len = strlen (path); + if (len == 1) + return g_strdup (path); + + p = len - 1; + while ((p > 0) && (ptr[p] != '.')) + p--; + if (p == 0) + p = len; + new_path = g_strndup (path, (guint) p); + + return new_path; +} + + +gboolean +make_directory_tree (GFile *dir, + mode_t mode, + GError **error) +{ + gboolean success = TRUE; + GFile *parent; + + if ((dir == NULL) || g_file_query_exists (dir, NULL)) + return TRUE; + + parent = g_file_get_parent (dir); + if (parent != NULL) { + success = make_directory_tree (parent, mode, error); + g_object_unref (parent); + if (! success) + return FALSE; + } + + success = g_file_make_directory (dir, NULL, error); + if ((error != NULL) && (*error != NULL) && g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { + g_clear_error (error); + success = TRUE; + } + + if (success) + g_file_set_attribute_uint32 (dir, + G_FILE_ATTRIBUTE_UNIX_MODE, + mode, + 0, + NULL, + NULL); + + return success; +} + + +gboolean +ensure_dir_exists (const char *uri, + mode_t mode, + GError **error) +{ + GFile *dir; + GError *priv_error = NULL; + + if (uri == NULL) + return FALSE; + + if (error == NULL) + error = &priv_error; + + dir = g_file_new_for_uri (uri); + if (! make_directory_tree (dir, mode, error)) { + g_warning ("could create directory %s: %s", uri, (*error)->message); + if (priv_error != NULL) + g_clear_error (&priv_error); + return FALSE; + } + + return TRUE; +} + + +gboolean +make_directory_tree_from_path (const char *path, + mode_t mode, + GError **error) +{ + char *uri; + gboolean result; + + uri = g_filename_to_uri (path, NULL, NULL); + result = ensure_dir_exists (uri, mode, error); + g_free (uri); + + return result; +} + + +const char * +get_file_extension (const char *filename) +{ + const char *ptr = filename; + int len; + int p; + const char *ext; + + if (filename == NULL) + return NULL; + + len = strlen (filename); + if (len <= 1) + return NULL; + + p = len - 1; + while ((p >= 0) && (ptr[p] != '.')) + p--; + if (p < 0) + return NULL; + + ext = filename + p; + if (ext - 4 > filename) { + const char *test = ext - 4; + if (strncmp (test, ".tar", 4) == 0) + ext = ext - 4; + } + return ext; +} + + +gboolean +file_extension_is (const char *filename, + const char *ext) +{ + int filename_l, ext_l; + + filename_l = strlen (filename); + ext_l = strlen (ext); + + if (filename_l < ext_l) + return FALSE; + return strcasecmp (filename + filename_l - ext_l, ext) == 0; +} + + +gboolean +is_mime_type (const char *mime_type, + const char *pattern) +{ + return (strcasecmp (mime_type, pattern) == 0); +} + + +const char* +get_file_mime_type (const char *uri, + gboolean fast_file_type) +{ + GFile *file; + GFileInfo *info; + GError *err = NULL; + const char *result = NULL; + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, + fast_file_type ? + G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE : + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + 0, NULL, &err); + if (info == NULL) { + g_warning ("could not get content type for %s: %s", uri, err->message); + g_clear_error (&err); + } + else { + result = get_static_string (g_file_info_get_content_type (info)); + g_object_unref (info); + } + + g_object_unref (file); + + return result; +} + + +const char* +get_file_mime_type_for_path (const char *filename, + gboolean fast_file_type) +{ + char *uri; + const char *mime_type; + + uri = g_filename_to_uri (filename, NULL, NULL); + mime_type = get_file_mime_type (uri, fast_file_type); + g_free (uri); + + return mime_type; +} + + +void +path_list_free (GList *path_list) +{ + if (path_list == NULL) + return; + g_list_foreach (path_list, (GFunc) g_free, NULL); + g_list_free (path_list); +} + + +GList * +path_list_dup (GList *path_list) +{ + GList *new_list = NULL; + GList *scan; + + for (scan = path_list; scan; scan = scan->next) + new_list = g_list_prepend (new_list, g_strdup (scan->data)); + + return g_list_reverse (new_list); +} + + +guint64 +get_dest_free_space (const char *path) +{ + guint64 freespace = 0; + GFile *file; + GFileInfo *info; + GError *err = NULL; + + file = g_file_new_for_path (path); + info = g_file_query_filesystem_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, &err); + if (info != NULL) { + freespace = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); + g_object_unref (info); + } + else { + g_warning ("Could not get filesystem free space on volume that contains %s: %s", path, err->message); + g_error_free (err); + } + g_object_unref (file); + + return freespace; +} + + +static gboolean +delete_directory_recursive (GFile *dir, + GError **error) +{ + char *uri; + GFileEnumerator *file_enum; + GFileInfo *info; + gboolean error_occurred = FALSE; + + if (error != NULL) + *error = NULL; + + file_enum = g_file_enumerate_children (dir, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_TYPE, + 0, NULL, error); + + uri = g_file_get_uri (dir); + while (! error_occurred && (info = g_file_enumerator_next_file (file_enum, NULL, error)) != NULL) { + char *child_uri; + GFile *child; + + child_uri = build_uri (uri, g_file_info_get_name (info), NULL); + child = g_file_new_for_uri (child_uri); + + switch (g_file_info_get_file_type (info)) { + case G_FILE_TYPE_DIRECTORY: + if (! delete_directory_recursive (child, error)) + error_occurred = TRUE; + break; + default: + if (! g_file_delete (child, NULL, error)) + error_occurred = TRUE; + break; + } + + g_object_unref (child); + g_free (child_uri); + g_object_unref (info); + } + g_free (uri); + + if (! error_occurred && ! g_file_delete (dir, NULL, error)) + error_occurred = TRUE; + + g_object_unref (file_enum); + + return ! error_occurred; +} + + +gboolean +remove_directory (const char *uri) +{ + GFile *dir; + gboolean result; + GError *error = NULL; + + dir = g_file_new_for_uri (uri); + result = delete_directory_recursive (dir, &error); + if (! result) { + g_warning ("Cannot delete %s: %s", uri, error->message); + g_clear_error (&error); + } + g_object_unref (dir); + + return result; +} + + +gboolean +remove_local_directory (const char *path) +{ + char *uri; + gboolean result; + + if (path == NULL) + return TRUE; + + uri = g_filename_to_uri (path, NULL, NULL); + result = remove_directory (uri); + g_free (uri); + + return result; +} + + +static const char *try_folder[] = { "cache", "~", "tmp", NULL }; + + +static char * +ith_temp_folder_to_try (int n) +{ + const char *folder; + + folder = try_folder[n]; + if (strcmp (folder, "cache") == 0) + folder = g_get_user_cache_dir (); + else if (strcmp (folder, "~") == 0) + folder = g_get_home_dir (); + else if (strcmp (folder, "tmp") == 0) + folder = g_get_tmp_dir (); + + return g_strdup (folder); +} + + +char * +get_temp_work_dir (const char *parent_folder) +{ + guint64 max_size = 0; + char *best_folder = NULL; + int i; + char *template; + char *result = NULL; + + if (parent_folder == NULL) { + /* find the folder with more free space. */ + + for (i = 0; try_folder[i] != NULL; i++) { + char *folder; + guint64 size; + + folder = ith_temp_folder_to_try (i); + size = get_dest_free_space (folder); + if (max_size < size) { + max_size = size; + g_free (best_folder); + best_folder = folder; + } + else + g_free (folder); + } + } + else + best_folder = g_strdup (parent_folder); + + if (best_folder == NULL) + return NULL; + + template = g_strconcat (best_folder, "/.fr-XXXXXX", NULL); + result = mkdtemp (template); + + if ((result == NULL) || (*result == '\0')) { + g_free (template); + result = NULL; + } + + return result; +} + + +gboolean +is_temp_work_dir (const char *dir) +{ + int i; + const char *folder; + + if (strncmp (dir, "file://", 7) == 0) + dir = dir + 7; + else if (dir[0] != '/') + return FALSE; + + for (i = 0; try_folder[i] != NULL; i++) { + + folder = ith_temp_folder_to_try (i); + if (strncmp (dir, folder, strlen (folder)) == 0) + if (strncmp (dir + strlen (folder), "/.fr-", 5) == 0) { + g_free (folder); + return TRUE; + } + } + + g_free (folder); + return FALSE; +} + + +gboolean +is_temp_dir (const char *dir) +{ + if (strncmp (dir, "file://", 7) == 0) + dir = dir + 7; + if (strcmp (g_get_tmp_dir (), dir) == 0) + return TRUE; + if (path_in_path (g_get_tmp_dir (), dir)) + return TRUE; + else + return is_temp_work_dir (dir); +} + + +/* file list utils */ + + +gboolean +file_list__match_pattern (const char *line, + const char *pattern) +{ + const char *l = line, *p = pattern; + + for (; (*p != 0) && (*l != 0); p++, l++) { + if (*p != '%') { + if (*p != *l) + return FALSE; + } + else { + p++; + switch (*p) { + case 'a': + break; + case 'n': + if (!isdigit (*l)) + return FALSE; + break; + case 'c': + if (!isalpha (*l)) + return FALSE; + break; + default: + return FALSE; + } + } + } + + return (*p == 0); +} + + +int +file_list__get_index_from_pattern (const char *line, + const char *pattern) +{ + int line_l, pattern_l; + const char *l; + + line_l = strlen (line); + pattern_l = strlen (pattern); + + if ((pattern_l == 0) || (line_l == 0)) + return -1; + + for (l = line; *l != 0; l++) + if (file_list__match_pattern (l, pattern)) + return (l - line); + + return -1; +} + + +char* +file_list__get_next_field (const char *line, + int start_from, + int field_n) +{ + const char *f_start, *f_end; + + line = line + start_from; + + f_start = line; + while ((*f_start == ' ') && (*f_start != *line)) + f_start++; + f_end = f_start; + + while ((field_n > 0) && (*f_end != 0)) { + if (*f_end == ' ') { + field_n--; + if (field_n != 0) { + while ((*f_end == ' ') && (*f_end != *line)) + f_end++; + f_start = f_end; + } + } else + f_end++; + } + + return g_strndup (f_start, f_end - f_start); +} + + +char* +file_list__get_prev_field (const char *line, + int start_from, + int field_n) +{ + const char *f_start, *f_end; + + f_start = line + start_from - 1; + while ((*f_start == ' ') && (*f_start != *line)) + f_start--; + f_end = f_start; + + while ((field_n > 0) && (*f_start != *line)) { + if (*f_start == ' ') { + field_n--; + if (field_n != 0) { + while ((*f_start == ' ') && (*f_start != *line)) + f_start--; + f_end = f_start; + } + } else + f_start--; + } + + return g_strndup (f_start + 1, f_end - f_start); +} + + +gboolean +check_permissions (const char *uri, + int mode) +{ + GFile *file; + gboolean result; + + file = g_file_new_for_uri (uri); + result = check_file_permissions (file, mode); + + g_object_unref (file); + + return result; +} + + +gboolean +check_file_permissions (GFile *file, + int mode) +{ + gboolean result = TRUE; + GFileInfo *info; + GError *err = NULL; + gboolean default_permission_when_unknown = TRUE; + + info = g_file_query_info (file, "access::*", 0, NULL, &err); + if (err != NULL) { + g_clear_error (&err); + result = FALSE; + } + else { + if ((mode & R_OK) == R_OK) { + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) + result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)); + else + result = (result && default_permission_when_unknown); + } + + if ((mode & W_OK) == W_OK) { + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) + result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)); + else + result = (result && default_permission_when_unknown); + } + + if ((mode & X_OK) == X_OK) { + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) + result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)); + else + result = (result && default_permission_when_unknown); + } + + g_object_unref (info); + } + + return result; +} + + +gboolean +is_program_in_path (const char *filename) +{ + char *str; + char *value; + int result = FALSE; + + value = g_hash_table_lookup (ProgramsCache, filename); + if (value != NULL) { + result = (strcmp (value, "1") == 0); + return result; + } + + str = g_find_program_in_path (filename); + if (str != NULL) { + g_free (str); + result = TRUE; + } + + g_hash_table_insert (ProgramsCache, + g_strdup (filename), + result ? "1" : "0"); + + return result; +} + + +gboolean +is_program_available (const char *filename, + gboolean check) +{ + return ! check || is_program_in_path (filename); +} + + +const char * +get_home_uri (void) +{ + static char *home_uri = NULL; + if (home_uri == NULL) + home_uri = g_filename_to_uri (g_get_home_dir (), NULL, NULL); + return home_uri; +} + + +char * +get_home_relative_uri (const char *partial_uri) +{ + return g_strconcat (get_home_uri (), + "/", + partial_uri, + NULL); +} + + +GFile * +get_home_relative_file (const char *partial_uri) +{ + GFile *file; + char *uri; + + uri = g_strconcat (get_home_uri (), "/", partial_uri, NULL); + file = g_file_new_for_uri (uri); + g_free (uri); + + return file; +} + + +const char * +remove_host_from_uri (const char *uri) +{ + const char *idx, *sep; + + if (uri == NULL) + return NULL; + + idx = strstr (uri, "://"); + if (idx == NULL) + return uri; + idx += 3; + if (*idx == '\0') + return "/"; + sep = strstr (idx, "/"); + if (sep == NULL) + return idx; + return sep; +} + + +char * +get_uri_host (const char *uri) +{ + const char *idx; + + idx = strstr (uri, "://"); + if (idx == NULL) + return NULL; + idx = strstr (idx + 3, "/"); + if (idx == NULL) + return NULL; + return g_strndup (uri, (idx - uri)); +} + + +char * +get_uri_root (const char *uri) +{ + char *host; + char *root; + + host = get_uri_host (uri); + if (host == NULL) + return NULL; + root = g_strconcat (host, "/", NULL); + g_free (host); + + return root; +} + + +int +uricmp (const char *uri1, + const char *uri2) +{ + return strcmp_null_tolerant (uri1, uri2); +} + + +char * +get_alternative_uri (const char *folder, + const char *name) +{ + char *new_uri = NULL; + int n = 1; + + do { + g_free (new_uri); + if (n == 1) + new_uri = g_strconcat (folder, "/", name, NULL); + else + new_uri = g_strdup_printf ("%s/%s%%20(%d)", folder, name, n); + n++; + } while (uri_exists (new_uri)); + + return new_uri; +} + + +char * +get_alternative_uri_for_uri (const char *uri) +{ + char *base_uri; + char *new_uri; + + base_uri = remove_level_from_path (uri); + new_uri = get_alternative_uri (base_uri, file_name_from_path (uri)); + g_free (base_uri); + + return new_uri; +} + + +GList * +gio_file_list_dup (GList *l) +{ + GList *r = NULL, *scan; + for (scan = l; scan; scan = scan->next) + r = g_list_prepend (r, g_file_dup ((GFile*)scan->data)); + return g_list_reverse (r); +} + + +void +gio_file_list_free (GList *l) +{ + GList *scan; + for (scan = l; scan; scan = scan->next) + g_object_unref (scan->data); + g_list_free (l); +} + + +GList * +gio_file_list_new_from_uri_list (GList *uris) +{ + GList *r = NULL, *scan; + for (scan = uris; scan; scan = scan->next) + r = g_list_prepend (r, g_file_new_for_uri ((char*)scan->data)); + return g_list_reverse (r); +} + + +void +g_key_file_save (GKeyFile *key_file, + GFile *file) +{ + char *file_data; + gsize size; + GError *error = NULL; + + file_data = g_key_file_to_data (key_file, &size, &error); + if (error != NULL) { + g_warning ("Could not save options: %s\n", error->message); + g_clear_error (&error); + } + else { + GFileOutputStream *stream; + + stream = g_file_replace (file, NULL, FALSE, 0, NULL, &error); + if (stream == NULL) { + g_warning ("Could not save options: %s\n", error->message); + g_clear_error (&error); + } + else if (! g_output_stream_write_all (G_OUTPUT_STREAM (stream), file_data, size, NULL, NULL, &error)) { + g_warning ("Could not save options: %s\n", error->message); + g_clear_error (&error); + } + else if (! g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &error)) { + g_warning ("Could not save options: %s\n", error->message); + g_clear_error (&error); + } + + g_object_unref (stream); + } + + g_free (file_data); +} -- cgit v1.2.1