1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* gnome-vfs-utils.c - Private utility functions for the GNOME Virtual
6 Copyright (C) 1999 Free Software Foundation
7 Copyright (C) 2000, 2001 Eazel, Inc.
9 The Gnome Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
14 The Gnome Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with the Gnome Library; see the file COPYING.LIB. If not,
21 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
24 Authors: Ettore Perazzoli <ettore@comm2000.it>
25 John Sullivan <sullivan@eazel.com>
26 Darin Adler <darin@eazel.com>
30 #ifdef HAVE_SYS_PARAM_H
31 #include <sys/param.h>
33 #include "gnome-vfs-utils.h"
35 #include "gnome-vfs-i18n.h"
36 #include "gnome-vfs-private-utils.h"
37 #include "gnome-vfs-ops.h"
38 #include "gnome-vfs-mime-handlers.h"
39 #include <glib/gstrfuncs.h>
40 #include <glib/gutils.h>
41 #include <gconf/gconf-client.h>
46 #include <sys/types.h>
49 #if HAVE_SYS_STATVFS_H
50 #include <sys/statvfs.h>
55 #elif HAVE_SYS_MOUNT_H
56 #include <sys/mount.h>
59 #define KILOBYTE_FACTOR 1024.0
60 #define MEGABYTE_FACTOR (1024.0 * 1024.0)
61 #define GIGABYTE_FACTOR (1024.0 * 1024.0 * 1024.0)
63 #define READ_CHUNK_SIZE 8192
65 #define MAX_SYMLINKS_FOLLOWED 32
69 * gnome_vfs_format_file_size_for_display:
72 * Formats the file size passed in @bytes in a way that is easy for
73 * the user to read. Gives the size in bytes, kilobytes, megabytes or
74 * gigabytes, choosing whatever is appropriate.
76 * Returns: a newly allocated string with the size ready to be shown.
80 gnome_vfs_format_file_size_for_display (GnomeVFSFileSize size)
82 if (size < (GnomeVFSFileSize) KILOBYTE_FACTOR) {
84 return g_strdup (_("1 byte"));
86 return g_strdup_printf (_("%u bytes"),
89 gdouble displayed_size;
91 if (size < (GnomeVFSFileSize) MEGABYTE_FACTOR) {
92 displayed_size = (gdouble) size / KILOBYTE_FACTOR;
93 return g_strdup_printf (_("%.1f K"),
95 } else if (size < (GnomeVFSFileSize) GIGABYTE_FACTOR) {
96 displayed_size = (gdouble) size / MEGABYTE_FACTOR;
97 return g_strdup_printf (_("%.1f MB"),
100 displayed_size = (gdouble) size / GIGABYTE_FACTOR;
101 return g_strdup_printf (_("%.1f GB"),
108 UNSAFE_ALL = 0x1, /* Escape all unsafe characters */
109 UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */
110 UNSAFE_PATH = 0x4, /* Allows '/' and '?' and '&' and '=' */
111 UNSAFE_DOS_PATH = 0x8, /* Allows '/' and '?' and '&' and '=' and ':' */
112 UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */
113 UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */
114 } UnsafeCharacterSet;
116 static const guchar acceptable[96] =
117 { /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
118 0x00,0x3F,0x20,0x20,0x20,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x22,0x20,0x3F,0x3F,0x1C, /* 2X !"#$%&'()*+,-./ */
119 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x2C, /* 3X 0123456789:;<=>? */
120 0x30,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* 4X @ABCDEFGHIJKLMNO */
121 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, /* 5X PQRSTUVWXYZ[\]^_ */
122 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* 6X `abcdefghijklmno */
123 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20 /* 7X pqrstuvwxyz{|}~DEL */
135 static const guchar uri_character_kind[128] =
137 CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,
138 CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,
139 CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,
140 CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,CONTROL ,
141 /* ' ' ! " # $ % & ' */
142 SPACE ,UNRESERVED,DELIMITERS,DELIMITERS,RESERVED ,DELIMITERS,RESERVED ,UNRESERVED,
143 /* ( ) * + , - . / */
144 UNRESERVED,UNRESERVED,UNRESERVED,RESERVED ,RESERVED ,UNRESERVED,UNRESERVED,RESERVED ,
145 /* 0 1 2 3 4 5 6 7 */
146 UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
147 /* 8 9 : ; < = > ? */
148 UNRESERVED,UNRESERVED,RESERVED ,RESERVED ,DELIMITERS,RESERVED ,DELIMITERS,RESERVED ,
149 /* @ A B C D E F G */
150 RESERVED ,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
151 /* H I J K L M N O */
152 UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
153 /* P Q R S T U V W */
154 UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
155 /* X Y Z [ \ ] ^ _ */
156 UNRESERVED,UNRESERVED,UNRESERVED,UNWISE ,UNWISE ,UNWISE ,UNWISE ,UNRESERVED,
157 /* ` a b c d e f g */
158 UNWISE ,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
159 /* h i j k l m n o */
160 UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
161 /* p q r s t u v w */
162 UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
163 /* x y z { | } ~ DEL */
164 UNRESERVED,UNRESERVED,UNRESERVED,UNWISE ,UNWISE ,UNWISE ,UNRESERVED,CONTROL
168 /* Below modified from libwww HTEscape.c */
170 #define HEX_ESCAPE '%'
172 /* Escape undesirable characters using %
173 * -------------------------------------
175 * This function takes a pointer to a string in which
176 * some characters may be unacceptable unescaped.
177 * It returns a string which has these characters
178 * represented by a '%' character followed by two hex digits.
180 * This routine returns a g_malloced string.
183 static const gchar hex[16] = "0123456789ABCDEF";
186 gnome_vfs_escape_string_internal (const gchar *string,
187 UnsafeCharacterSet mask)
189 #define ACCEPTABLE_CHAR(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
196 UnsafeCharacterSet use_mask;
198 g_return_val_if_fail (mask == UNSAFE_ALL
199 || mask == UNSAFE_ALLOW_PLUS
200 || mask == UNSAFE_PATH
201 || mask == UNSAFE_DOS_PATH
202 || mask == UNSAFE_HOST
203 || mask == UNSAFE_SLASHES, NULL);
205 if (string == NULL) {
211 for (p = string; *p != '\0'; p++) {
213 if (!ACCEPTABLE_CHAR (c)) {
216 if ((use_mask == UNSAFE_HOST) &&
217 (unacceptable || (c == '/'))) {
218 /* when escaping a host, if we hit something that needs to be escaped, or we finally
219 * hit a path separator, revert to path mode (the host segment of the url is over).
221 use_mask = UNSAFE_PATH;
225 result = g_malloc (p - string + unacceptable * 2 + 1);
228 for (q = result, p = string; *p != '\0'; p++){
231 if (!ACCEPTABLE_CHAR (c)) {
232 *q++ = HEX_ESCAPE; /* means hex coming */
238 if ((use_mask == UNSAFE_HOST) &&
239 (!ACCEPTABLE_CHAR (c) || (c == '/'))) {
240 use_mask = UNSAFE_PATH;
250 * gnome_vfs_escape_string:
251 * @string: string to be escaped
253 * Escapes @string, replacing any and all special characters
254 * with equivalent escape sequences.
256 * Return value: a newly allocated string equivalent to @string
257 * but with all special characters escaped
260 gnome_vfs_escape_string (const gchar *string)
262 return gnome_vfs_escape_string_internal (string, UNSAFE_ALL);
266 * gnome_vfs_escape_path_string:
267 * @path: string to be escaped
269 * Escapes @path, replacing only special characters that would not
270 * be found in paths (so '/', '&', '=', and '?' will not be escaped by
273 * Return value: a newly allocated string equivalent to @path but
274 * with non-path characters escaped
277 gnome_vfs_escape_path_string (const gchar *path)
279 return gnome_vfs_escape_string_internal (path, UNSAFE_PATH);
283 * gnome_vfs_escape_host_and_path_string:
284 * @path: string to be escaped
286 * Escapes @path, replacing only special characters that would not
287 * be found in paths or host name (so '/', '&', '=', ':', '@'
288 * and '?' will not be escaped by this function).
290 * Return value: a newly allocated string equivalent to @path but
291 * with non-path/host characters escaped
294 gnome_vfs_escape_host_and_path_string (const gchar *path)
296 return gnome_vfs_escape_string_internal (path, UNSAFE_HOST);
300 * gnome_vfs_escape_slashes:
301 * @string: string to be escaped
303 * Escapes only '/' and '%' characters in @string, replacing
304 * them with their escape sequence equivalents.
306 * Return value: a newly allocated string equivalent to @string,
307 * but with no unescaped '/' or '%' characters
310 gnome_vfs_escape_slashes (const gchar *string)
312 return gnome_vfs_escape_string_internal (string, UNSAFE_SLASHES);
316 gnome_vfs_escape_set (const char *string,
317 const char *match_set)
321 char *result_scanner;
326 if (string == NULL) {
330 if (match_set == NULL) {
331 return g_strdup (string);
334 for (scanner = string; *scanner != '\0'; scanner++) {
335 if (strchr(match_set, *scanner) != NULL) {
336 /* this character is in the set of characters
343 if (escape_count == 0) {
344 return g_strdup (string);
347 /* allocate two extra characters for every character that
348 * needs escaping and space for a trailing zero
350 result = g_malloc (scanner - string + escape_count * 2 + 1);
351 for (scanner = string, result_scanner = result; *scanner != '\0'; scanner++) {
352 if (strchr(match_set, *scanner) != NULL) {
353 /* this character is in the set of characters
356 *result_scanner++ = HEX_ESCAPE;
357 *result_scanner++ = hex[*scanner >> 4];
358 *result_scanner++ = hex[*scanner & 15];
361 *result_scanner++ = *scanner;
365 *result_scanner = '\0';
371 * gnome_vfs_expand_initial_tilde:
372 * @path: a local file path which may start with a '~'
374 * If @path starts with a ~, representing the user's home
375 * directory, expand it to the actual path location.
377 * Return value: a newly allocated string with the initial
378 * tilde (if there was one) converted to an actual path
381 gnome_vfs_expand_initial_tilde (const char *path)
383 char *slash_after_user_name, *user_name;
384 struct passwd *passwd_file_entry;
386 g_return_val_if_fail (path != NULL, NULL);
388 if (path[0] != '~') {
389 return g_strdup (path);
392 if (path[1] == '/' || path[1] == '\0') {
393 return g_strconcat (g_get_home_dir (), &path[1], NULL);
396 slash_after_user_name = strchr (&path[1], '/');
397 if (slash_after_user_name == NULL) {
398 user_name = g_strdup (&path[1]);
400 user_name = g_strndup (&path[1],
401 slash_after_user_name - &path[1]);
403 passwd_file_entry = getpwnam (user_name);
406 if (passwd_file_entry == NULL || passwd_file_entry->pw_dir == NULL) {
407 return g_strdup (path);
410 return g_strconcat (passwd_file_entry->pw_dir,
411 slash_after_user_name,
418 return c >= '0' && c <= '9' ? c - '0'
419 : c >= 'A' && c <= 'F' ? c - 'A' + 10
420 : c >= 'a' && c <= 'f' ? c - 'a' + 10
425 unescape_character (const char *scanner)
430 first_digit = hex_to_int (*scanner++);
431 if (first_digit < 0) {
435 second_digit = hex_to_int (*scanner++);
436 if (second_digit < 0) {
440 return (first_digit << 4) | second_digit;
444 * gnome_vfs_unescape_string:
445 * @escaped_string: an escaped URI, path, or other string
446 * @illegal_characters: a string containing a sequence of characters
447 * considered "illegal", '\0' is automatically in this list.
449 * Decodes escaped characters (i.e. PERCENTxx sequences) in @escaped_string.
450 * Characters are encoded in PERCENTxy form, where xy is the ASCII hex code
451 * for character 16x+y.
453 * Return value: a newly allocated string with the unescaped equivalents,
454 * or %NULL if @escaped_string contained one of the characters
455 * in @illegal_characters.
458 gnome_vfs_unescape_string (const gchar *escaped_string,
459 const gchar *illegal_characters)
465 if (escaped_string == NULL) {
469 result = g_malloc (strlen (escaped_string) + 1);
472 for (in = escaped_string; *in != '\0'; in++) {
474 if (*in == HEX_ESCAPE) {
475 character = unescape_character (in + 1);
477 /* Check for an illegal character. We consider '\0' illegal here. */
479 || (illegal_characters != NULL
480 && strchr (illegal_characters, (char)character) != NULL)) {
486 *out++ = (char)character;
490 g_assert (out - result <= strlen (escaped_string));
496 * gnome_vfs_unescape_for_display:
497 * @escaped: The string encoded with escaped sequences
499 * Similar to gnome_vfs_unescape_string, but it returns something
500 * semi-intelligable to a user even upon receiving traumatic input
501 * such as %00 or URIs in bad form.
503 * See also: gnome_vfs_unescape_string.
505 * Return value: A pointer to a g_malloc'd string with all characters
506 * replacing their escaped hex values
508 * WARNING: You should never use this function on a whole URI! It
509 * unescapes reserved characters, and can result in a mangled URI
510 * that can not be re-entered. For example, it unescapes "#" "&" and "?",
511 * which have special meanings in URI strings.
514 gnome_vfs_unescape_string_for_display (const gchar *escaped)
516 const gchar *in, *start_escape;
522 if (escaped == NULL) {
526 result = g_malloc (strlen (escaped) + 1);
529 for (in = escaped; *in != '\0'; ) {
534 if (c == HEX_ESCAPE) {
535 /* Get the first hex digit. */
536 i = hex_to_int (*in++);
543 if (invalid_escape == 0) {
544 /* Get the second hex digit. */
545 i = hex_to_int (*in++);
552 if (invalid_escape == 0) {
553 /* Check for an illegal character. */
559 if (invalid_escape != 0) {
560 for (j = 0; j < invalid_escape; j++) {
561 *out++ = *start_escape++;
569 g_assert (out - result <= strlen (escaped));
574 * gnome_vfs_remove_optional_escapes:
575 * @uri: an escaped uri
577 * Scans the uri and converts characters that do not have to be
578 * escaped into an un-escaped form. The characters that get treated this
579 * way are defined as unreserved by the RFC.
581 * Return value: an error value if the uri is found to be malformed.
584 gnome_vfs_remove_optional_escapes (char *uri)
594 length = strlen (uri);
596 for (scanner = uri; *scanner != '\0'; scanner++, length--) {
597 if (*scanner == HEX_ESCAPE) {
598 character = unescape_character (scanner + 1);
600 /* invalid hexadecimal character */
601 return GNOME_VFS_ERROR_INVALID_URI;
604 if (uri_character_kind [character] == UNRESERVED) {
605 /* This character does not need to be escaped, convert it
606 * to a non-escaped form.
608 *scanner = (guchar)character;
609 g_assert (length >= 3);
611 /* Shrink the string covering up the two extra digits of the
612 * escaped character. Include the trailing '\0' in the copy
613 * to keep the string terminated.
615 memmove (scanner + 1, scanner + 3, length - 2);
617 /* This character must stay escaped, skip the entire
624 } else if (*scanner > 127
625 || uri_character_kind [*scanner] == DELIMITERS
626 || uri_character_kind [*scanner] == UNWISE
627 || uri_character_kind [*scanner] == CONTROL) {
628 /* It is illegal for this character to be in an un-escaped form
631 return GNOME_VFS_ERROR_INVALID_URI;
638 gnome_vfs_make_uri_canonical_old (const char *original_uri_text)
643 uri = gnome_vfs_uri_new_private (original_uri_text, TRUE, TRUE, FALSE);
648 result = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
649 gnome_vfs_uri_unref (uri);
655 * gnome_vfs_make_path_name_canonical:
656 * @path: a file path, relative or absolute
658 * Calls _gnome_vfs_canonicalize_pathname, allocating storage for the
659 * result and providing for a cleaner memory management.
661 * Return value: a canonical version of @path
664 gnome_vfs_make_path_name_canonical (const gchar *path)
669 path_clone = g_strdup (path);
670 result = _gnome_vfs_canonicalize_pathname (path_clone);
671 if (result != path_clone) {
673 return g_strdup (result);
680 * gnome_vfs_list_deep_free:
681 * @list: list to be freed
683 * Free @list, and call g_free() on all data members.
686 gnome_vfs_list_deep_free (GList *list)
693 for (p = list; p != NULL; p = p->next) {
700 * gnome_vfs_get_local_path_from_uri:
701 * @uri: URI to convert to a local path
703 * Create a local path for a file:/// URI. Do not use with URIs
706 * Return value: a newly allocated string containing the local path
707 * NULL is returned on error or if the uri isn't a file: URI
708 * without a fragment identifier (or chained URI).
711 gnome_vfs_get_local_path_from_uri (const char *uri)
713 const char *path_part;
715 if (!_gnome_vfs_istr_has_prefix (uri, "file:/")) {
719 path_part = uri + strlen ("file:");
720 if (strchr (path_part, '#') != NULL) {
724 if (_gnome_vfs_istr_has_prefix (path_part, "///")) {
726 } else if (_gnome_vfs_istr_has_prefix (path_part, "//")) {
730 return gnome_vfs_unescape_string (path_part, "/");
734 * gnome_vfs_get_uri_from_local_path:
735 * @local_full_path: a full local filesystem path (i.e. not relative)
737 * Returns a file:/// URI for the local path @local_full_path.
739 * Return value: a newly allocated string containing the URI corresponding
740 * to @local_full_path (NULL for some bad errors).
743 gnome_vfs_get_uri_from_local_path (const char *local_full_path)
745 char *escaped_path, *result;
747 if (local_full_path == NULL) {
751 g_return_val_if_fail (local_full_path[0] == '/', NULL);
753 escaped_path = gnome_vfs_escape_path_string (local_full_path);
754 result = g_strconcat ("file://", escaped_path, NULL);
755 g_free (escaped_path);
760 * gnome_vfs_get_volume_free_space:
764 * Stores in @size the amount of free space on a volume.
765 * This only works for local file systems with the file: scheme.
767 * Returns: GNOME_VFS_OK on success, otherwise an error code
770 gnome_vfs_get_volume_free_space (const GnomeVFSURI *vfs_uri,
771 GnomeVFSFileSize *size)
773 GnomeVFSFileSize free_blocks, block_size;
775 const char *path, *scheme;
776 char *unescaped_path;
779 struct statvfs statfs_buffer;
781 struct statfs statfs_buffer;
786 path = gnome_vfs_uri_get_path (vfs_uri);
788 return GNOME_VFS_ERROR_NOT_SUPPORTED;
791 scheme = gnome_vfs_uri_get_scheme (vfs_uri);
793 /* We only handle the file scheme for now */
794 if (g_ascii_strcasecmp (scheme, "file") != 0 || !_gnome_vfs_istr_has_prefix (path, "/")) {
795 return GNOME_VFS_ERROR_NOT_SUPPORTED;
798 unescaped_path = gnome_vfs_unescape_string (path, G_DIR_SEPARATOR_S);
801 statfs_result = statvfs (unescaped_path, &statfs_buffer);
803 statfs_result = statfs (unescaped_path, &statfs_buffer);
806 g_free (unescaped_path);
808 if (statfs_result != 0) {
809 return gnome_vfs_result_from_errno ();
812 block_size = statfs_buffer.f_bsize;
813 free_blocks = statfs_buffer.f_bavail;
815 *size = block_size * free_blocks;
821 gnome_vfs_icon_path_from_filename (const char *relative_filename)
823 const char *gnome_var;
825 char **paths, **temp_paths;
827 if (g_path_is_absolute (relative_filename) &&
828 g_file_test (relative_filename, G_FILE_TEST_EXISTS))
829 return g_strdup (relative_filename);
831 gnome_var = g_getenv ("GNOME_PATH");
833 if (gnome_var == NULL) {
837 paths = g_strsplit (gnome_var, ":", 0);
839 for (temp_paths = paths; *temp_paths != NULL; temp_paths++) {
840 full_filename = g_strconcat (*temp_paths, "/share/pixmaps/", relative_filename, NULL);
841 if (g_file_test (full_filename, G_FILE_TEST_EXISTS)) {
843 return full_filename;
845 g_free (full_filename);
846 full_filename = NULL;
854 strdup_to (const char *string, const char *end)
857 return g_strdup (string);
859 return g_strndup (string, end - string);
863 is_executable_file (const char *path)
865 struct stat stat_buffer;
867 /* Check that it exists. */
868 if (stat (path, &stat_buffer) != 0) {
872 /* Check that it is a file. */
873 if (!S_ISREG (stat_buffer.st_mode)) {
877 /* Check that it's executable. */
878 if (access (path, X_OK) != 0) {
886 executable_in_path (const char *executable_name)
888 const char *path_list, *piece_start, *piece_end;
889 char *piece, *raw_path, *expanded_path;
892 path_list = g_getenv ("PATH");
894 for (piece_start = path_list; ; piece_start = piece_end + 1) {
895 /* Find the next piece of PATH. */
896 piece_end = strchr (piece_start, ':');
897 piece = strdup_to (piece_start, piece_end);
900 if (piece[0] == '\0') {
903 /* Try out this path with the executable. */
904 raw_path = g_strconcat (piece, "/", executable_name, NULL);
905 expanded_path = gnome_vfs_expand_initial_tilde (raw_path);
908 is_good = is_executable_file (expanded_path);
909 g_free (expanded_path);
918 if (piece_end == NULL) {
925 get_executable_name_from_command_string (const char *command_string)
927 /* FIXME bugzilla.eazel.com 2757:
928 * We need to handle quoting here for the full-path case */
929 return g_strstrip (strdup_to (command_string, strchr (command_string, ' ')));
933 * gnome_vfs_is_executable_command_string:
936 * Checks if @command_string starts with the full path of an executable file
937 * or an executable in $PATH.
939 * Returns: TRUE if command_string started with and executable file,
943 gnome_vfs_is_executable_command_string (const char *command_string)
945 char *executable_name;
946 char *executable_path;
949 /* Check whether command_string is a full path for an executable. */
950 if (command_string[0] == '/') {
952 /* FIXME bugzilla.eazel.com 2757:
953 * Because we don't handle quoting, we can check for full
954 * path including spaces, but no parameters, and full path
955 * with no spaces with or without parameters. But this will
956 * fail for quoted full path with spaces, and parameters.
959 /* This works if command_string contains a space, but not
960 * if command_string has parameters.
962 if (is_executable_file (command_string)) {
966 /* This works if full path has no spaces, with or without parameters */
967 executable_path = get_executable_name_from_command_string (command_string);
968 found = is_executable_file (executable_path);
969 g_free (executable_path);
974 executable_name = get_executable_name_from_command_string (command_string);
975 found = executable_in_path (executable_name);
976 g_free (executable_name);
982 * gnome_vfs_read_entire_file:
983 * @uri: URI of the file to read
984 * @file_size: after reading the file, contains the size of the file read
985 * @file_contents: contains the file_size bytes, the contents of the file at @uri.
987 * Reads an entire file into memory for convenience. Beware accidentally
988 * loading large files into memory with this function.
990 * Return value: An integer representing the result of the operation
996 gnome_vfs_read_entire_file (const char *uri,
998 char **file_contents)
1000 GnomeVFSResult result;
1001 GnomeVFSHandle *handle;
1003 GnomeVFSFileSize total_bytes_read;
1004 GnomeVFSFileSize bytes_read;
1007 *file_contents = NULL;
1009 /* Open the file. */
1010 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1011 if (result != GNOME_VFS_OK) {
1015 /* Read the whole thing. */
1017 total_bytes_read = 0;
1019 buffer = g_realloc (buffer, total_bytes_read + READ_CHUNK_SIZE);
1020 result = gnome_vfs_read (handle,
1021 buffer + total_bytes_read,
1024 if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) {
1026 gnome_vfs_close (handle);
1030 /* Check for overflow. */
1031 if (total_bytes_read + bytes_read < total_bytes_read) {
1033 gnome_vfs_close (handle);
1034 return GNOME_VFS_ERROR_TOO_BIG;
1037 total_bytes_read += bytes_read;
1038 } while (result == GNOME_VFS_OK);
1040 /* Close the file. */
1041 result = gnome_vfs_close (handle);
1042 if (result != GNOME_VFS_OK) {
1047 /* Return the file. */
1048 *file_size = total_bytes_read;
1049 *file_contents = g_realloc (buffer, total_bytes_read);
1050 return GNOME_VFS_OK;
1054 gnome_vfs_make_valid_utf8 (const char *name)
1057 const char *remainder, *invalid;
1058 int remaining_bytes, valid_bytes;
1062 remaining_bytes = strlen (name);
1064 while (remaining_bytes != 0) {
1065 if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
1068 valid_bytes = invalid - remainder;
1070 if (string == NULL) {
1071 string = g_string_sized_new (remaining_bytes);
1073 g_string_append_len (string, remainder, valid_bytes);
1074 g_string_append_c (string, '?');
1076 remaining_bytes -= valid_bytes + 1;
1077 remainder = invalid + 1;
1080 if (string == NULL) {
1081 return g_strdup (name);
1084 g_string_append (string, remainder);
1085 g_string_append (string, _(" (invalid Unicode)"));
1086 g_assert (g_utf8_validate (string->str, -1, NULL));
1088 return g_string_free (string, FALSE);
1092 gnome_vfs_format_uri_for_display_internal (const char *uri, gboolean filenames_are_locale_encoded)
1094 char *canonical_uri, *path, *utf8_path;
1096 g_return_val_if_fail (uri != NULL, g_strdup (""));
1098 canonical_uri = gnome_vfs_make_uri_canonical_old (uri);
1100 /* If there's no fragment and it's a local path. */
1101 path = gnome_vfs_get_local_path_from_uri (canonical_uri);
1104 if (filenames_are_locale_encoded) {
1105 utf8_path = g_locale_to_utf8 (path, -1, NULL, NULL, NULL);
1107 g_free (canonical_uri);
1111 } else if (g_utf8_validate (path, -1, NULL)) {
1112 g_free (canonical_uri);
1117 if (canonical_uri && !g_utf8_validate (canonical_uri, -1, NULL)) {
1118 utf8_path = gnome_vfs_make_valid_utf8 (canonical_uri);
1119 g_free (canonical_uri);
1120 canonical_uri = utf8_path;
1124 return canonical_uri;
1129 * gnome_vfs_format_uri_for_display:
1131 * Filter, modify, unescape and change URIs to make them appropriate
1132 * to display to users. The conversion is done such that the roundtrip
1133 * to UTF-8 is reversible.
1136 * file: URI's without fragments should appear as local paths
1137 * file: URI's with fragments should appear as file: URI's
1138 * All other URI's appear as expected
1142 * Returns: a newly allocated UTF-8 string
1148 gnome_vfs_format_uri_for_display (const char *uri)
1150 static gboolean broken_filenames;
1152 broken_filenames = g_getenv ("G_BROKEN_FILENAMES") != NULL;
1154 return gnome_vfs_format_uri_for_display_internal (uri, broken_filenames);
1158 is_valid_scheme_character (char c)
1160 return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
1164 has_valid_scheme (const char *uri)
1170 if (!is_valid_scheme_character (*p)) {
1176 } while (is_valid_scheme_character (*p));
1182 gnome_vfs_escape_high_chars (const guchar *string)
1185 const guchar *scanner;
1186 guchar *result_scanner;
1188 static const gchar hex[16] = "0123456789ABCDEF";
1190 #define ACCEPTABLE(a) ((a)>=32 && (a)<128)
1194 if (string == NULL) {
1198 for (scanner = string; *scanner != '\0'; scanner++) {
1199 if (!ACCEPTABLE(*scanner)) {
1204 if (escape_count == 0) {
1205 return g_strdup (string);
1208 /* allocate two extra characters for every character that
1209 * needs escaping and space for a trailing zero
1211 result = g_malloc (scanner - string + escape_count * 2 + 1);
1212 for (scanner = string, result_scanner = result; *scanner != '\0'; scanner++) {
1213 if (!ACCEPTABLE(*scanner)) {
1214 *result_scanner++ = '%';
1215 *result_scanner++ = hex[*scanner >> 4];
1216 *result_scanner++ = hex[*scanner & 15];
1219 *result_scanner++ = *scanner;
1223 *result_scanner = '\0';
1228 /* http uris look like <something>.<2-4 letters>, possibly followed by a slash and some text. */
1230 looks_like_http_uri (const char *str)
1235 const char *first_slash;
1237 first_slash = strchr(str, '/');
1238 if (first_slash == NULL) {
1241 len = first_slash - str;
1243 for (i = 0; i < 5 && i < len; i++) {
1244 c = str[len - 1 - i];
1245 if (i >= 2 && c == '.') {
1248 if (!g_ascii_isalpha (c)) {
1255 /* The strip_trailing_whitespace option is intended to make copy/paste of
1256 * URIs less error-prone when it is known that trailing whitespace isn't
1260 gnome_vfs_make_uri_from_input_internal (const char *text,
1261 gboolean filenames_are_locale_encoded,
1262 gboolean strip_trailing_whitespace)
1264 char *stripped, *path, *uri, *locale_path, *filesystem_path, *escaped;
1266 g_return_val_if_fail (text != NULL, g_strdup (""));
1268 /* Strip off leading whitespaces (since they can't be part of a valid
1269 uri). Only strip off trailing whitespaces when requested since
1270 they might be part of a valid uri.
1272 if (strip_trailing_whitespace) {
1273 stripped = g_strstrip (g_strdup (text));
1275 stripped = g_strchug (g_strdup (text));
1278 switch (stripped[0]) {
1280 uri = g_strdup ("");
1283 if (filenames_are_locale_encoded) {
1284 GError *error = NULL;
1285 locale_path = g_locale_from_utf8 (stripped, -1, NULL, NULL, &error);
1286 if (locale_path != NULL) {
1287 uri = gnome_vfs_get_uri_from_local_path (locale_path);
1288 g_free (locale_path);
1290 /* We couldn't convert to the locale. */
1291 /* FIXME: We should probably give a user-visible error here. */
1295 uri = gnome_vfs_get_uri_from_local_path (stripped);
1299 if (filenames_are_locale_encoded) {
1300 filesystem_path = g_locale_from_utf8 (stripped, -1, NULL, NULL, NULL);
1302 filesystem_path = g_strdup (stripped);
1304 /* deliberately falling into default case on fail */
1305 if (filesystem_path != NULL) {
1306 path = gnome_vfs_expand_initial_tilde (filesystem_path);
1307 g_free (filesystem_path);
1309 uri = gnome_vfs_get_uri_from_local_path (path);
1315 /* don't insert break here, read above comment */
1317 if (has_valid_scheme (stripped)) {
1318 uri = gnome_vfs_escape_high_chars (stripped);
1319 } else if (looks_like_http_uri (stripped)) {
1320 escaped = gnome_vfs_escape_high_chars (stripped);
1321 uri = g_strconcat ("http://", escaped, NULL);
1324 escaped = gnome_vfs_escape_high_chars (stripped);
1325 uri = g_strconcat ("file://", escaped, NULL);
1337 * gnome_vfs_make_uri_from_input:
1338 * @location: a possibly mangled "uri", in UTF8
1340 * Takes a user input path/URI and makes a valid URI out of it.
1342 * This function is the reverse of gnome_vfs_format_uri_for_display
1343 * but it also handles the fact that the user could have typed
1344 * arbitrary UTF8 in the entry showing the string.
1346 * Returns: a newly allocated uri.
1351 gnome_vfs_make_uri_from_input (const char *location)
1353 static gboolean broken_filenames;
1355 broken_filenames = g_getenv ("G_BROKEN_FILENAMES") != NULL;
1357 return gnome_vfs_make_uri_from_input_internal (location, broken_filenames, TRUE);
1361 * gnome_vfs_make_uri_from_input_with_dirs:
1362 * @in: a relative or absolute path
1364 * Determines a fully qualified URL from a relative or absolute input path.
1365 * Basically calls gnome_vfs_make_uri_from_input except it specifically
1366 * tries to support paths relative to the specified directories (can be homedir
1367 * and/or current directory).
1369 * Return value: a newly allocated string containing the fully qualified URL
1374 gnome_vfs_make_uri_from_input_with_dirs (const char *in,
1375 GnomeVFSMakeURIDirs dirs)
1377 char *uri, *path, *dir;
1381 uri = g_strdup ("");
1386 uri = gnome_vfs_make_uri_from_input (in);
1390 /* this might be a relative path, check if it exists relative
1391 * to current dir and home dir.
1394 if (dirs & GNOME_VFS_MAKE_URI_DIR_CURRENT) {
1395 dir = g_get_current_dir ();
1396 path = g_build_filename (dir, in, NULL);
1399 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
1400 uri = gnome_vfs_make_uri_from_input (path);
1406 dirs & GNOME_VFS_MAKE_URI_DIR_HOMEDIR) {
1407 path = g_build_filename (g_get_home_dir (), in, NULL);
1409 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
1410 uri = gnome_vfs_make_uri_from_input (path);
1416 uri = gnome_vfs_make_uri_from_input (in);
1425 * gnome_vfs_make_uri_canonical_strip_fragment:
1428 * If the @uri passed contains a fragment (anything after a '#') strips if,
1429 * then makes the URI canonical.
1431 * Returns: a newly allocated string containing a canonical URI.
1437 gnome_vfs_make_uri_canonical_strip_fragment (const char *uri)
1439 const char *fragment;
1440 char *without_fragment, *canonical;
1442 fragment = strchr (uri, '#');
1443 if (fragment == NULL) {
1444 return gnome_vfs_make_uri_canonical (uri);
1447 without_fragment = g_strndup (uri, fragment - uri);
1448 canonical = gnome_vfs_make_uri_canonical (without_fragment);
1449 g_free (without_fragment);
1454 uris_match (const char *uri_1, const char *uri_2, gboolean ignore_fragments)
1456 char *canonical_1, *canonical_2;
1459 if (ignore_fragments) {
1460 canonical_1 = gnome_vfs_make_uri_canonical_strip_fragment (uri_1);
1461 canonical_2 = gnome_vfs_make_uri_canonical_strip_fragment (uri_2);
1463 canonical_1 = gnome_vfs_make_uri_canonical (uri_1);
1464 canonical_2 = gnome_vfs_make_uri_canonical (uri_2);
1467 result = strcmp (canonical_1, canonical_2) ? FALSE : TRUE;
1469 g_free (canonical_1);
1470 g_free (canonical_2);
1476 * gnome_vfs_uris_match:
1477 * @uri_1: stringified URI to compare with @uri_2.
1478 * @uri_2: stringified URI to compare with @uri_1.
1482 * Return value: TRUE if they are the same, FALSE otherwise.
1488 gnome_vfs_uris_match (const char *uri_1, const char *uri_2)
1490 return uris_match (uri_1, uri_2, FALSE);
1494 gnome_vfs_str_has_prefix (const char *haystack, const char *needle)
1498 /* Eat one character at a time. */
1499 h = haystack == NULL ? "" : haystack;
1500 n = needle == NULL ? "" : needle;
1508 } while (*h++ == *n++);
1514 gnome_vfs_uri_is_local_scheme (const char *uri)
1516 gboolean is_local_scheme;
1519 char *local_schemes[] = {"file:", "help:", "ghelp:", "gnome-help:",
1520 "trash:", "man:", "info:",
1521 "hardware:", "search:", "pipe:",
1522 "gnome-trash:", NULL};
1524 is_local_scheme = FALSE;
1525 for (temp_scheme = *local_schemes, i = 0; temp_scheme != NULL; i++, temp_scheme = local_schemes[i]) {
1526 is_local_scheme = _gnome_vfs_istr_has_prefix (uri, temp_scheme);
1527 if (is_local_scheme) {
1533 return is_local_scheme;
1537 gnome_vfs_handle_trailing_slashes (const char *uri)
1539 char *temp, *uri_copy;
1540 gboolean previous_char_is_column, previous_chars_are_slashes_without_column;
1541 gboolean previous_chars_are_slashes_with_column;
1542 gboolean is_local_scheme;
1544 g_assert (uri != NULL);
1546 uri_copy = g_strdup (uri);
1547 if (strlen (uri_copy) <= 2) {
1551 is_local_scheme = gnome_vfs_uri_is_local_scheme (uri);
1553 previous_char_is_column = FALSE;
1554 previous_chars_are_slashes_without_column = FALSE;
1555 previous_chars_are_slashes_with_column = FALSE;
1557 /* remove multiple trailing slashes */
1558 for (temp = uri_copy; *temp != '\0'; temp++) {
1559 if (*temp == '/' && !previous_char_is_column) {
1560 previous_chars_are_slashes_without_column = TRUE;
1561 } else if (*temp == '/' && previous_char_is_column) {
1562 previous_chars_are_slashes_without_column = FALSE;
1563 previous_char_is_column = TRUE;
1564 previous_chars_are_slashes_with_column = TRUE;
1566 previous_chars_are_slashes_without_column = FALSE;
1567 previous_char_is_column = FALSE;
1568 previous_chars_are_slashes_with_column = FALSE;
1572 previous_char_is_column = TRUE;
1576 if (*temp == '\0' && previous_chars_are_slashes_without_column) {
1577 if (is_local_scheme) {
1578 /* go back till you remove them all. */
1579 for (temp--; *(temp) == '/'; temp--) {
1583 /* go back till you remove them all but one. */
1584 for (temp--; *(temp - 1) == '/'; temp--) {
1590 if (*temp == '\0' && previous_chars_are_slashes_with_column) {
1591 /* go back till you remove them all but three. */
1592 for (temp--; *(temp - 3) != ':' && *(temp - 2) != ':' && *(temp - 1) != ':'; temp--) {
1602 * gnome_vfs_make_uri_canonical:
1603 * @uri: and absolute or relative URI, it might have scheme.
1605 * Standarizes the format of the uri being passed, so that it can be used
1606 * later in other functions that expect a canonical URI.
1608 * Returns: a newly allocated string that contains the canonical
1609 * representation of @uri.
1615 gnome_vfs_make_uri_canonical (const char *uri)
1617 char *canonical_uri, *old_uri, *p;
1618 gboolean relative_uri;
1620 relative_uri = FALSE;
1626 /* FIXME bugzilla.eazel.com 648:
1627 * This currently ignores the issue of two uris that are not identical but point
1628 * to the same data except for the specific cases of trailing '/' characters,
1629 * file:/ and file:///, and "lack of file:".
1632 canonical_uri = gnome_vfs_handle_trailing_slashes (uri);
1634 /* Note: In some cases, a trailing slash means nothing, and can
1635 * be considered equivalent to no trailing slash. But this is
1636 * not true in every case; specifically not for web addresses passed
1637 * to a web-browser. So we don't have the trailing-slash-equivalence
1638 * logic here, but we do use that logic in EelDirectory where
1639 * the rules are more strict.
1642 /* Add file: if there is no scheme. */
1643 if (strchr (canonical_uri, ':') == NULL) {
1644 old_uri = canonical_uri;
1646 if (old_uri[0] != '/') {
1647 /* FIXME bugzilla.eazel.com 5069:
1648 * bandaid alert. Is this really the right thing to do?
1650 * We got what really is a relative path. We do a little bit of
1651 * a stretch here and assume it was meant to be a cryptic absolute path,
1652 * and convert it to one. Since we can't call gnome_vfs_uri_new and
1653 * gnome_vfs_uri_to_string to do the right make-canonical conversion,
1654 * we have to do it ourselves.
1656 relative_uri = TRUE;
1657 canonical_uri = gnome_vfs_make_path_name_canonical (old_uri);
1659 old_uri = canonical_uri;
1660 canonical_uri = g_strconcat ("file:///", old_uri, NULL);
1662 canonical_uri = g_strconcat ("file:", old_uri, NULL);
1667 /* Lower-case the scheme. */
1668 for (p = canonical_uri; *p != ':'; p++) {
1669 g_assert (*p != '\0');
1670 *p = g_ascii_tolower (*p);
1673 if (!relative_uri) {
1674 old_uri = canonical_uri;
1675 canonical_uri = gnome_vfs_make_uri_canonical_old (canonical_uri);
1676 if (canonical_uri != NULL) {
1679 canonical_uri = old_uri;
1683 /* FIXME bugzilla.eazel.com 2802:
1684 * Work around gnome-vfs's desire to convert file:foo into file://foo
1685 * by converting to file:///foo here. When you remove this, check that
1686 * typing "foo" into location bar does not crash and returns an error
1687 * rather than displaying the contents of /
1689 if (gnome_vfs_str_has_prefix (canonical_uri, "file://")
1690 && !gnome_vfs_str_has_prefix (canonical_uri, "file:///")) {
1691 old_uri = canonical_uri;
1692 canonical_uri = g_strconcat ("file:/", old_uri + 5, NULL);
1696 return canonical_uri;
1700 * gnome_vfs_get_uri_scheme:
1701 * @uri: a stringified URI
1703 * Retrieve the scheme used in @uri
1705 * Return value: A newly allocated string containing the scheme, NULL
1706 * if @uri it doesn't seem to contain a scheme
1712 gnome_vfs_get_uri_scheme (const char *uri)
1716 g_return_val_if_fail (uri != NULL, NULL);
1718 colon = strchr (uri, ':');
1720 if (colon == NULL) {
1724 return g_strndup (uri, colon - uri);
1727 /* Note that NULL's and full paths are also handled by this function.
1728 * A NULL location will return the current working directory
1731 file_uri_from_local_relative_path (const char *location)
1734 char *base_uri, *base_uri_slash;
1735 char *location_escaped;
1738 current_dir = g_get_current_dir ();
1739 base_uri = gnome_vfs_get_uri_from_local_path (current_dir);
1740 /* g_get_current_dir returns w/o trailing / */
1741 base_uri_slash = g_strconcat (base_uri, "/", NULL);
1743 location_escaped = gnome_vfs_escape_path_string (location);
1745 uri = gnome_vfs_uri_make_full_from_relative (base_uri_slash, location_escaped);
1747 g_free (location_escaped);
1748 g_free (base_uri_slash);
1750 g_free (current_dir);
1756 * gnome_vfs_make_uri_from_shell_arg:
1757 * @location: a possibly mangled "uri"
1759 * Similar to gnome_vfs_make_uri_from_input, except that:
1761 * 1) guesses relative paths instead of http domains
1762 * 2) doesn't bother stripping leading/trailing white space
1763 * 3) doesn't bother with ~ expansion--that's done by the shell
1765 * Returns: a newly allocated uri
1771 gnome_vfs_make_uri_from_shell_arg (const char *location)
1775 g_return_val_if_fail (location != NULL, g_strdup (""));
1777 switch (location[0]) {
1779 uri = g_strdup ("");
1782 uri = gnome_vfs_get_uri_from_local_path (location);
1785 if (has_valid_scheme (location)) {
1786 uri = g_strdup (location);
1788 uri = file_uri_from_local_relative_path (location);
1796 * gnome_vfs_make_uri_full_from_relative:
1798 * Returns a full URI given a full base URI, and a secondary URI which may
1801 * This function is deprecated, please use
1802 * gnome_vfs_uri_make_full_from_relative from gnome-vfs-uri.h
1804 * Return value: the URI (NULL for some bad errors).
1810 gnome_vfs_make_uri_full_from_relative (const char *base_uri, const char *relative_uri)
1812 return gnome_vfs_uri_make_full_from_relative (base_uri, relative_uri);
1816 _gnome_vfs_uri_resolve_all_symlinks_uri (GnomeVFSURI *uri,
1817 GnomeVFSURI **result_uri)
1819 GnomeVFSURI *new_uri, *resolved_uri;
1820 GnomeVFSFileInfo *info;
1823 int n_followed_symlinks;
1825 /* Ref the original uri so we don't lose it */
1826 uri = gnome_vfs_uri_ref (uri);
1830 info = gnome_vfs_file_info_new ();
1833 n_followed_symlinks = 0;
1835 while (*p == GNOME_VFS_URI_PATH_CHR)
1837 while (*p != 0 && *p != GNOME_VFS_URI_PATH_CHR)
1840 new_uri = gnome_vfs_uri_dup (uri);
1841 g_free (new_uri->text);
1842 new_uri->text = g_strndup (uri->text, p - uri->text);
1844 gnome_vfs_file_info_clear (info);
1845 res = gnome_vfs_get_file_info_uri (new_uri, info, GNOME_VFS_FILE_INFO_DEFAULT);
1846 if (res != GNOME_VFS_OK) {
1847 gnome_vfs_uri_unref (new_uri);
1850 if (info->type == GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK &&
1851 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SYMLINK_NAME) {
1852 n_followed_symlinks++;
1853 if (n_followed_symlinks > MAX_SYMLINKS_FOLLOWED) {
1854 res = GNOME_VFS_ERROR_TOO_MANY_LINKS;
1855 gnome_vfs_uri_unref (new_uri);
1858 resolved_uri = gnome_vfs_uri_resolve_relative (new_uri,
1859 info->symlink_name);
1861 gnome_vfs_uri_unref (uri);
1862 uri = gnome_vfs_uri_append_path (resolved_uri, p);
1863 gnome_vfs_uri_unref (resolved_uri);
1865 gnome_vfs_uri_unref (uri);
1871 gnome_vfs_uri_unref (new_uri);
1875 *result_uri = gnome_vfs_uri_dup (uri);
1877 gnome_vfs_file_info_unref (info);
1878 gnome_vfs_uri_unref (uri);
1883 _gnome_vfs_uri_resolve_all_symlinks (const char *text_uri,
1884 char **resolved_text_uri)
1886 GnomeVFSURI *uri, *resolved_uri;
1889 *resolved_text_uri = NULL;
1891 uri = gnome_vfs_uri_new (text_uri);
1892 if (uri == NULL || uri->text == NULL) {
1893 return GNOME_VFS_ERROR_NOT_SUPPORTED;
1896 res = _gnome_vfs_uri_resolve_all_symlinks_uri (uri, &resolved_uri);
1898 if (res == GNOME_VFS_OK) {
1899 *resolved_text_uri = gnome_vfs_uri_to_string (resolved_uri, GNOME_VFS_URI_HIDE_NONE);
1900 gnome_vfs_uri_unref (resolved_uri);
1906 _gnome_vfs_uri_is_in_subdir (GnomeVFSURI *uri, GnomeVFSURI *dir)
1908 GnomeVFSFileInfo *dirinfo, *info;
1909 GnomeVFSURI *resolved_dir, *parent, *tmp;
1913 resolved_dir = NULL;
1918 dirinfo = gnome_vfs_file_info_new ();
1919 info = gnome_vfs_file_info_new ();
1921 res = gnome_vfs_get_file_info_uri (dir, dirinfo, GNOME_VFS_FILE_INFO_DEFAULT);
1922 if (res != GNOME_VFS_OK || dirinfo->type != GNOME_VFS_FILE_TYPE_DIRECTORY) {
1926 res = _gnome_vfs_uri_resolve_all_symlinks_uri (dir, &resolved_dir);
1927 if (res != GNOME_VFS_OK) {
1931 res = _gnome_vfs_uri_resolve_all_symlinks_uri (uri, &tmp);
1932 if (res != GNOME_VFS_OK) {
1936 parent = gnome_vfs_uri_get_parent (tmp);
1937 gnome_vfs_uri_unref (tmp);
1939 while (parent != NULL) {
1940 res = gnome_vfs_get_file_info_uri (parent, info, GNOME_VFS_FILE_INFO_DEFAULT);
1941 if (res != GNOME_VFS_OK) {
1945 if (dirinfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_DEVICE &&
1946 dirinfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_INODE &&
1947 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_DEVICE &&
1948 info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_INODE) {
1949 if (dirinfo->device == info->device &&
1950 dirinfo->inode == info->inode) {
1955 if (gnome_vfs_uri_equal (dir, parent)) {
1961 tmp = gnome_vfs_uri_get_parent (parent);
1962 gnome_vfs_uri_unref (parent);
1967 if (resolved_dir != NULL) {
1968 gnome_vfs_uri_unref (resolved_dir);
1970 if (parent != NULL) {
1971 gnome_vfs_uri_unref (parent);
1973 gnome_vfs_file_info_unref (info);
1974 gnome_vfs_file_info_unref (dirinfo);
1979 * gnome_vfs_url_show:
1981 * Launches the default application or component associated with the given url.
1983 * Return value: GNOME_VFS_OK if the default action was launched,
1984 * GNOME_VFS_ERROR_BAD_PARAMETERS for an invalid or non-existant url,
1985 * GNOME_VFS_ERROR_NOT_SUPPORTED if no default action is associated with the URL.
1986 * Also error codes from gnome_vfs_mime_action_launch and
1987 * gnome_vfs_url_show_using_handler for other errors.
1992 gnome_vfs_url_show (const char *url)
1994 return gnome_vfs_url_show_with_env (url, NULL);
1998 * gnome_vfs_url_show_with_env:
2000 * Like gnome_vfs_url_show except that the default action will be launched
2001 * with the given environment.
2003 * Return value: GNOME_VFS_OK if the default action was launched.
2008 gnome_vfs_url_show_with_env (const char *url,
2011 GnomeVFSMimeApplication *app;
2012 GnomeVFSMimeAction *action;
2013 GnomeVFSResult result;
2018 g_return_val_if_fail (url != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
2020 scheme = gnome_vfs_get_uri_scheme (url);
2021 if (scheme == NULL) {
2022 return GNOME_VFS_ERROR_BAD_PARAMETERS;
2025 /* check if this scheme requires special handling */
2026 if (_gnome_vfs_use_handler_for_scheme (scheme)) {
2027 result = _gnome_vfs_url_show_using_handler_with_env (url, envp);
2034 type = gnome_vfs_get_mime_type (url);
2037 return GNOME_VFS_ERROR_BAD_PARAMETERS;
2040 params.data = (char *) url;
2044 app = gnome_vfs_mime_get_default_application (type);
2047 result = gnome_vfs_mime_application_launch_with_env (app, ¶ms, envp);
2048 gnome_vfs_mime_application_free (app);
2053 action = gnome_vfs_mime_get_default_action (type);
2055 if (action != NULL) {
2056 result = gnome_vfs_mime_action_launch_with_env (action, ¶ms, envp);
2057 gnome_vfs_mime_action_free (action);
2063 return GNOME_VFS_ERROR_NO_DEFAULT;