source: trunk/third/gnome-vfs/libgnomevfs/gnome-vfs-utils.c @ 17128

Revision 17128, 23.2 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17127, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3/* gnome-vfs-utils.c - Private utility functions for the GNOME Virtual
4   File System.
5
6   Copyright (C) 1999 Free Software Foundation
7   Copyright (C) 2000, 2001 Eazel, Inc.
8
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.
13
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.
18
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.
23
24   Authors: Ettore Perazzoli <ettore@comm2000.it>
25            John Sullivan <sullivan@eazel.com>
26            Darin Adler <darin@eazel.com>
27*/
28
29#include <config.h>
30
31#ifdef HAVE_SYS_PARAM_H
32#include <sys/param.h>
33#endif
34
35#include "gnome-vfs-utils.h"
36#include "gnome-vfs-private-utils.h"
37#include "gnome-vfs-private.h"
38#include "gnome-vfs.h"
39#include <ctype.h>
40#include <pwd.h>
41#include <stdlib.h>
42#include <string.h>
43#include <sys/stat.h>
44#include <sys/types.h>
45#include <unistd.h>
46
47#if HAVE_SYS_STATVFS_H
48#include <sys/statvfs.h>
49#endif
50
51#if HAVE_SYS_VFS_H
52#include <sys/vfs.h>
53#elif HAVE_SYS_MOUNT_H
54#include <sys/mount.h>
55#endif
56
57#define KILOBYTE_FACTOR 1024.0
58#define MEGABYTE_FACTOR (1024.0 * 1024.0)
59#define GIGABYTE_FACTOR (1024.0 * 1024.0 * 1024.0)
60
61gchar*
62gnome_vfs_format_file_size_for_display (GnomeVFSFileSize bytes)
63{
64        if (bytes < (GnomeVFSFileSize) KILOBYTE_FACTOR) {
65                if (bytes == 1)
66                        return g_strdup (_("1 byte"));
67                else
68                        return g_strdup_printf (_("%u bytes"),
69                                                       (guint) bytes);
70        } else {
71                gdouble displayed_size;
72
73                if (bytes < (GnomeVFSFileSize) MEGABYTE_FACTOR) {
74                        displayed_size = (gdouble) bytes / KILOBYTE_FACTOR;
75                        return g_strdup_printf (_("%.1f K"),
76                                                       displayed_size);
77                } else if (bytes < (GnomeVFSFileSize) GIGABYTE_FACTOR) {
78                        displayed_size = (gdouble) bytes / MEGABYTE_FACTOR;
79                        return g_strdup_printf (_("%.1f MB"),
80                                                       displayed_size);
81                } else {
82                        displayed_size = (gdouble) bytes / GIGABYTE_FACTOR;
83                        return g_strdup_printf (_("%.1f GB"),
84                                                       displayed_size);
85                }
86        }
87}
88
89typedef enum {
90        UNSAFE_ALL        = 0x1,  /* Escape all unsafe characters   */
91        UNSAFE_ALLOW_PLUS = 0x2,  /* Allows '+'  */
92        UNSAFE_PATH       = 0x4,  /* Allows '/' and '?' and '&' and '='  */
93        UNSAFE_DOS_PATH   = 0x8,  /* Allows '/' and '?' and '&' and '=' and ':' */
94        UNSAFE_HOST       = 0x10, /* Allows '/' and ':' and '@' */
95        UNSAFE_SLASHES    = 0x20  /* Allows all characters except for '/' and '%' */
96} UnsafeCharacterSet;
97
98static const guchar acceptable[96] =
99{ /* X0   X1   X2   X3   X4   X5   X6   X7   X8   X9   XA   XB   XC   XD   XE   XF */
100    0x00,0x3F,0x20,0x20,0x20,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x22,0x20,0x3F,0x3F,0x1C, /* 2X  !"#$%&'()*+,-./   */
101    0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x2C, /* 3X 0123456789:;<=>?   */
102    0x30,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* 4X @ABCDEFGHIJKLMNO   */
103    0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, /* 5X PQRSTUVWXYZ[\]^_   */
104    0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* 6X `abcdefghijklmno   */
105    0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20  /* 7X pqrstuvwxyz{|}~DEL */
106};
107
108enum {
109        RESERVED = 1,
110        UNRESERVED,
111        DELIMITERS,
112        UNWISE,
113        CONTROL,
114        SPACE   
115};
116
117static const guchar uri_character_kind[128] =
118{
119    CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,
120    CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,
121    CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,
122    CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,CONTROL   ,
123    /* ' '        !          "          #          $          %          &          '      */
124    SPACE     ,UNRESERVED,DELIMITERS,DELIMITERS,RESERVED  ,DELIMITERS,RESERVED  ,UNRESERVED,
125    /*  (         )          *          +          ,          -          .          /      */
126    UNRESERVED,UNRESERVED,UNRESERVED,RESERVED  ,RESERVED  ,UNRESERVED,UNRESERVED,RESERVED  ,
127    /*  0         1          2          3          4          5          6          7      */
128    UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
129    /*  8         9          :          ;          <          =          >          ?      */
130    UNRESERVED,UNRESERVED,RESERVED  ,RESERVED  ,DELIMITERS,RESERVED  ,DELIMITERS,RESERVED  ,
131    /*  @         A          B          C          D          E          F          G      */
132    RESERVED  ,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
133    /*  H         I          J          K          L          M          N          O      */
134    UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
135    /*  P         Q          R          S          T          U          V          W      */
136    UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
137    /*  X         Y          Z          [          \          ]          ^          _      */
138    UNRESERVED,UNRESERVED,UNRESERVED,UNWISE    ,UNWISE    ,UNWISE    ,UNWISE    ,UNRESERVED,
139    /*  `         a          b          c          d          e          f          g      */
140    UNWISE    ,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
141    /*  h         i          j          k          l          m          n          o      */
142    UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
143    /*  p         q          r          s          t          u          v          w      */
144    UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,UNRESERVED,
145    /*  x         y          z         {           |          }          ~         DEL     */
146    UNRESERVED,UNRESERVED,UNRESERVED,UNWISE    ,UNWISE    ,UNWISE    ,UNRESERVED,CONTROL
147};
148
149
150/*  Below modified from libwww HTEscape.c */
151
152#define HEX_ESCAPE '%'
153
154/*  Escape undesirable characters using %
155 *  -------------------------------------
156 *
157 * This function takes a pointer to a string in which
158 * some characters may be unacceptable unescaped.
159 * It returns a string which has these characters
160 * represented by a '%' character followed by two hex digits.
161 *
162 * This routine returns a g_malloced string.
163 */
164
165static const gchar hex[16] = "0123456789ABCDEF";
166
167static gchar *
168gnome_vfs_escape_string_internal (const gchar *string,
169                                  UnsafeCharacterSet mask)
170{
171#define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
172
173        const gchar *p;
174        gchar *q;
175        gchar *result;
176        guchar c;
177        gint unacceptable;
178        UnsafeCharacterSet use_mask;
179
180        g_return_val_if_fail (mask == UNSAFE_ALL
181                              || mask == UNSAFE_ALLOW_PLUS
182                              || mask == UNSAFE_PATH
183                              || mask == UNSAFE_DOS_PATH
184                              || mask == UNSAFE_HOST
185                              || mask == UNSAFE_SLASHES, NULL);
186
187        if (string == NULL) {
188                return NULL;
189        }
190       
191        unacceptable = 0;
192        use_mask = mask;
193        for (p = string; *p != '\0'; p++) {
194                c = *p;
195                if (!ACCEPTABLE (c)) {
196                        unacceptable++;
197                }
198                if ((use_mask == UNSAFE_HOST) &&
199                    (unacceptable || (c == '/'))) {
200                        /* when escaping a host, if we hit something that needs to be escaped, or we finally
201                         * hit a path separator, revert to path mode (the host segment of the url is over).
202                         */
203                        use_mask = UNSAFE_PATH;
204                }
205        }
206       
207        result = g_malloc (p - string + unacceptable * 2 + 1);
208
209        use_mask = mask;
210        for (q = result, p = string; *p != '\0'; p++){
211                c = *p;
212               
213                if (!ACCEPTABLE (c)) {
214                        *q++ = HEX_ESCAPE; /* means hex coming */
215                        *q++ = hex[c >> 4];
216                        *q++ = hex[c & 15];
217                } else {
218                        *q++ = c;
219                }
220                if ((use_mask == UNSAFE_HOST) &&
221                    (!ACCEPTABLE (c) || (c == '/'))) {
222                        use_mask = UNSAFE_PATH;
223                }
224        }
225       
226        *q = '\0';
227       
228        return result;
229}
230
231gchar *
232gnome_vfs_escape_string (const gchar *file_name)
233{
234        return gnome_vfs_escape_string_internal (file_name, UNSAFE_ALL);
235}
236
237gchar *
238gnome_vfs_escape_path_string (const gchar *path)
239{
240        return gnome_vfs_escape_string_internal (path, UNSAFE_PATH);
241}
242
243gchar *
244gnome_vfs_escape_host_and_path_string (const gchar *path)
245{
246        return gnome_vfs_escape_string_internal (path, UNSAFE_HOST);
247}
248
249gchar *
250gnome_vfs_escape_slashes (const gchar *string)
251{
252        return gnome_vfs_escape_string_internal (string, UNSAFE_SLASHES);
253}
254
255char *
256gnome_vfs_escape_set (const char *string,
257                      const char *match_set)
258{
259        char *result;
260        const char *scanner;
261        char *result_scanner;
262        int escape_count;
263
264        escape_count = 0;
265
266        if (string == NULL) {
267                return NULL;
268        }
269
270        if (match_set == NULL) {
271                return g_strdup (string);
272        }
273       
274        for (scanner = string; *scanner != '\0'; scanner++) {
275                if (strchr(match_set, *scanner) != NULL) {
276                        /* this character is in the set of characters
277                         * we want escaped.
278                         */
279                        escape_count++;
280                }
281        }
282       
283        if (escape_count == 0) {
284                return g_strdup (string);
285        }
286
287        /* allocate two extra characters for every character that
288         * needs escaping and space for a trailing zero
289         */
290        result = g_malloc (scanner - string + escape_count * 2 + 1);
291        for (scanner = string, result_scanner = result; *scanner != '\0'; scanner++) {
292                if (strchr(match_set, *scanner) != NULL) {
293                        /* this character is in the set of characters
294                         * we want escaped.
295                         */
296                        *result_scanner++ = HEX_ESCAPE;
297                        *result_scanner++ = hex[*scanner >> 4];
298                        *result_scanner++ = hex[*scanner & 15];
299                       
300                } else {
301                        *result_scanner++ = *scanner;
302                }
303        }
304
305        *result_scanner = '\0';
306
307        return result;
308}
309
310char *
311gnome_vfs_expand_initial_tilde (const char *path)
312{
313        char *slash_after_user_name, *user_name;
314        struct passwd *passwd_file_entry;
315
316        g_return_val_if_fail (path != NULL, NULL);
317
318        if (path[0] != '~') {
319                return g_strdup (path);
320        }
321       
322        if (path[1] == '/' || path[1] == '\0') {
323                return g_strconcat (g_get_home_dir (), &path[1], NULL);
324        }
325
326        slash_after_user_name = strchr (&path[1], '/');
327        if (slash_after_user_name == NULL) {
328                user_name = g_strdup (&path[1]);
329        } else {
330                user_name = g_strndup (&path[1],
331                                       slash_after_user_name - &path[1]);
332        }
333        passwd_file_entry = getpwnam (user_name);
334        g_free (user_name);
335
336        if (passwd_file_entry == NULL || passwd_file_entry->pw_dir == NULL) {
337                return g_strdup (path);
338        }
339
340        return g_strconcat (passwd_file_entry->pw_dir,
341                            slash_after_user_name,
342                            NULL);
343}
344
345static int
346hex_to_int (gchar c)
347{
348        return  c >= '0' && c <= '9' ? c - '0'
349                : c >= 'A' && c <= 'F' ? c - 'A' + 10
350                : c >= 'a' && c <= 'f' ? c - 'a' + 10
351                : -1;
352}
353
354static int
355unescape_character (const char *scanner)
356{
357        int first_digit;
358        int second_digit;
359
360        first_digit = hex_to_int (*scanner++);
361        if (first_digit < 0) {
362                return -1;
363        }
364
365        second_digit = hex_to_int (*scanner++);
366        if (second_digit < 0) {
367                return -1;
368        }
369
370        return (first_digit << 4) | second_digit;
371}
372
373/*  Decode %xx escaped characters
374**  -----------------------------
375**
376** This function takes a pointer to a string in which some
377** characters may have been encoded in %xy form, where xy is
378** the ASCII hex code for character 16x+y.
379*/
380
381gchar *
382gnome_vfs_unescape_string (const gchar *escaped, const gchar *illegal_characters)
383{
384        const gchar *in;
385        gchar *out, *result;
386        gint character;
387       
388        if (escaped == NULL) {
389                return NULL;
390        }
391
392        result = g_malloc (strlen (escaped) + 1);
393       
394        out = result;
395        for (in = escaped; *in != '\0'; in++) {
396                character = *in;
397                if (*in == HEX_ESCAPE) {
398                        character = unescape_character (in + 1);
399
400                        /* Check for an illegal character. We consider '\0' illegal here. */
401                        if (character <= 0
402                            || (illegal_characters != NULL
403                                && strchr (illegal_characters, (char)character) != NULL)) {
404                                g_free (result);
405                                return NULL;
406                        }
407                        in += 2;
408                }
409                *out++ = (char)character;
410        }
411       
412        *out = '\0';
413        g_assert (out - result <= strlen (escaped));
414        return result;
415       
416}
417
418/**
419 * gnome_vfs_unescape_for_display:
420 * @escaped: The string encoded with escaped sequences
421 *
422 * Similar to gnome_vfs_unescape_string, but it returns something
423 * semi-intelligable to a user even upon receiving traumatic input
424 * such as %00 or URIs in bad form.
425 *
426 * See also: gnome_vfs_unescape_string.
427 *
428 * Return value: A pointer to a g_malloc'd string with all characters
429 *               replacing their escaped hex values
430 *
431 * WARNING: You should never use this function on a whole URI!  It
432 * unescapes reserved characters, and can result in a mangled URI
433 * that can not be re-entered.  For example, it unescapes "#" "&" and "?",
434 * which have special meanings in URI strings.
435 **/
436gchar *
437gnome_vfs_unescape_string_for_display (const gchar *escaped)
438{
439        const gchar *in, *start_escape;
440        gchar *out, *result;
441        gint i,j;
442        gchar c;
443        gint invalid_escape;
444
445        if (escaped == NULL) {
446                return NULL;
447        }
448
449        result = g_malloc (strlen (escaped) + 1);
450       
451        out = result;
452        for (in = escaped; *in != '\0'; ) {
453                start_escape = in;
454                c = *in++;
455                invalid_escape = 0;
456               
457                if (c == HEX_ESCAPE) {
458                        /* Get the first hex digit. */
459                        i = hex_to_int (*in++);
460                        if (i < 0) {
461                                invalid_escape = 1;
462                                in--;
463                        }
464                        c = i << 4;
465                       
466                        if (invalid_escape == 0) {
467                                /* Get the second hex digit. */
468                                i = hex_to_int (*in++);
469                                if (i < 0) {
470                                        invalid_escape = 2;
471                                        in--;
472                                }
473                                c |= i;
474                        }
475                        if (invalid_escape == 0) {
476                                /* Check for an illegal character. */
477                                if (c == '\0') {
478                                        invalid_escape = 3;
479                                }
480                        }
481                }
482                if (invalid_escape != 0) {
483                        for (j = 0; j < invalid_escape; j++) {
484                                *out++ = *start_escape++;
485                        }
486                } else {
487                        *out++ = c;
488                }
489        }
490       
491        *out = '\0';
492        g_assert (out - result <= strlen (escaped));
493        return result;
494}
495
496/**
497 * gnome_vfs_remove_optional_escapes:
498 * @uri: an escaped uri
499 *
500 * Scans the uri and converts characters that do not have to be
501 * escaped into an un-escaped form. The characters that get treated this
502 * way are defined as unreserved by the RFC.
503 *
504 * Return value: an error value if the uri is found to be malformed.
505 **/
506GnomeVFSResult
507gnome_vfs_remove_optional_escapes (char *uri)
508{
509        guchar *scanner;
510        int character;
511        int length;
512
513        if (uri == NULL) {
514                return GNOME_VFS_OK;
515        }
516       
517        length = strlen (uri);
518
519        for (scanner = uri; *scanner != '\0'; scanner++, length--) {
520                if (*scanner == HEX_ESCAPE) {
521                        character = unescape_character (scanner + 1);
522                        if (character < 0) {
523                                /* invalid hexadecimal character */
524                                return GNOME_VFS_ERROR_INVALID_URI;
525                        }
526
527                        if (uri_character_kind [character] == UNRESERVED) {
528                                /* This character does not need to be escaped, convert it
529                                 * to a non-escaped form.
530                                 */
531                                *scanner = (guchar)character;
532                                g_assert (length >= 3);
533
534                                /* Shrink the string covering up the two extra digits of the
535                                 * escaped character. Include the trailing '\0' in the copy
536                                 * to keep the string terminated.
537                                 */
538                                memmove (scanner + 1, scanner + 3, length - 2);
539                        } else {
540                                /* This character must stay escaped, skip the entire
541                                 * escaped sequence
542                                 */
543                                scanner += 2;
544                        }
545                        length -= 2;
546
547                } else if (*scanner > 127
548                        || uri_character_kind [*scanner] == DELIMITERS
549                        || uri_character_kind [*scanner] == UNWISE
550                        || uri_character_kind [*scanner] == CONTROL) {
551                        /* It is illegal for this character to be in an un-escaped form
552                         * in the uri.
553                         */
554                        return GNOME_VFS_ERROR_INVALID_URI;
555                }
556        }
557        return GNOME_VFS_OK;
558}
559
560char *
561gnome_vfs_make_uri_canonical (const char *original_uri_text)
562{
563        /* For now use a sub-optimal implementation involving a
564         * conversion to GnomeVFSURI and back.
565         */
566        GnomeVFSURI *uri;
567        char *result;
568
569        uri = gnome_vfs_uri_new_private (original_uri_text, TRUE, TRUE, FALSE);
570        if (uri == NULL) {
571                return NULL;;
572        }
573
574        result = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
575        gnome_vfs_uri_unref (uri);
576
577        return result;
578}
579
580
581/**
582 * gnome_vfs_make_canonical_pathname:
583 * @path: a file path, relative or absolute
584 *
585 * Calls gnome_vfs_canonicalize_pathname, allocating storage for the result and
586 * providing for a cleaner memory management.
587 *
588 * Return value: a canonical version of @path
589 **/
590gchar *
591gnome_vfs_make_path_name_canonical (const gchar *path)
592{
593        char *path_clone;
594        char *result;
595
596        path_clone = g_strdup (path);
597        result = gnome_vfs_canonicalize_pathname (path_clone);
598        if (result != path_clone) {
599                g_free (path_clone);
600                return g_strdup (result);
601        }
602
603        return path_clone;
604}
605
606void
607gnome_vfs_list_deep_free (GList *list)
608{
609        GList *p;
610
611        if (list == NULL)
612                return;
613
614        for (p = list; p != NULL; p = p->next) {
615                g_free (p->data);
616        }
617        g_list_free (list);
618}
619
620/**
621 * gnome_vfs_get_local_path_from_uri:
622 *
623 * Return a local path for a file:/// URI.
624 *
625 * Return value: the local path
626 * NULL is returned on error or if the uri isn't a file: URI
627 * without a fragment identifier (or chained URI).
628 **/
629char *
630gnome_vfs_get_local_path_from_uri (const char *uri)
631{
632        const char *path_part;
633
634        if (!gnome_vfs_istr_has_prefix (uri, "file:/")) {
635                return NULL;
636        }
637       
638        path_part = uri + strlen ("file:");
639        if (strchr (path_part, '#') != NULL) {
640                return NULL;
641        }
642       
643        if (gnome_vfs_istr_has_prefix (path_part, "///")) {
644                path_part += 2;
645        } else if (gnome_vfs_istr_has_prefix (path_part, "//")) {
646                return NULL;
647        }
648
649        return gnome_vfs_unescape_string (path_part, "/");
650}
651
652/**
653 * gnome_vfs_get_uri_from_local_path:
654 *
655 * Return a file:/// URI for a local path.
656 *
657 * Return value: the URI (NULL for some bad errors).
658 **/
659char *
660gnome_vfs_get_uri_from_local_path (const char *local_path)
661{
662        char *escaped_path, *result;
663       
664        if (local_path == NULL) {
665                return NULL;
666        }
667
668        g_return_val_if_fail (local_path[0] == '/', NULL);
669
670        escaped_path = gnome_vfs_escape_path_string (local_path);
671        result = g_strconcat ("file://", escaped_path, NULL);
672        g_free (escaped_path);
673        return result;
674}
675
676/* gnome_vfs_get_volume_free_space
677 *
678 * Return total amount of free space on a volume.
679 * This only works for local file systems with
680 * the file: scheme.
681 */
682GnomeVFSResult
683gnome_vfs_get_volume_free_space (const GnomeVFSURI *vfs_uri, GnomeVFSFileSize *size)
684{       
685        GnomeVFSFileSize free_blocks, block_size;
686        int statfs_result;
687        const char *path, *scheme;
688        char *unescaped_path;
689        GnomeVFSResult ret;
690#if HAVE_STATVFS
691        struct statvfs statfs_buffer;
692#else
693        struct statfs statfs_buffer;
694#endif
695
696        *size = 0;
697
698        /* We can't check non local systems */
699        if (!gnome_vfs_uri_is_local (vfs_uri)) {
700                return GNOME_VFS_ERROR_NOT_SUPPORTED;
701        }
702
703        path = gnome_vfs_uri_get_path (vfs_uri);
704
705        unescaped_path = gnome_vfs_unescape_string (path, G_DIR_SEPARATOR_S);
706       
707        scheme = gnome_vfs_uri_get_scheme (vfs_uri);
708       
709        /* We only handle the file scheme for now */
710        if (g_strcasecmp (scheme, "file") != 0 || !gnome_vfs_istr_has_prefix (path, "/")) {
711                return GNOME_VFS_ERROR_NOT_SUPPORTED;
712        }
713
714#if HAVE_STATVFS
715        statfs_result = statvfs (unescaped_path, &statfs_buffer);
716#else
717        statfs_result = statfs (unescaped_path, &statfs_buffer);   
718#endif 
719
720        if (statfs_result == 0) {
721                ret = GNOME_VFS_OK;
722        } else {
723                ret = gnome_vfs_result_from_errno ();
724        }
725       
726        g_return_val_if_fail (statfs_result == 0, FALSE);
727        block_size = statfs_buffer.f_bsize;
728        free_blocks = statfs_buffer.f_bavail;
729
730        *size = block_size * free_blocks;
731
732        g_free (unescaped_path);
733       
734        return ret;
735}
736
737/**
738 * hack_file_exists
739 * @filename: pathname to test for existance.
740 *
741 * Returns true if filename exists
742 */
743/* FIXME: Why is this here? Why not use g_file_exists in libgnome/gnome-util.h?
744 * (I tried to simply replace but there were strange include dependencies, maybe
745 * that's why this function exists.)
746 */
747static int
748hack_file_exists (const char *filename)
749{
750        struct stat s;
751
752        g_return_val_if_fail (filename != NULL,FALSE);
753   
754        return stat (filename, &s) == 0;
755}
756
757
758char *
759gnome_vfs_icon_path_from_filename (const char *relative_filename)
760{
761        const char *gnome_var;
762        char *full_filename;
763        char **paths, **temp_paths;
764
765        gnome_var = g_getenv ("GNOME_PATH");
766
767        if (gnome_var == NULL) {
768                gnome_var = GNOME_VFS_PREFIX;
769        }
770
771        paths = g_strsplit (gnome_var, ":", 0);
772
773        for (temp_paths = paths; *temp_paths != NULL; temp_paths++) {
774                full_filename = g_strconcat (*temp_paths, "/share/pixmaps/", relative_filename, NULL);
775                if (hack_file_exists (full_filename)) {
776                        g_strfreev (paths);
777                        return full_filename;
778                }
779                g_free (full_filename);
780                full_filename = NULL;
781        }
782
783        g_strfreev (paths);
784        return NULL;
785}
786
787
788static char *
789strdup_to (const char *string, const char *end)
790{
791        if (end == NULL) {
792                return g_strdup (string);
793        }
794        return g_strndup (string, end - string);
795}
796
797static gboolean
798is_executable_file (const char *path)
799{
800        struct stat stat_buffer;
801
802        /* Check that it exists. */
803        if (stat (path, &stat_buffer) != 0) {
804                return FALSE;
805        }
806
807        /* Check that it is a file. */
808        if (!S_ISREG (stat_buffer.st_mode)) {
809                return FALSE;
810        }
811
812        /* Check that it's executable. */
813        if (access (path, X_OK) != 0) {
814                return FALSE;
815        }
816
817        return TRUE;
818}
819
820
821static gboolean
822executable_in_path (const char *executable_name)
823{
824        const char *path_list, *piece_start, *piece_end;
825        char *piece, *raw_path, *expanded_path;
826        gboolean is_good;
827
828        path_list = g_getenv ("PATH");
829
830        for (piece_start = path_list; ; piece_start = piece_end + 1) {
831                /* Find the next piece of PATH. */
832                piece_end = strchr (piece_start, ':');
833                piece = strdup_to (piece_start, piece_end);
834                g_strstrip (piece);
835               
836                if (piece[0] == '\0') {
837                        is_good = FALSE;
838                } else {
839                        /* Try out this path with the executable. */
840                        raw_path = g_strconcat (piece, "/", executable_name, NULL);
841                        expanded_path = gnome_vfs_expand_initial_tilde (raw_path);
842                        g_free (raw_path);
843                       
844                        is_good = is_executable_file (expanded_path);
845                        g_free (expanded_path);
846                }
847               
848                g_free (piece);
849               
850                if (is_good) {
851                        return TRUE;
852                }
853
854                if (piece_end == NULL) {
855                        return FALSE;
856                }
857        }
858}
859
860static char *
861get_executable_name_from_command_string (const char *command_string)
862{
863        /* FIXME bugzilla.eazel.com 2757:
864         * We need to handle quoting here for the full-path case */
865        return g_strstrip (strdup_to (command_string, strchr (command_string, ' ')));
866}
867
868/* Returns TRUE if commmand_string starts with the full path for an executable
869 * file, or starts with a command for an executable in $PATH.
870 */
871gboolean
872gnome_vfs_is_executable_command_string (const char *command_string)
873{
874        char *executable_name;
875        char *executable_path;
876        gboolean found;
877
878        /* Check whether command_string is a full path for an executable. */
879        if (command_string[0] == '/') {
880
881                /* FIXME bugzilla.eazel.com 2757:
882                 * Because we don't handle quoting, we can check for full
883                 * path including spaces, but no parameters, and full path
884                 * with no spaces with or without parameters. But this will
885                 * fail for quoted full path with spaces, and parameters.
886                 */
887
888                /* This works if command_string contains a space, but not
889                 * if command_string has parameters.
890                 */
891                if (is_executable_file (command_string)) {
892                        return TRUE;
893                }
894
895                /* This works if full path has no spaces, with or without parameters */
896                executable_path = get_executable_name_from_command_string (command_string);
897                found = is_executable_file (executable_path);
898                g_free (executable_path);
899
900                return found;
901        }
902       
903        executable_name = get_executable_name_from_command_string (command_string);
904        found = executable_in_path (executable_name);
905        g_free (executable_name);
906
907        return found;
908}
Note: See TracBrowser for help on using the repository browser.