Bug Summary

File:file-utils.c
Warning:line 624, column 52
Access to field 'message' results in a dereference of a null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name file-utils.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -I .. -I .. -D GRAPA_RESOURCE_UI_PATH="/org/cafe/Grapa/ui" -D FR_PREFIX="/usr" -D FR_SYSCONFDIR="/usr/etc" -D FR_DATADIR="/usr/share" -D PRIVDATADIR="/usr/share/grapa/" -D FR_LIBDIR="/usr/lib" -D PKG_DATA_DIR="/usr/share/grapa" -D PIXMAPSDIR="/usr/share/pixmaps" -D GLADEDIR="" -D LOCALEDIR="/usr/share/locale" -D SHDIR="/usr/libexec/grapa/" -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/gio-unix-2.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/json-glib-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-08-12-174805-49809-1 -x c file-utils.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3/*
4 * Grapa
5 *
6 * Copyright (C) 2001, 2003 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#define _XOPEN_SOURCE700 700
24
25#include <config.h>
26#include <pwd.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <strings.h>
31#include <ctype.h>
32#include <time.h>
33#include <unistd.h>
34#include <sys/param.h>
35#include <sys/stat.h>
36#include <sys/time.h>
37#include <sys/types.h>
38#include <dirent.h>
39
40#include <glib.h>
41#include <gio/gio.h>
42#include "file-utils.h"
43#include "glib-utils.h"
44#include "fr-init.h"
45
46
47#define SPECIAL_DIR(x)((strcmp ((x), "..") == 0) || (strcmp ((x), ".") == 0)) ((strcmp ((x), "..") == 0) || (strcmp ((x), ".") == 0))
48
49
50gboolean
51uri_exists (const char *uri)
52{
53 GFile *file;
54 gboolean exists;
55
56 if (uri == NULL((void*)0))
57 return FALSE(0);
58
59 file = g_file_new_for_uri (uri);
60 exists = g_file_query_exists (file, NULL((void*)0));
61 g_object_unref (file);
62
63 return exists;
64}
65
66
67static gboolean
68uri_is_filetype (const char *uri,
69 GFileType file_type)
70{
71 gboolean result = FALSE(0);
72 GFile *file;
73 GFileInfo *info;
74 GError *error = NULL((void*)0);
75
76 file = g_file_new_for_uri (uri);
77
78 if (! g_file_query_exists (file, NULL((void*)0))) {
79 g_object_unref (file);
80 return FALSE(0);
81 }
82
83 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type", 0, NULL((void*)0), &error);
84 if (error == NULL((void*)0)) {
85 result = (g_file_info_get_file_type (info) == file_type);
86 }
87 else {
88 g_warning ("Failed to get file type for uri %s: %s", uri, error->message);
89 g_error_free (error);
90 }
91
92 g_object_unref (info);
93 g_object_unref (file);
94
95 return result;
96}
97
98
99gboolean
100uri_is_file (const char *uri)
101{
102 return uri_is_filetype (uri, G_FILE_TYPE_REGULAR);
103}
104
105
106gboolean
107uri_is_dir (const char *uri)
108{
109 return uri_is_filetype (uri, G_FILE_TYPE_DIRECTORY);
110}
111
112
113gboolean
114path_is_dir (const char *path)
115{
116 char *uri;
117 gboolean result;
118
119 uri = g_filename_to_uri (path, NULL((void*)0), NULL((void*)0));
120 result = uri_is_dir (uri);
121 g_free (uri);
122
123 return result;
124}
125
126gboolean
127uri_is_local (const char *uri)
128{
129 return strncmp (uri, "file://", 7) == 0;
130}
131
132
133gboolean
134dir_is_empty (const char *uri)
135{
136 GFile *file;
137 GFileEnumerator *file_enum;
138 GFileInfo *info;
139 GError *error = NULL((void*)0);
140 int n = 0;
141
142 file = g_file_new_for_uri (uri);
143
144 if (! g_file_query_exists (file, NULL((void*)0))) {
145 g_object_unref (file);
146 return TRUE(!(0));
147 }
148
149 file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name", 0, NULL((void*)0), &error);
150 if (error != NULL((void*)0)) {
151 g_warning ("Failed to enumerate children of %s: %s", uri, error->message);
152 g_error_free (error);
153 g_object_unref (file_enum);
154 g_object_unref (file);
155 return TRUE(!(0));
156 }
157
158 while ((n == 0) && ((info = g_file_enumerator_next_file (file_enum, NULL((void*)0), &error)) != NULL((void*)0))) {
159 if (error != NULL((void*)0)) {
160 g_warning ("Encountered error while enumerating children of %s (ignoring): %s", uri, error->message);
161 g_error_free (error);
162 }
163 else if (! SPECIAL_DIR (g_file_info_get_name (info))((strcmp ((g_file_info_get_name (info)), "..") == 0) || (strcmp
((g_file_info_get_name (info)), ".") == 0))
)
164 n++;
165 g_object_unref (info);
166 }
167
168 g_object_unref (file);
169 g_object_unref (file_enum);
170
171 return (n == 0);
172}
173
174
175gboolean
176dir_contains_one_object (const char *uri)
177{
178 GFile *file;
179 GFileEnumerator *file_enum;
180 GFileInfo *info;
181 GError *err = NULL((void*)0);
182 int n = 0;
183
184 file = g_file_new_for_uri (uri);
185
186 if (! g_file_query_exists (file, NULL((void*)0))) {
187 g_object_unref (file);
188 return FALSE(0);
189 }
190
191 file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name", 0, NULL((void*)0), &err);
192 if (err != NULL((void*)0)) {
193 g_warning ("Failed to enumerate children of %s: %s", uri, err->message);
194 g_error_free (err);
195 g_object_unref (file_enum);
196 g_object_unref (file);
197 return FALSE(0);
198 }
199
200 while ((info = g_file_enumerator_next_file (file_enum, NULL((void*)0), &err)) != NULL((void*)0)) {
201 const char *name;
202
203 if (err != NULL((void*)0)) {
204 g_warning ("Encountered error while enumerating children of %s, ignoring: %s", uri, err->message);
205 g_error_free (err);
206 g_object_unref (info);
207 continue;
208 }
209
210 name = g_file_info_get_name (info);
211 if (strcmp (name, ".") == 0 || strcmp (name, "..") == 0) {
212 g_object_unref (info);
213 continue;
214 }
215
216 g_object_unref (info);
217
218 if (++n > 1)
219 break;
220 }
221
222 g_object_unref (file);
223 g_object_unref (file_enum);
224
225 return (n == 1);
226}
227
228
229char *
230get_dir_content_if_unique (const char *uri)
231{
232 GFile *file;
233 GFileEnumerator *file_enum;
234 GFileInfo *info;
235 GError *err = NULL((void*)0);
236 char *content_uri = NULL((void*)0);
237
238 file = g_file_new_for_uri (uri);
239
240 if (! g_file_query_exists (file, NULL((void*)0))) {
241 g_object_unref (file);
242 return NULL((void*)0);
243 }
244
245 file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name", 0, NULL((void*)0), &err);
246 if (err != NULL((void*)0)) {
247 g_warning ("Failed to enumerate children of %s: %s", uri, err->message);
248 g_error_free (err);
249 return NULL((void*)0);
250 }
251
252 while ((info = g_file_enumerator_next_file (file_enum, NULL((void*)0), &err)) != NULL((void*)0)) {
253 const char *name;
254
255 if (err != NULL((void*)0)) {
256 g_warning ("Failed to get info while enumerating children: %s", err->message);
257 g_clear_error (&err);
258 g_object_unref (info);
259 continue;
260 }
261
262 name = g_file_info_get_name (info);
263 if ((strcmp (name, ".") == 0) || (strcmp (name, "..") == 0)) {
264 g_object_unref (info);
265 continue;
266 }
267
268 if (content_uri != NULL((void*)0)) {
269 g_free (content_uri);
270 g_object_unref (info);
271 content_uri = NULL((void*)0);
272 break;
273 }
274
275 content_uri = build_uri (uri, name, NULL((void*)0));
276 g_object_unref (info);
277 }
278
279 if (err != NULL((void*)0)) {
280 g_warning ("Failed to get info after enumerating children: %s", err->message);
281 g_clear_error (&err);
282 }
283
284 g_object_unref (file_enum);
285 g_object_unref (file);
286
287 return content_uri;
288}
289
290
291/* Check whether the dirname is contained in filename */
292gboolean
293path_in_path (const char *dirname,
294 const char *filename)
295{
296 int dirname_l, filename_l, separator_position;
297
298 if ((dirname == NULL((void*)0)) || (filename == NULL((void*)0)))
299 return FALSE(0);
300
301 dirname_l = strlen (dirname);
302 filename_l = strlen (filename);
303
304 if ((dirname_l == filename_l + 1)
305 && (dirname[dirname_l - 1] == '/'))
306 return FALSE(0);
307
308 if ((filename_l == dirname_l + 1)
309 && (filename[filename_l - 1] == '/'))
310 return FALSE(0);
311
312 if (dirname[dirname_l - 1] == '/')
313 separator_position = dirname_l - 1;
314 else
315 separator_position = dirname_l;
316
317 return ((filename_l > dirname_l)
318 && (strncmp (dirname, filename, dirname_l) == 0)
319 && (filename[separator_position] == '/'));
320}
321
322
323goffset
324get_file_size (const char *uri)
325{
326 goffset size = 0;
327 GFile *file;
328 GFileInfo *info;
329 GError *err = NULL((void*)0);
330
331 if ((uri == NULL((void*)0)) || (*uri == '\0'))
332 return 0;
333
334 file = g_file_new_for_uri (uri);
335 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE"standard::size", 0, NULL((void*)0), &err);
336 if (err == NULL((void*)0)) {
337 size = g_file_info_get_size (info);
338 }
339 else {
340 g_warning ("Failed to get file size for %s: %s", uri, err->message);
341 g_error_free (err);
342 }
343
344 g_object_unref (info);
345 g_object_unref (file);
346
347 return size;
348}
349
350
351goffset
352get_file_size_for_path (const char *path)
353{
354 char *uri;
355 goffset result;
356
357 uri = g_filename_to_uri (path, NULL((void*)0), NULL((void*)0));
358 result = get_file_size (uri);
359 g_free (uri);
360
361 return result;
362}
363
364
365static time_t
366get_file_time_type (const char *uri,
367 const char *type)
368{
369 time_t result = 0;
370 GFile *file;
371 GFileInfo *info;
372 GError *err = NULL((void*)0);
373
374 if ((uri == NULL((void*)0)) || (*uri == '\0'))
375 return 0;
376
377 file = g_file_new_for_uri (uri);
378 info = g_file_query_info (file, type, 0, NULL((void*)0), &err);
379 if (err == NULL((void*)0)) {
380 result = (time_t) g_file_info_get_attribute_uint64 (info, type);
381 }
382 else {
383 g_warning ("Failed to get %s: %s", type, err->message);
384 g_error_free (err);
385 result = 0;
386 }
387
388 g_object_unref (info);
389 g_object_unref (file);
390
391 return result;
392}
393
394
395time_t
396get_file_mtime (const char *uri)
397{
398 return get_file_time_type (uri, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
399}
400
401
402time_t
403get_file_mtime_for_path (const char *path)
404{
405 char *uri;
406 time_t result;
407
408 uri = g_filename_to_uri (path, NULL((void*)0), NULL((void*)0));
409 result = get_file_mtime (uri);
410 g_free (uri);
411
412 return result;
413}
414
415
416time_t
417get_file_ctime (const char *uri)
418{
419 return get_file_time_type (uri, G_FILE_ATTRIBUTE_TIME_CREATED"time::created");
420}
421
422
423gboolean
424file_is_hidden (const gchar *name)
425{
426 if (name[0] != '.') return FALSE(0);
427 if (name[1] == '\0') return FALSE(0);
428 if ((name[1] == '.') && (name[2] == '\0')) return FALSE(0);
429
430 return TRUE(!(0));
431}
432
433
434/* like g_path_get_basename but does not warn about NULL and does not
435 * alloc a new string. */
436const gchar* file_name_from_path(const gchar *file_name)
437{
438 register char *base;
439 register gssize last_char;
440
441 if (file_name == NULL((void*)0))
442 return NULL((void*)0);
443
444 if ((file_name[0] == '\0') || (strlen (file_name) == 0))
445 return "";
446
447 last_char = strlen (file_name) - 1;
448
449 if (file_name [last_char] == G_DIR_SEPARATOR'/')
450 return "";
451
452 base = g_utf8_strrchr (file_name, -1, G_DIR_SEPARATOR'/');
453 if (! base)
454 return file_name;
455
456 return base + 1;
457}
458
459
460char *
461dir_name_from_path (const gchar *path)
462{
463 register gssize base;
464 register gssize last_char;
465
466 if (path == NULL((void*)0))
467 return NULL((void*)0);
468
469 if (path[0] == '\0')
470 return g_strdup ("")g_strdup_inline ("");
471
472 last_char = strlen (path) - 1;
473 if (path[last_char] == G_DIR_SEPARATOR'/')
474 last_char--;
475
476 base = last_char;
477 while ((base >= 0) && (path[base] != G_DIR_SEPARATOR'/'))
478 base--;
479
480 return g_strndup (path + base + 1, last_char - base);
481}
482
483
484gchar *
485remove_level_from_path (const gchar *path)
486{
487 int p;
488 const char *ptr = path;
489 char *new_path;
490
491 if (path == NULL((void*)0))
492 return NULL((void*)0);
493
494 p = strlen (path) - 1;
495 if (p < 0)
496 return NULL((void*)0);
497
498 while ((p > 0) && (ptr[p] != '/'))
499 p--;
500 if ((p == 0) && (ptr[p] == '/'))
501 p++;
502 new_path = g_strndup (path, (guint)p);
503
504 return new_path;
505}
506
507
508char *
509remove_ending_separator (const char *path)
510{
511 gint len, copy_len;
512
513 if (path == NULL((void*)0))
514 return NULL((void*)0);
515
516 copy_len = len = strlen (path);
517 if ((len > 1) && (path[len - 1] == '/'))
518 copy_len--;
519
520 return g_strndup (path, copy_len);
521}
522
523
524char *
525build_uri (const char *base, ...)
526{
527 va_list args;
528 const char *child;
529 GString *uri;
530
531 uri = g_string_new (base);
532
533 va_start (args, base)__builtin_va_start(args, base);
534 while ((child = va_arg (args, const char *)__builtin_va_arg(args, const char *)) != NULL((void*)0)) {
535 if (! g_str_has_suffix (uri->str, "/")(__builtin_constant_p ("/")? __extension__ ({ const char * const
__str = (uri->str); const char * const __suffix = ("/"); gboolean
__result = (0); if (__str == ((void*)0) || __suffix == ((void
*)0)) __result = (g_str_has_suffix) (__str, __suffix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if
(__str_len >= __suffix_len) __result = memcmp (__str + __str_len
- __suffix_len, ((__suffix) + !(__suffix)), __suffix_len) ==
0; } __result; }) : (g_str_has_suffix) (uri->str, "/") )
&& ! g_str_has_prefix (child, "/")(__builtin_constant_p ("/")? __extension__ ({ const char * const
__str = (child); const char * const __prefix = ("/"); gboolean
__result = (0); if (__str == ((void*)0) || __prefix == ((void
*)0)) __result = (g_str_has_prefix) (__str, __prefix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if
(__str_len >= __prefix_len) __result = memcmp (((__str) +
!(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0; }
__result; }) : (g_str_has_prefix) (child, "/") )
)
536 g_string_append (uri, "/")(__builtin_constant_p ("/") ? __extension__ ({ const char * const
__val = ("/"); g_string_append_len_inline (uri, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (uri, "/", (gssize) -1
))
;
537 g_string_append (uri, child)(__builtin_constant_p (child) ? __extension__ ({ const char *
const __val = (child); g_string_append_len_inline (uri, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (uri, child
, (gssize) -1))
;
538 }
539 va_end (args)__builtin_va_end(args);
540
541 return g_string_free (uri, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((uri)
, ((0))) : g_string_free_and_steal (uri)) : (g_string_free) (
(uri), ((0))))
;
542}
543
544
545gchar *
546remove_extension_from_path (const gchar *path)
547{
548 int len;
549 int p;
550 const char *ptr = path;
551 char *new_path;
552
553 if (! path)
554 return NULL((void*)0);
555
556 len = strlen (path);
557 if (len == 1)
558 return g_strdup (path)g_strdup_inline (path);
559
560 p = len - 1;
561 while ((p > 0) && (ptr[p] != '.'))
562 p--;
563 if (p == 0)
564 p = len;
565 new_path = g_strndup (path, (guint) p);
566
567 return new_path;
568}
569
570
571gboolean
572make_directory_tree (GFile *dir,
573 mode_t mode,
574 GError **error)
575{
576 gboolean success = TRUE(!(0));
577 GFile *parent;
578
579 if ((dir == NULL((void*)0)) || g_file_query_exists (dir, NULL((void*)0)))
7
Assuming 'dir' is not equal to NULL
8
Assuming the condition is false
9
Taking false branch
580 return TRUE(!(0));
581
582 parent = g_file_get_parent (dir);
583 if (parent != NULL((void*)0)) {
10
Assuming 'parent' is equal to NULL
11
Taking false branch
584 success = make_directory_tree (parent, mode, error);
585 g_object_unref (parent);
586 if (! success)
587 return FALSE(0);
588 }
589
590 success = g_file_make_directory (dir, NULL((void*)0), error);
12
Assigning value
591 if ((error
12.1
'error' is not equal to NULL
!= NULL((void*)0)) && (*error != NULL((void*)0)) && g_error_matches (*error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_EXISTS)) {
13
Assuming pointer value is null
592 g_clear_error (error);
593 success = TRUE(!(0));
594 }
595
596 if (success)
14
Assuming 'success' is 0
15
Taking false branch
597 g_file_set_attribute_uint32 (dir,
598 G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode",
599 mode,
600 0,
601 NULL((void*)0),
602 NULL((void*)0));
603
604 return success;
605}
606
607
608gboolean
609ensure_dir_exists (const char *uri,
610 mode_t mode,
611 GError **error)
612{
613 GFile *dir;
614 GError *priv_error = NULL((void*)0);
615
616 if (uri == NULL((void*)0))
2
Assuming 'uri' is not equal to NULL
3
Taking false branch
617 return FALSE(0);
618
619 if (error == NULL((void*)0))
4
Assuming 'error' is not equal to NULL
5
Taking false branch
620 error = &priv_error;
621
622 dir = g_file_new_for_uri (uri);
623 if (! make_directory_tree (dir, mode, error)) {
6
Calling 'make_directory_tree'
16
Returning from 'make_directory_tree'
17
Taking true branch
624 g_warning ("could create directory %s: %s", uri, (*error)->message);
18
Access to field 'message' results in a dereference of a null pointer
625 if (priv_error != NULL((void*)0))
626 g_clear_error (&priv_error);
627 return FALSE(0);
628 }
629
630 return TRUE(!(0));
631}
632
633
634gboolean
635make_directory_tree_from_path (const char *path,
636 mode_t mode,
637 GError **error)
638{
639 char *uri;
640 gboolean result;
641
642 uri = g_filename_to_uri (path, NULL((void*)0), NULL((void*)0));
643 result = ensure_dir_exists (uri, mode, error);
1
Calling 'ensure_dir_exists'
644 g_free (uri);
645
646 return result;
647}
648
649
650const char *
651get_file_extension (const char *filename)
652{
653 const char *ptr = filename;
654 int len;
655 int p;
656 const char *ext;
657
658 if (filename == NULL((void*)0))
659 return NULL((void*)0);
660
661 len = strlen (filename);
662 if (len <= 1)
663 return NULL((void*)0);
664
665 p = len - 1;
666 while ((p >= 0) && (ptr[p] != '.'))
667 p--;
668 if (p < 0)
669 return NULL((void*)0);
670
671 ext = filename + p;
672 if (ext - 4 > filename) {
673 const char *test = ext - 4;
674 if (strncmp (test, ".tar", 4) == 0)
675 ext = ext - 4;
676 }
677 return ext;
678}
679
680
681gboolean
682file_extension_is (const char *filename,
683 const char *ext)
684{
685 int filename_l, ext_l;
686
687 filename_l = strlen (filename);
688 ext_l = strlen (ext);
689
690 if (filename_l < ext_l)
691 return FALSE(0);
692 return strcasecmp (filename + filename_l - ext_l, ext) == 0;
693}
694
695
696gboolean
697is_mime_type (const char *mime_type,
698 const char *pattern)
699{
700 return (strcasecmp (mime_type, pattern) == 0);
701}
702
703
704const char*
705get_file_mime_type (const char *uri,
706 gboolean fast_file_type)
707{
708 GFile *file;
709 GFileInfo *info;
710 GError *err = NULL((void*)0);
711 const char *result = NULL((void*)0);
712
713 file = g_file_new_for_uri (uri);
714 info = g_file_query_info (file,
715 fast_file_type ?
716 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE"standard::fast-content-type" :
717 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE"standard::content-type",
718 0, NULL((void*)0), &err);
719 if (info == NULL((void*)0)) {
720 g_warning ("could not get content type for %s: %s", uri, err->message);
721 g_clear_error (&err);
722 }
723 else {
724 result = get_static_string (g_file_info_get_content_type (info));
725 g_object_unref (info);
726 }
727
728 g_object_unref (file);
729
730 return result;
731}
732
733
734const char*
735get_file_mime_type_for_path (const char *filename,
736 gboolean fast_file_type)
737{
738 char *uri;
739 const char *mime_type;
740
741 uri = g_filename_to_uri (filename, NULL((void*)0), NULL((void*)0));
742 mime_type = get_file_mime_type (uri, fast_file_type);
743 g_free (uri);
744
745 return mime_type;
746}
747
748
749void
750path_list_free (GList *path_list)
751{
752 if (path_list == NULL((void*)0))
753 return;
754 g_list_free_full (path_list, g_free);
755}
756
757
758GList *
759path_list_dup (GList *path_list)
760{
761 GList *new_list = NULL((void*)0);
762 GList *scan;
763
764 for (scan = path_list; scan; scan = scan->next)
765 new_list = g_list_prepend (new_list, g_strdup (scan->data)g_strdup_inline (scan->data));
766
767 return g_list_reverse (new_list);
768}
769
770
771guint64
772get_dest_free_space (const char *path)
773{
774 guint64 freespace = 0;
775 GFile *file;
776 GFileInfo *info;
777 GError *err = NULL((void*)0);
778
779 file = g_file_new_for_path (path);
780 info = g_file_query_filesystem_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_FREE"filesystem::free", NULL((void*)0), &err);
781 if (info != NULL((void*)0)) {
782 freespace = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE"filesystem::free");
783 g_object_unref (info);
784 }
785 else {
786 g_warning ("Could not get filesystem free space on volume that contains %s: %s", path, err->message);
787 g_error_free (err);
788 }
789 g_object_unref (file);
790
791 return freespace;
792}
793
794
795static gboolean
796delete_directory_recursive (GFile *dir,
797 GError **error)
798{
799 char *uri;
800 GFileEnumerator *file_enum;
801 GFileInfo *info;
802 gboolean error_occurred = FALSE(0);
803
804 if (error != NULL((void*)0))
805 *error = NULL((void*)0);
806
807 file_enum = g_file_enumerate_children (dir,
808 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name" ","
809 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type",
810 0, NULL((void*)0), error);
811
812 uri = g_file_get_uri (dir);
813 while (! error_occurred && (info = g_file_enumerator_next_file (file_enum, NULL((void*)0), error)) != NULL((void*)0)) {
814 char *child_uri;
815 GFile *child;
816
817 child_uri = build_uri (uri, g_file_info_get_name (info), NULL((void*)0));
818 child = g_file_new_for_uri (child_uri);
819
820 switch (g_file_info_get_file_type (info)) {
821 case G_FILE_TYPE_DIRECTORY:
822 if (! delete_directory_recursive (child, error))
823 error_occurred = TRUE(!(0));
824 break;
825 default:
826 if (! g_file_delete (child, NULL((void*)0), error))
827 error_occurred = TRUE(!(0));
828 break;
829 }
830
831 g_object_unref (child);
832 g_free (child_uri);
833 g_object_unref (info);
834 }
835 g_free (uri);
836
837 if (! error_occurred && ! g_file_delete (dir, NULL((void*)0), error))
838 error_occurred = TRUE(!(0));
839
840 g_object_unref (file_enum);
841
842 return ! error_occurred;
843}
844
845
846gboolean
847remove_directory (const char *uri)
848{
849 GFile *dir;
850 gboolean result;
851 GError *error = NULL((void*)0);
852
853 dir = g_file_new_for_uri (uri);
854 result = delete_directory_recursive (dir, &error);
855 if (! result) {
856 g_warning ("Cannot delete %s: %s", uri, error->message);
857 g_clear_error (&error);
858 }
859 g_object_unref (dir);
860
861 return result;
862}
863
864
865gboolean
866remove_local_directory (const char *path)
867{
868 char *uri;
869 gboolean result;
870
871 if (path == NULL((void*)0))
872 return TRUE(!(0));
873
874 uri = g_filename_to_uri (path, NULL((void*)0), NULL((void*)0));
875 result = remove_directory (uri);
876 g_free (uri);
877
878 return result;
879}
880
881
882static const char *try_folder[] = { "cache", "~", "tmp", NULL((void*)0) };
883
884
885static char *
886ith_temp_folder_to_try (int n)
887{
888 const char *folder;
889
890 folder = try_folder[n];
891 if (strcmp (folder, "cache") == 0)
892 folder = g_get_user_cache_dir ();
893 else if (strcmp (folder, "~") == 0)
894 folder = g_get_home_dir ();
895 else if (strcmp (folder, "tmp") == 0)
896 folder = g_get_tmp_dir ();
897
898 return g_strdup (folder)g_strdup_inline (folder);
899}
900
901
902char *
903get_temp_work_dir (const char *parent_folder)
904{
905 guint64 max_size = 0;
906 char *best_folder = NULL((void*)0);
907 char *template;
908 char *result = NULL((void*)0);
909
910 if (parent_folder == NULL((void*)0)) {
911 /* find the folder with more free space. */
912
913 int i;
914
915 for (i = 0; try_folder[i] != NULL((void*)0); i++) {
916 char *folder;
917 guint64 size;
918
919 folder = ith_temp_folder_to_try (i);
920 size = get_dest_free_space (folder);
921 if (max_size < size) {
922 max_size = size;
923 g_free (best_folder);
924 best_folder = folder;
925 }
926 else
927 g_free (folder);
928 }
929 }
930 else
931 best_folder = g_strdup (parent_folder)g_strdup_inline (parent_folder);
932
933 if (best_folder == NULL((void*)0))
934 return NULL((void*)0);
935
936 template = g_strconcat (best_folder, "/.fr-XXXXXX", NULL((void*)0));
937 result = mkdtemp (template);
938
939 if ((result == NULL((void*)0)) || (*result == '\0')) {
940 g_free (template);
941 result = NULL((void*)0);
942 }
943
944 return result;
945}
946
947
948gboolean
949is_temp_work_dir (const char *dir)
950{
951 int i;
952 char *folder = NULL((void*)0);
953
954 if (strncmp (dir, "file://", 7) == 0)
955 dir = dir + 7;
956 else if (dir[0] != '/')
957 return FALSE(0);
958
959 for (i = 0; try_folder[i] != NULL((void*)0); i++) {
960 folder = ith_temp_folder_to_try (i);
961 if (strncmp (dir, folder, strlen (folder)) == 0)
962 if (strncmp (dir + strlen (folder), "/.fr-", 5) == 0) {
963 g_free (folder);
964 return TRUE(!(0));
965 }
966 g_free (folder);
967 }
968
969 return FALSE(0);
970}
971
972
973gboolean
974is_temp_dir (const char *dir)
975{
976 if (strncmp (dir, "file://", 7) == 0)
977 dir = dir + 7;
978 if (strcmp (g_get_tmp_dir (), dir) == 0)
979 return TRUE(!(0));
980 if (path_in_path (g_get_tmp_dir (), dir))
981 return TRUE(!(0));
982 else
983 return is_temp_work_dir (dir);
984}
985
986
987/* file list utils */
988
989
990gboolean
991file_list__match_pattern (const char *line,
992 const char *pattern)
993{
994 const char *l = line, *p = pattern;
995
996 for (; (*p != 0) && (*l != 0); p++, l++) {
997 if (*p != '%') {
998 if (*p != *l)
999 return FALSE(0);
1000 }
1001 else {
1002 p++;
1003 switch (*p) {
1004 case 'a':
1005 break;
1006 case 'n':
1007 if (!isdigit (*l)((*__ctype_b_loc ())[(int) ((*l))] & (unsigned short int)
_ISdigit)
)
1008 return FALSE(0);
1009 break;
1010 case 'c':
1011 if (!isalpha (*l)((*__ctype_b_loc ())[(int) ((*l))] & (unsigned short int)
_ISalpha)
)
1012 return FALSE(0);
1013 break;
1014 default:
1015 return FALSE(0);
1016 }
1017 }
1018 }
1019
1020 return (*p == 0);
1021}
1022
1023
1024int
1025file_list__get_index_from_pattern (const char *line,
1026 const char *pattern)
1027{
1028 int line_l, pattern_l;
1029 const char *l;
1030
1031 line_l = strlen (line);
1032 pattern_l = strlen (pattern);
1033
1034 if ((pattern_l == 0) || (line_l == 0))
1035 return -1;
1036
1037 for (l = line; *l != 0; l++)
1038 if (file_list__match_pattern (l, pattern))
1039 return (l - line);
1040
1041 return -1;
1042}
1043
1044
1045char*
1046file_list__get_next_field (const char *line,
1047 int start_from,
1048 int field_n)
1049{
1050 const char *f_start, *f_end;
1051
1052 line = line + start_from;
1053
1054 f_start = line;
1055 while ((*f_start == ' ') && (*f_start != *line))
1056 f_start++;
1057 f_end = f_start;
1058
1059 while ((field_n > 0) && (*f_end != 0)) {
1060 if (*f_end == ' ') {
1061 field_n--;
1062 if (field_n != 0) {
1063 while ((*f_end == ' ') && (*f_end != *line))
1064 f_end++;
1065 f_start = f_end;
1066 }
1067 } else
1068 f_end++;
1069 }
1070
1071 return g_strndup (f_start, f_end - f_start);
1072}
1073
1074
1075char*
1076file_list__get_prev_field (const char *line,
1077 int start_from,
1078 int field_n)
1079{
1080 const char *f_start, *f_end;
1081
1082 f_start = line + start_from - 1;
1083 while ((*f_start == ' ') && (*f_start != *line))
1084 f_start--;
1085 f_end = f_start;
1086
1087 while ((field_n > 0) && (*f_start != *line)) {
1088 if (*f_start == ' ') {
1089 field_n--;
1090 if (field_n != 0) {
1091 while ((*f_start == ' ') && (*f_start != *line))
1092 f_start--;
1093 f_end = f_start;
1094 }
1095 } else
1096 f_start--;
1097 }
1098
1099 return g_strndup (f_start + 1, f_end - f_start);
1100}
1101
1102
1103gboolean
1104check_permissions (const char *uri,
1105 int mode)
1106{
1107 GFile *file;
1108 gboolean result;
1109
1110 file = g_file_new_for_uri (uri);
1111 result = check_file_permissions (file, mode);
1112
1113 g_object_unref (file);
1114
1115 return result;
1116}
1117
1118
1119gboolean
1120check_file_permissions (GFile *file,
1121 int mode)
1122{
1123 gboolean result = TRUE(!(0));
1124 GFileInfo *info;
1125 GError *err = NULL((void*)0);
1126 gboolean default_permission_when_unknown = TRUE(!(0));
1127
1128 info = g_file_query_info (file, "access::*", 0, NULL((void*)0), &err);
1129 if (err != NULL((void*)0)) {
1130 g_clear_error (&err);
1131 result = FALSE(0);
1132 }
1133 else {
1134 if ((mode & R_OK4) == R_OK4) {
1135 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ"access::can-read"))
1136 result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ"access::can-read"));
1137 else
1138 result = (result && default_permission_when_unknown);
1139 }
1140
1141 if ((mode & W_OK2) == W_OK2) {
1142 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE"access::can-write"))
1143 result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE"access::can-write"));
1144 else
1145 result = (result && default_permission_when_unknown);
1146 }
1147
1148 if ((mode & X_OK1) == X_OK1) {
1149 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE"access::can-execute"))
1150 result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE"access::can-execute"));
1151 else
1152 result = (result && default_permission_when_unknown);
1153 }
1154
1155 g_object_unref (info);
1156 }
1157
1158 return result;
1159}
1160
1161
1162gboolean
1163is_program_in_path (const char *filename)
1164{
1165 char *str;
1166 char *value;
1167 int result = FALSE(0);
1168
1169 value = g_hash_table_lookup (ProgramsCache, filename);
1170 if (value != NULL((void*)0)) {
1171 result = (strcmp (value, "1") == 0);
1172 return result;
1173 }
1174
1175 str = g_find_program_in_path (filename);
1176 if (str != NULL((void*)0)) {
1177 g_free (str);
1178 result = TRUE(!(0));
1179 }
1180
1181 g_hash_table_insert (ProgramsCache,
1182 g_strdup (filename)g_strdup_inline (filename),
1183 result ? "1" : "0");
1184
1185 return result;
1186}
1187
1188
1189gboolean
1190is_program_available (const char *filename,
1191 gboolean check)
1192{
1193 return ! check || is_program_in_path (filename);
1194}
1195
1196
1197const char *
1198get_home_uri (void)
1199{
1200 static char *home_uri = NULL((void*)0);
1201 if (home_uri == NULL((void*)0))
1202 home_uri = g_filename_to_uri (g_get_home_dir (), NULL((void*)0), NULL((void*)0));
1203 return home_uri;
1204}
1205
1206
1207char *
1208get_home_relative_uri (const char *partial_uri)
1209{
1210 return g_strconcat (get_home_uri (),
1211 "/",
1212 partial_uri,
1213 NULL((void*)0));
1214}
1215
1216
1217GFile *
1218get_home_relative_file (const char *partial_uri)
1219{
1220 GFile *file;
1221 char *uri;
1222
1223 uri = g_strconcat (get_home_uri (), "/", partial_uri, NULL((void*)0));
1224 file = g_file_new_for_uri (uri);
1225 g_free (uri);
1226
1227 return file;
1228}
1229
1230
1231GFile *
1232get_user_config_subdirectory (const char *child_name,
1233 gboolean create_child)
1234{
1235 char *full_path;
1236 GFile *file;
1237 GError *error = NULL((void*)0);
1238
1239 full_path = g_strconcat (g_get_user_config_dir (), "/", child_name, NULL((void*)0));
1240 file = g_file_new_for_path (full_path);
1241 g_free (full_path);
1242
1243 if (create_child && ! make_directory_tree (file, 0700, &error)) {
1244 g_warning ("%s", error->message);
1245 g_error_free (error);
1246 g_object_unref (file);
1247 file = NULL((void*)0);
1248 }
1249
1250 return file;
1251}
1252
1253
1254const char *
1255remove_host_from_uri (const char *uri)
1256{
1257 const char *idx, *sep;
1258
1259 if (uri == NULL((void*)0))
1260 return NULL((void*)0);
1261
1262 idx = strstr (uri, "://");
1263 if (idx == NULL((void*)0))
1264 return uri;
1265 idx += 3;
1266 if (*idx == '\0')
1267 return "/";
1268 sep = strstr (idx, "/");
1269 if (sep == NULL((void*)0))
1270 return idx;
1271 return sep;
1272}
1273
1274
1275char *
1276get_uri_host (const char *uri)
1277{
1278 const char *idx;
1279
1280 idx = strstr (uri, "://");
1281 if (idx == NULL((void*)0))
1282 return NULL((void*)0);
1283 idx = strstr (idx + 3, "/");
1284 if (idx == NULL((void*)0))
1285 return NULL((void*)0);
1286 return g_strndup (uri, (idx - uri));
1287}
1288
1289
1290char *
1291get_uri_root (const char *uri)
1292{
1293 char *host;
1294 char *root;
1295
1296 host = get_uri_host (uri);
1297 if (host == NULL((void*)0))
1298 return NULL((void*)0);
1299 root = g_strconcat (host, "/", NULL((void*)0));
1300 g_free (host);
1301
1302 return root;
1303}
1304
1305
1306int
1307uricmp (const char *uri1,
1308 const char *uri2)
1309{
1310 return strcmp_null_tolerant (uri1, uri2);
1311}
1312
1313
1314char *
1315get_alternative_uri (const char *folder,
1316 const char *name)
1317{
1318 char *new_uri = NULL((void*)0);
1319 int n = 1;
1320
1321 do {
1322 g_free (new_uri);
1323 if (n == 1)
1324 new_uri = g_strconcat (folder, "/", name, NULL((void*)0));
1325 else
1326 new_uri = g_strdup_printf ("%s/%s%%20(%d)", folder, name, n);
1327 n++;
1328 } while (uri_exists (new_uri));
1329
1330 return new_uri;
1331}
1332
1333
1334char *
1335get_alternative_uri_for_uri (const char *uri)
1336{
1337 char *base_uri;
1338 char *new_uri;
1339
1340 base_uri = remove_level_from_path (uri);
1341 new_uri = get_alternative_uri (base_uri, file_name_from_path (uri));
1342 g_free (base_uri);
1343
1344 return new_uri;
1345}
1346
1347
1348GList *
1349gio_file_list_dup (GList *l)
1350{
1351 GList *r = NULL((void*)0), *scan;
1352 for (scan = l; scan; scan = scan->next)
1353 r = g_list_prepend (r, g_file_dup ((GFile*)scan->data));
1354 return g_list_reverse (r);
1355}
1356
1357
1358void
1359gio_file_list_free (GList *l)
1360{
1361 GList *scan;
1362 for (scan = l; scan; scan = scan->next)
1363 g_object_unref (scan->data);
1364 g_list_free (l);
1365}
1366
1367
1368GList *
1369gio_file_list_new_from_uri_list (GList *uris)
1370{
1371 GList *r = NULL((void*)0), *scan;
1372 for (scan = uris; scan; scan = scan->next)
1373 r = g_list_prepend (r, g_file_new_for_uri ((char*)scan->data));
1374 return g_list_reverse (r);
1375}
1376
1377
1378void
1379g_key_file_save (GKeyFile *key_file,
1380 GFile *file)
1381{
1382 char *file_data;
1383 gsize size;
1384 GError *error = NULL((void*)0);
1385
1386 file_data = g_key_file_to_data (key_file, &size, &error);
1387 if (error != NULL((void*)0)) {
1388 g_warning ("Could not save options: %s\n", error->message);
1389 g_clear_error (&error);
1390 }
1391 else {
1392 GFileOutputStream *stream;
1393
1394 stream = g_file_replace (file, NULL((void*)0), FALSE(0), 0, NULL((void*)0), &error);
1395 if (stream == NULL((void*)0)) {
1396 g_warning ("Could not save options: %s\n", error->message);
1397 g_clear_error (&error);
1398 }
1399 else if (! g_output_stream_write_all (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, file_data, size, NULL((void*)0), NULL((void*)0), &error)) {
1400 g_warning ("Could not save options: %s\n", error->message);
1401 g_clear_error (&error);
1402 }
1403 else if (! g_output_stream_close (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, NULL((void*)0), &error)) {
1404 g_warning ("Could not save options: %s\n", error->message);
1405 g_clear_error (&error);
1406 }
1407
1408 g_object_unref (stream);
1409 }
1410
1411 g_free (file_data);
1412}