Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 : :
3 : : /* GIO - GLib Input, Output and Streaming Library
4 : : *
5 : : * Copyright (C) 2006-2007 Red Hat, Inc.
6 : : *
7 : : * SPDX-License-Identifier: LGPL-2.1-or-later
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2.1 of the License, or (at your option) any later version.
13 : : *
14 : : * This 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 : : * Lesser General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU Lesser General
20 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 : : *
22 : : * Author: Alexander Larsson <alexl@redhat.com>
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include <glib.h>
28 : :
29 : : #ifdef HAVE_SYS_TIME_H
30 : : #include <sys/time.h>
31 : : #endif
32 : : #include <sys/types.h>
33 : : #include <sys/stat.h>
34 : : #include <string.h>
35 : : #include <fcntl.h>
36 : : #include <errno.h>
37 : : #ifdef G_OS_UNIX
38 : : #include <grp.h>
39 : : #include <pwd.h>
40 : : #endif
41 : : #ifdef HAVE_SELINUX
42 : : #include <selinux/selinux.h>
43 : : #endif
44 : :
45 : : #ifdef HAVE_XATTR
46 : :
47 : : #if defined HAVE_SYS_XATTR_H
48 : : #include <sys/xattr.h>
49 : : #elif defined HAVE_ATTR_XATTR_H
50 : : #include <attr/xattr.h>
51 : : #else
52 : : #error "Neither <sys/xattr.h> nor <attr/xattr.h> is present but extended attribute support is enabled."
53 : : #endif /* defined HAVE_SYS_XATTR_H || HAVE_ATTR_XATTR_H */
54 : :
55 : : #endif /* HAVE_XATTR */
56 : :
57 : : #include <glib/gstdio.h>
58 : : #include <glib/gstdioprivate.h>
59 : : #include <gfileattribute-priv.h>
60 : : #include <gfileinfo-priv.h>
61 : : #include <gvfs.h>
62 : :
63 : : #ifdef G_OS_UNIX
64 : : #include <unistd.h>
65 : : #include "glib-unix.h"
66 : : #endif
67 : :
68 : : #include "glib-private.h"
69 : :
70 : : #include "thumbnail-verify.h"
71 : :
72 : : #ifdef G_OS_WIN32
73 : : #include <windows.h>
74 : : #include <io.h>
75 : : #ifndef W_OK
76 : : #define W_OK 2
77 : : #endif
78 : : #ifndef R_OK
79 : : #define R_OK 4
80 : : #endif
81 : : #ifndef X_OK
82 : : #define X_OK 0 /* not really */
83 : : #endif
84 : : #ifndef S_ISREG
85 : : #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
86 : : #endif
87 : : #ifndef S_ISDIR
88 : : #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
89 : : #endif
90 : : #ifndef S_IXUSR
91 : : #define S_IXUSR _S_IEXEC
92 : : #endif
93 : : #endif
94 : :
95 : : #ifndef O_CLOEXEC
96 : : #define O_CLOEXEC 0
97 : : #endif
98 : :
99 : : #include "glocalfileinfo.h"
100 : : #include "gioerror.h"
101 : : #include "gthemedicon.h"
102 : : #include "gcontenttypeprivate.h"
103 : : #include "glibintl.h"
104 : :
105 : :
106 : : struct ThumbMD5Context {
107 : : guint32 buf[4];
108 : : guint32 bits[2];
109 : : unsigned char in[64];
110 : : };
111 : :
112 : : #ifndef G_OS_WIN32
113 : :
114 : : typedef struct {
115 : : char *user_name;
116 : : char *real_name;
117 : : } UidData;
118 : :
119 : : G_LOCK_DEFINE_STATIC (uid_cache);
120 : : static GHashTable *uid_cache = NULL;
121 : :
122 : : G_LOCK_DEFINE_STATIC (gid_cache);
123 : : static GHashTable *gid_cache = NULL;
124 : :
125 : : #endif /* !G_OS_WIN32 */
126 : :
127 : : char *
128 : 372 : _g_local_file_info_create_etag (GLocalFileStat *statbuf)
129 : : {
130 : : glong sec, usec, nsec;
131 : :
132 : 372 : g_return_val_if_fail (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_MTIME), NULL);
133 : :
134 : 372 : sec = _g_stat_mtime (statbuf);
135 : 372 : usec = _g_stat_mtim_nsec (statbuf) / 1000;
136 : 372 : nsec = _g_stat_mtim_nsec (statbuf);
137 : :
138 : 372 : return g_strdup_printf ("%lu:%lu:%lu", sec, usec, nsec);
139 : : }
140 : :
141 : : static char *
142 : 76 : _g_local_file_info_create_file_id (GLocalFileStat *statbuf)
143 : : {
144 : : guint64 ino;
145 : : #ifdef G_OS_WIN32
146 : : ino = statbuf->file_index;
147 : : #else
148 : 76 : ino = _g_stat_ino (statbuf);
149 : : #endif
150 : 76 : return g_strdup_printf ("l%" G_GUINT64_FORMAT ":%" G_GUINT64_FORMAT,
151 : 76 : (guint64) _g_stat_dev (statbuf),
152 : : ino);
153 : : }
154 : :
155 : : static char *
156 : 76 : _g_local_file_info_create_fs_id (GLocalFileStat *statbuf)
157 : : {
158 : 76 : return g_strdup_printf ("l%" G_GUINT64_FORMAT,
159 : 76 : (guint64) _g_stat_dev (statbuf));
160 : : }
161 : :
162 : : #if defined (S_ISLNK) || defined (G_OS_WIN32)
163 : :
164 : : static gchar *
165 : 59 : read_link (const gchar *full_name)
166 : : {
167 : : #if defined (HAVE_READLINK)
168 : : gchar *buffer;
169 : : gsize size;
170 : :
171 : 59 : size = 256;
172 : 59 : buffer = g_malloc (size);
173 : :
174 : : while (1)
175 : 0 : {
176 : : gssize read_size;
177 : :
178 : 59 : read_size = readlink (full_name, buffer, size);
179 [ - + ]: 59 : if (read_size < 0)
180 : : {
181 : 0 : g_free (buffer);
182 : 0 : return NULL;
183 : : }
184 [ + - ]: 59 : if ((gsize) read_size < size)
185 : : {
186 : 59 : buffer[read_size] = 0;
187 : 59 : return buffer;
188 : : }
189 : 0 : size *= 2;
190 : 0 : buffer = g_realloc (buffer, size);
191 : : }
192 : : #elif defined (G_OS_WIN32)
193 : : gchar *buffer;
194 : : int read_size;
195 : :
196 : : read_size = GLIB_PRIVATE_CALL (g_win32_readlink_utf8) (full_name, NULL, 0, &buffer, TRUE);
197 : : if (read_size < 0)
198 : : return NULL;
199 : : else if (read_size == 0)
200 : : return strdup ("");
201 : : else
202 : : return buffer;
203 : : #else
204 : : return NULL;
205 : : #endif
206 : : }
207 : :
208 : : #endif /* S_ISLNK || G_OS_WIN32 */
209 : :
210 : : #ifdef HAVE_SELINUX
211 : : /* Get the SELinux security context */
212 : : static void
213 : 722 : get_selinux_context (const char *path,
214 : : GFileInfo *info,
215 : : GFileAttributeMatcher *attribute_matcher,
216 : : gboolean follow_symlinks)
217 : : {
218 : : char *context;
219 : :
220 [ + + ]: 722 : if (!_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT))
221 : 646 : return;
222 : :
223 [ - + ]: 76 : if (is_selinux_enabled ())
224 : : {
225 [ # # ]: 0 : if (follow_symlinks)
226 : : {
227 [ # # ]: 0 : if (lgetfilecon_raw (path, &context) < 0)
228 : 0 : return;
229 : : }
230 : : else
231 : : {
232 [ # # ]: 0 : if (getfilecon_raw (path, &context) < 0)
233 : 0 : return;
234 : : }
235 : :
236 [ # # ]: 0 : if (context)
237 : : {
238 : 0 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT, context);
239 : 0 : freecon (context);
240 : : }
241 : : }
242 : : }
243 : : #endif
244 : :
245 : : #ifdef HAVE_XATTR
246 : :
247 : : /* Wrappers to hide away differences between (Linux) getxattr/lgetxattr and
248 : : * (Mac) getxattr(..., XATTR_NOFOLLOW)
249 : : */
250 : : #ifdef HAVE_XATTR_NOFOLLOW
251 : : #define g_fgetxattr(fd,name,value,size) fgetxattr(fd,name,value,size,0,0)
252 : : #define g_flistxattr(fd,name,size) flistxattr(fd,name,size,0)
253 : : #define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0,0)
254 : : #define g_removexattr(path,name) removexattr(path,name,0)
255 : : #else
256 : : #define g_fgetxattr fgetxattr
257 : : #define g_flistxattr flistxattr
258 : : #define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0)
259 : : #define g_removexattr(path,name) removexattr(path,name)
260 : : #endif
261 : :
262 : : static gssize
263 : 81 : g_getxattr (const char *path, const char *name, void *value, size_t size,
264 : : gboolean follow_symlinks)
265 : : {
266 : : #ifdef HAVE_XATTR_NOFOLLOW
267 : : return getxattr (path, name, value, size, 0, follow_symlinks ? 0 : XATTR_NOFOLLOW);
268 : : #else
269 [ + + ]: 81 : if (follow_symlinks)
270 : 5 : return getxattr (path, name, value, size);
271 : : else
272 : 76 : return lgetxattr (path, name, value, size);
273 : : #endif
274 : : }
275 : :
276 : : static gssize
277 : 308 : g_listxattr(const char *path, char *namebuf, size_t size,
278 : : gboolean follow_symlinks)
279 : : {
280 : : #ifdef HAVE_XATTR_NOFOLLOW
281 : : return listxattr (path, namebuf, size, follow_symlinks ? 0 : XATTR_NOFOLLOW);
282 : : #else
283 [ + + ]: 308 : if (follow_symlinks)
284 : 4 : return listxattr (path, namebuf, size);
285 : : else
286 : 304 : return llistxattr (path, namebuf, size);
287 : : #endif
288 : : }
289 : :
290 : : static gboolean
291 : 8005 : valid_char (char c)
292 : : {
293 [ + + + - : 8005 : return c >= 32 && c <= 126 && c != '\\';
+ - ]
294 : : }
295 : :
296 : : static gboolean
297 : 11 : name_is_valid (const char *str)
298 : : {
299 [ + + ]: 249 : while (*str)
300 : : {
301 [ - + ]: 238 : if (!valid_char (*str++))
302 : 0 : return FALSE;
303 : : }
304 : 11 : return TRUE;
305 : : }
306 : :
307 : : static char *
308 : 172 : hex_escape_buffer (const char *str,
309 : : size_t len,
310 : : gboolean *free_return)
311 : : {
312 : : size_t num_invalid, i;
313 : : char *escaped_str, *p;
314 : : unsigned char c;
315 : : static char *hex_digits = "0123456789abcdef";
316 : :
317 : 172 : num_invalid = 0;
318 [ + + ]: 4747 : for (i = 0; i < len; i++)
319 : : {
320 [ + + ]: 4575 : if (!valid_char (str[i]))
321 : 86 : num_invalid++;
322 : : }
323 : :
324 [ + + ]: 172 : if (num_invalid == 0)
325 : : {
326 : 88 : *free_return = FALSE;
327 : 88 : return (char *)str;
328 : : }
329 : :
330 : 84 : escaped_str = g_malloc (len + num_invalid*3 + 1);
331 : :
332 : 84 : p = escaped_str;
333 [ + + ]: 3276 : for (i = 0; i < len; i++)
334 : : {
335 [ + + ]: 3192 : if (valid_char (str[i]))
336 : 3106 : *p++ = str[i];
337 : : else
338 : : {
339 : 86 : c = str[i];
340 : 86 : *p++ = '\\';
341 : 86 : *p++ = 'x';
342 : 86 : *p++ = hex_digits[(c >> 4) & 0xf];
343 : 86 : *p++ = hex_digits[c & 0xf];
344 : : }
345 : : }
346 : 84 : *p = 0;
347 : :
348 : 84 : *free_return = TRUE;
349 : 84 : return escaped_str;
350 : : }
351 : :
352 : : static char *
353 : 86 : hex_escape_string (const char *str,
354 : : gboolean *free_return)
355 : : {
356 : 86 : return hex_escape_buffer (str, strlen (str), free_return);
357 : : }
358 : :
359 : : static char *
360 : 22 : hex_unescape_string (const char *str,
361 : : int *out_len,
362 : : gboolean *free_return)
363 : : {
364 : : int i;
365 : : char *unescaped_str, *p;
366 : : unsigned char c;
367 : : int len;
368 : :
369 : 22 : len = strlen (str);
370 : :
371 [ + + ]: 22 : if (strchr (str, '\\') == NULL)
372 : : {
373 [ + + ]: 14 : if (out_len)
374 : 2 : *out_len = len;
375 : 14 : *free_return = FALSE;
376 : 14 : return (char *)str;
377 : : }
378 : :
379 : 8 : unescaped_str = g_malloc (len + 1);
380 : :
381 : 8 : p = unescaped_str;
382 [ + + ]: 312 : for (i = 0; i < len; i++)
383 : : {
384 [ + + ]: 304 : if (str[i] == '\\' &&
385 [ + - ]: 10 : str[i+1] == 'x' &&
386 [ + - ]: 10 : len - i >= 4)
387 : : {
388 : 10 : c =
389 : 10 : (g_ascii_xdigit_value (str[i+2]) << 4) |
390 : 10 : g_ascii_xdigit_value (str[i+3]);
391 : 10 : *p++ = c;
392 : 10 : i += 3;
393 : : }
394 : : else
395 : 294 : *p++ = str[i];
396 : : }
397 [ + - ]: 8 : if (out_len)
398 : 8 : *out_len = p - unescaped_str;
399 : 8 : *p++ = 0;
400 : :
401 : 8 : *free_return = TRUE;
402 : 8 : return unescaped_str;
403 : : }
404 : :
405 : : static void
406 : 86 : escape_xattr (GFileInfo *info,
407 : : const char *gio_attr, /* gio attribute name */
408 : : const char *value, /* Is zero terminated */
409 : : size_t len /* not including zero termination */)
410 : : {
411 : : char *escaped_val;
412 : : gboolean free_escaped_val;
413 : :
414 : 86 : escaped_val = hex_escape_buffer (value, len, &free_escaped_val);
415 : :
416 : 86 : g_file_info_set_attribute_string (info, gio_attr, escaped_val);
417 : :
418 [ + + ]: 86 : if (free_escaped_val)
419 : 84 : g_free (escaped_val);
420 : 86 : }
421 : :
422 : : static void
423 : 81 : get_one_xattr (const char *path,
424 : : GFileInfo *info,
425 : : const char *gio_attr,
426 : : const char *xattr,
427 : : gboolean follow_symlinks)
428 : : {
429 : : char value[64];
430 : : char *value_p;
431 : : gssize len;
432 : : int errsv;
433 : :
434 : 81 : len = g_getxattr (path, xattr, value, sizeof (value)-1, follow_symlinks);
435 : 81 : errsv = errno;
436 : :
437 : 81 : value_p = NULL;
438 [ + + ]: 81 : if (len >= 0)
439 : 80 : value_p = value;
440 [ + - - + ]: 1 : else if (len == -1 && errsv == ERANGE)
441 : : {
442 : 0 : len = g_getxattr (path, xattr, NULL, 0, follow_symlinks);
443 : :
444 [ # # ]: 0 : if (len < 0)
445 : 1 : return;
446 : :
447 : 0 : value_p = g_malloc (len+1);
448 : :
449 : 0 : len = g_getxattr (path, xattr, value_p, len, follow_symlinks);
450 : :
451 [ # # ]: 0 : if (len < 0)
452 : : {
453 : 0 : g_free (value_p);
454 : 0 : return;
455 : : }
456 : : }
457 : : else
458 : 1 : return;
459 : :
460 : : /* Null terminate */
461 : 80 : value_p[len] = 0;
462 : :
463 : 80 : escape_xattr (info, gio_attr, value_p, len);
464 : :
465 [ - + ]: 80 : if (value_p != value)
466 : 0 : g_free (value_p);
467 : : }
468 : :
469 : : #endif /* defined HAVE_XATTR */
470 : :
471 : : static void
472 : 1444 : get_xattrs (const char *path,
473 : : gboolean user,
474 : : GFileInfo *info,
475 : : GFileAttributeMatcher *matcher,
476 : : gboolean follow_symlinks)
477 : : {
478 : : #ifdef HAVE_XATTR
479 : : gboolean all;
480 : : gsize list_size;
481 : : gssize list_res_size;
482 : : size_t len;
483 : : char *list;
484 : : const char *attr, *attr2;
485 : :
486 [ + + ]: 1444 : if (user)
487 : 722 : all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr");
488 : : else
489 : 722 : all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr-sys");
490 : :
491 [ + + ]: 1444 : if (all)
492 : : {
493 : : int errsv;
494 : :
495 : 154 : list_res_size = g_listxattr (path, NULL, 0, follow_symlinks);
496 : :
497 [ + - - + ]: 154 : if (list_res_size == -1 ||
498 : : list_res_size == 0)
499 : 0 : return;
500 : :
501 : 154 : list_size = list_res_size;
502 : 154 : list = g_malloc (list_size);
503 : :
504 : 154 : retry:
505 : :
506 : 154 : list_res_size = g_listxattr (path, list, list_size, follow_symlinks);
507 : 154 : errsv = errno;
508 : :
509 [ - + - - ]: 154 : if (list_res_size == -1 && errsv == ERANGE)
510 : : {
511 : 0 : list_size = list_size * 2;
512 : 0 : list = g_realloc (list, list_size);
513 : 0 : goto retry;
514 : : }
515 : :
516 [ - + ]: 154 : if (list_res_size == -1)
517 : : {
518 : 0 : g_free (list);
519 : 0 : return;
520 : : }
521 : :
522 : 154 : attr = list;
523 [ + + ]: 312 : while (list_res_size > 0)
524 : : {
525 [ + + + - : 158 : if ((user && g_str_has_prefix (attr, "user.")) ||
- + + - +
+ + + ]
526 [ + - - + : 76 : (!user && !g_str_has_prefix (attr, "user.")))
+ - + - ]
527 : : {
528 : : char *escaped_attr, *gio_attr;
529 : : gboolean free_escaped_attr;
530 : :
531 [ + + ]: 80 : if (user)
532 : : {
533 : 4 : escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr);
534 : 4 : gio_attr = g_strconcat ("xattr::", escaped_attr, NULL);
535 : : }
536 : : else
537 : : {
538 : 76 : escaped_attr = hex_escape_string (attr, &free_escaped_attr);
539 : 76 : gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL);
540 : : }
541 : :
542 [ - + ]: 80 : if (free_escaped_attr)
543 : 0 : g_free (escaped_attr);
544 : :
545 : 80 : get_one_xattr (path, info, gio_attr, attr, follow_symlinks);
546 : :
547 : 80 : g_free (gio_attr);
548 : : }
549 : :
550 : 158 : len = strlen (attr) + 1;
551 : 158 : attr += len;
552 : 158 : list_res_size -= len;
553 : : }
554 : :
555 : 154 : g_free (list);
556 : : }
557 : : else
558 : : {
559 [ + + ]: 1291 : while ((attr = g_file_attribute_matcher_enumerate_next (matcher)) != NULL)
560 : : {
561 : : char *unescaped_attribute, *a;
562 : : gboolean free_unescaped_attribute;
563 : :
564 : 1 : attr2 = strchr (attr, ':');
565 [ + - ]: 1 : if (attr2)
566 : : {
567 : 1 : attr2 += 2; /* Skip '::' */
568 : 1 : unescaped_attribute = hex_unescape_string (attr2, NULL, &free_unescaped_attribute);
569 [ + - ]: 1 : if (user)
570 : 1 : a = g_strconcat ("user.", unescaped_attribute, NULL);
571 : : else
572 : 0 : a = unescaped_attribute;
573 : :
574 : 1 : get_one_xattr (path, info, attr, a, follow_symlinks);
575 : :
576 [ + - ]: 1 : if (user)
577 : 1 : g_free (a);
578 : :
579 [ - + ]: 1 : if (free_unescaped_attribute)
580 : 0 : g_free (unescaped_attribute);
581 : : }
582 : : }
583 : : }
584 : : #endif /* defined HAVE_XATTR */
585 : : }
586 : :
587 : : #ifdef HAVE_XATTR
588 : : static void
589 : 6 : get_one_xattr_from_fd (int fd,
590 : : GFileInfo *info,
591 : : const char *gio_attr,
592 : : const char *xattr)
593 : : {
594 : : char value[64];
595 : : char *value_p;
596 : : gssize len;
597 : : int errsv;
598 : :
599 : 6 : len = g_fgetxattr (fd, xattr, value, sizeof (value) - 1);
600 : 6 : errsv = errno;
601 : :
602 : 6 : value_p = NULL;
603 [ + - ]: 6 : if (len >= 0)
604 : 6 : value_p = value;
605 [ # # # # ]: 0 : else if (len == -1 && errsv == ERANGE)
606 : : {
607 : 0 : len = g_fgetxattr (fd, xattr, NULL, 0);
608 : :
609 [ # # ]: 0 : if (len < 0)
610 : 0 : return;
611 : :
612 : 0 : value_p = g_malloc (len + 1);
613 : :
614 : 0 : len = g_fgetxattr (fd, xattr, value_p, len);
615 : :
616 [ # # ]: 0 : if (len < 0)
617 : : {
618 : 0 : g_free (value_p);
619 : 0 : return;
620 : : }
621 : : }
622 : : else
623 : 0 : return;
624 : :
625 : : /* Null terminate */
626 : 6 : value_p[len] = 0;
627 : :
628 : 6 : escape_xattr (info, gio_attr, value_p, len);
629 : :
630 [ - + ]: 6 : if (value_p != value)
631 : 0 : g_free (value_p);
632 : : }
633 : : #endif /* defined HAVE_XATTR */
634 : :
635 : : static void
636 : 136 : get_xattrs_from_fd (int fd,
637 : : gboolean user,
638 : : GFileInfo *info,
639 : : GFileAttributeMatcher *matcher)
640 : : {
641 : : #ifdef HAVE_XATTR
642 : : gboolean all;
643 : : gsize list_size;
644 : : gssize list_res_size;
645 : : size_t len;
646 : : char *list;
647 : : const char *attr, *attr2;
648 : :
649 [ + + ]: 136 : if (user)
650 : 68 : all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr");
651 : : else
652 : 68 : all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr-sys");
653 : :
654 [ + + ]: 136 : if (all)
655 : : {
656 : : int errsv;
657 : :
658 : 70 : list_res_size = g_flistxattr (fd, NULL, 0);
659 : :
660 [ + - - + ]: 70 : if (list_res_size == -1 ||
661 : : list_res_size == 0)
662 : 0 : return;
663 : :
664 : 70 : list_size = list_res_size;
665 : 70 : list = g_malloc (list_size);
666 : :
667 : 70 : retry:
668 : :
669 : 70 : list_res_size = g_flistxattr (fd, list, list_size);
670 : 70 : errsv = errno;
671 : :
672 [ - + - - ]: 70 : if (list_res_size == -1 && errsv == ERANGE)
673 : : {
674 : 0 : list_size = list_size * 2;
675 : 0 : list = g_realloc (list, list_size);
676 : 0 : goto retry;
677 : : }
678 : :
679 [ - + ]: 70 : if (list_res_size == -1)
680 : : {
681 : 0 : g_free (list);
682 : 0 : return;
683 : : }
684 : :
685 : 70 : attr = list;
686 [ + + ]: 140 : while (list_res_size > 0)
687 : : {
688 [ + + + - : 70 : if ((user && g_str_has_prefix (attr, "user.")) ||
- + + - +
- + + ]
689 [ + - - + : 6 : (!user && !g_str_has_prefix (attr, "user.")))
+ - + - ]
690 : : {
691 : : char *escaped_attr, *gio_attr;
692 : : gboolean free_escaped_attr;
693 : :
694 [ - + ]: 6 : if (user)
695 : : {
696 : 0 : escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr);
697 : 0 : gio_attr = g_strconcat ("xattr::", escaped_attr, NULL);
698 : : }
699 : : else
700 : : {
701 : 6 : escaped_attr = hex_escape_string (attr, &free_escaped_attr);
702 : 6 : gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL);
703 : : }
704 : :
705 [ - + ]: 6 : if (free_escaped_attr)
706 : 0 : g_free (escaped_attr);
707 : :
708 : 6 : get_one_xattr_from_fd (fd, info, gio_attr, attr);
709 : 6 : g_free (gio_attr);
710 : : }
711 : :
712 : 70 : len = strlen (attr) + 1;
713 : 70 : attr += len;
714 : 70 : list_res_size -= len;
715 : : }
716 : :
717 : 70 : g_free (list);
718 : : }
719 : : else
720 : : {
721 [ - + ]: 66 : while ((attr = g_file_attribute_matcher_enumerate_next (matcher)) != NULL)
722 : : {
723 : : char *unescaped_attribute, *a;
724 : : gboolean free_unescaped_attribute;
725 : :
726 : 0 : attr2 = strchr (attr, ':');
727 [ # # ]: 0 : if (attr2)
728 : : {
729 : 0 : attr2++; /* Skip ':' */
730 : 0 : unescaped_attribute = hex_unescape_string (attr2, NULL, &free_unescaped_attribute);
731 [ # # ]: 0 : if (user)
732 : 0 : a = g_strconcat ("user.", unescaped_attribute, NULL);
733 : : else
734 : 0 : a = unescaped_attribute;
735 : :
736 : 0 : get_one_xattr_from_fd (fd, info, attr, a);
737 : :
738 [ # # ]: 0 : if (user)
739 : 0 : g_free (a);
740 : :
741 [ # # ]: 0 : if (free_unescaped_attribute)
742 : 0 : g_free (unescaped_attribute);
743 : : }
744 : : }
745 : : }
746 : : #endif /* defined HAVE_XATTR */
747 : : }
748 : :
749 : : #ifdef HAVE_XATTR
750 : : static gboolean
751 : 11 : set_xattr (char *filename,
752 : : const char *escaped_attribute,
753 : : const GFileAttributeValue *attr_value,
754 : : GError **error)
755 : : {
756 : : char *attribute, *value;
757 : : gboolean free_attribute, free_value;
758 : : int val_len, res, errsv;
759 : : gboolean is_user;
760 : : char *a;
761 : :
762 [ - + ]: 11 : if (attr_value == NULL)
763 : : {
764 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
765 : : _("Attribute value must be non-NULL"));
766 : 0 : return FALSE;
767 : : }
768 : :
769 [ + + - + ]: 11 : if (attr_value->type != G_FILE_ATTRIBUTE_TYPE_STRING && attr_value->type != G_FILE_ATTRIBUTE_TYPE_INVALID)
770 : : {
771 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
772 : : _("Invalid attribute type (string or invalid expected)"));
773 : 0 : return FALSE;
774 : : }
775 : :
776 [ - + ]: 11 : if (!name_is_valid (escaped_attribute))
777 : : {
778 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
779 : : _("Invalid extended attribute name"));
780 : 0 : return FALSE;
781 : : }
782 : :
783 [ + - - + : 11 : if (g_str_has_prefix (escaped_attribute, "xattr::"))
+ - + + ]
784 : : {
785 : 5 : escaped_attribute += strlen ("xattr::");
786 : 5 : is_user = TRUE;
787 : : }
788 : : else
789 : : {
790 [ + - - + : 6 : g_warn_if_fail (g_str_has_prefix (escaped_attribute, "xattr-sys::"));
+ - - + ]
791 : 6 : escaped_attribute += strlen ("xattr-sys::");
792 : 6 : is_user = FALSE;
793 : : }
794 : :
795 : 11 : attribute = hex_unescape_string (escaped_attribute, NULL, &free_attribute);
796 : :
797 [ + + ]: 11 : if (is_user)
798 : 5 : a = g_strconcat ("user.", attribute, NULL);
799 : : else
800 : 6 : a = attribute;
801 : :
802 [ + + ]: 11 : if (attr_value->type == G_FILE_ATTRIBUTE_TYPE_STRING)
803 : : {
804 : 10 : value = hex_unescape_string (attr_value->u.string, &val_len, &free_value);
805 : 10 : res = g_setxattr (filename, a, value, val_len);
806 : : }
807 : : else
808 : : {
809 : 1 : value = NULL;
810 : 1 : val_len = 0;
811 : 1 : free_value = FALSE;
812 : 1 : res = g_removexattr (filename, a);
813 : : }
814 : :
815 : 11 : errsv = errno;
816 : :
817 [ + + ]: 11 : if (is_user)
818 : 5 : g_free (a);
819 : :
820 [ - + ]: 11 : if (free_attribute)
821 : 0 : g_free (attribute);
822 : :
823 [ + + ]: 11 : if (free_value)
824 : 8 : g_free (value);
825 : :
826 [ + + ]: 11 : if (res == -1)
827 : : {
828 : 12 : g_set_error (error, G_IO_ERROR,
829 : 6 : g_io_error_from_errno (errsv),
830 : : _("Error setting extended attribute “%s”: %s"),
831 : : escaped_attribute, g_strerror (errsv));
832 : 6 : return FALSE;
833 : : }
834 : :
835 : 5 : return TRUE;
836 : : }
837 : :
838 : : #endif
839 : :
840 : :
841 : : void
842 : 997 : _g_local_file_info_get_parent_info (const char *dir,
843 : : GFileAttributeMatcher *attribute_matcher,
844 : : GLocalParentFileInfo *parent_info)
845 : : {
846 : : GStatBuf statbuf;
847 : : int res;
848 : :
849 : 997 : parent_info->extra_data = NULL;
850 : 997 : parent_info->free_extra_data = NULL;
851 : 997 : parent_info->writable = FALSE;
852 : 997 : parent_info->is_sticky = FALSE;
853 : 997 : parent_info->has_trash_dir = FALSE;
854 : 997 : parent_info->device = 0;
855 : 997 : parent_info->inode = 0;
856 : :
857 [ + + + - ]: 1915 : if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME) ||
858 [ + - ]: 1836 : _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE) ||
859 [ + + ]: 1836 : _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH) ||
860 : 918 : _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT))
861 : : {
862 : : /* FIXME: Windows: The underlying _waccess() call in the C
863 : : * library is mostly pointless as it only looks at the READONLY
864 : : * FAT-style attribute of the file, it doesn't check the ACL at
865 : : * all.
866 : : */
867 : 81 : parent_info->writable = (g_access (dir, W_OK) == 0);
868 : :
869 : 81 : res = g_stat (dir, &statbuf);
870 : :
871 : : /*
872 : : * The sticky bit (S_ISVTX) on a directory means that a file in that directory can be
873 : : * renamed or deleted only by the owner of the file, by the owner of the directory, and
874 : : * by a privileged process.
875 : : */
876 [ + - ]: 81 : if (res == 0)
877 : : {
878 : : #ifdef S_ISVTX
879 : 81 : parent_info->is_sticky = (statbuf.st_mode & S_ISVTX) != 0;
880 : : #else
881 : : parent_info->is_sticky = FALSE;
882 : : #endif
883 : 81 : parent_info->owner = statbuf.st_uid;
884 : 81 : parent_info->device = statbuf.st_dev;
885 : 81 : parent_info->inode = statbuf.st_ino;
886 : : /* No need to find trash dir if it's not writable anyway */
887 [ + + + - ]: 157 : if (parent_info->writable &&
888 : 76 : _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH))
889 : 76 : parent_info->has_trash_dir = _g_local_file_has_trash_dir (dir, statbuf.st_dev);
890 : : }
891 : : }
892 : 997 : }
893 : :
894 : : void
895 : 997 : _g_local_file_info_free_parent_info (GLocalParentFileInfo *parent_info)
896 : : {
897 [ - + ]: 997 : if (parent_info->extra_data &&
898 [ # # ]: 0 : parent_info->free_extra_data)
899 : 0 : parent_info->free_extra_data (parent_info->extra_data);
900 : 997 : }
901 : :
902 : : static void
903 : 720 : get_access_rights (GFileAttributeMatcher *attribute_matcher,
904 : : GFileInfo *info,
905 : : const gchar *path,
906 : : GLocalFileStat *statbuf,
907 : : GLocalParentFileInfo *parent_info)
908 : : {
909 : : /* FIXME: Windows: The underlyin _waccess() is mostly pointless */
910 [ + + ]: 720 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
911 : : G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ))
912 : 115 : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ,
913 : 115 : g_access (path, R_OK) == 0);
914 : :
915 [ + + ]: 720 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
916 : : G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE))
917 : 115 : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE,
918 : 115 : g_access (path, W_OK) == 0);
919 : :
920 [ + + ]: 720 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
921 : : G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE))
922 : 118 : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE,
923 : 118 : g_access (path, X_OK) == 0);
924 : :
925 : :
926 [ + - ]: 720 : if (parent_info)
927 : : {
928 : : gboolean writable;
929 : :
930 : 720 : writable = FALSE;
931 [ + + ]: 720 : if (parent_info->writable)
932 : : {
933 : : #ifdef G_OS_WIN32
934 : : writable = TRUE;
935 : : #else
936 [ - + ]: 115 : if (parent_info->is_sticky)
937 : : {
938 : 0 : uid_t uid = geteuid ();
939 : :
940 [ # # ]: 0 : if (uid == _g_stat_uid (statbuf) ||
941 [ # # # # ]: 0 : uid == (uid_t) parent_info->owner ||
942 : : uid == 0)
943 : 0 : writable = TRUE;
944 : : }
945 : : else
946 : 115 : writable = TRUE;
947 : : #endif
948 : : }
949 : :
950 [ + + ]: 720 : if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME))
951 : 115 : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME,
952 : : writable);
953 : :
954 [ + + ]: 720 : if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE))
955 : 115 : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE,
956 : : writable);
957 : :
958 [ + + ]: 720 : if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH))
959 [ + - ]: 230 : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH,
960 [ + + ]: 115 : writable && parent_info->has_trash_dir);
961 : : }
962 : 720 : }
963 : :
964 : : static void
965 : 788 : set_info_from_stat (GFileInfo *info,
966 : : GLocalFileStat *statbuf,
967 : : GFileAttributeMatcher *attribute_matcher)
968 : : {
969 : : GFileType file_type;
970 : :
971 : 788 : file_type = G_FILE_TYPE_UNKNOWN;
972 : :
973 [ + + ]: 788 : if (S_ISREG (_g_stat_mode (statbuf)))
974 : 602 : file_type = G_FILE_TYPE_REGULAR;
975 [ + + ]: 186 : else if (S_ISDIR (_g_stat_mode (statbuf)))
976 : 123 : file_type = G_FILE_TYPE_DIRECTORY;
977 : : #ifndef G_OS_WIN32
978 [ + - ]: 63 : else if (S_ISCHR (_g_stat_mode (statbuf)) ||
979 [ + - ]: 63 : S_ISBLK (_g_stat_mode (statbuf)) ||
980 [ + - ]: 63 : S_ISFIFO (_g_stat_mode (statbuf))
981 : : #ifdef S_ISSOCK
982 [ + + ]: 63 : || S_ISSOCK (_g_stat_mode (statbuf))
983 : : #endif
984 : : )
985 : 16 : file_type = G_FILE_TYPE_SPECIAL;
986 : : #endif
987 : : #ifdef S_ISLNK
988 [ + - ]: 47 : else if (S_ISLNK (_g_stat_mode (statbuf)))
989 : 47 : file_type = G_FILE_TYPE_SYMBOLIC_LINK;
990 : : #elif defined (G_OS_WIN32)
991 : : else if (statbuf->reparse_tag == IO_REPARSE_TAG_SYMLINK ||
992 : : statbuf->reparse_tag == IO_REPARSE_TAG_MOUNT_POINT)
993 : : file_type = G_FILE_TYPE_SYMBOLIC_LINK;
994 : : #endif
995 : :
996 : 788 : g_file_info_set_file_type (info, file_type);
997 : 788 : g_file_info_set_size (info, _g_stat_size (statbuf));
998 : :
999 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_DEVICE, _g_stat_dev (statbuf));
1000 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_NLINK, _g_stat_nlink (statbuf));
1001 : : #ifndef G_OS_WIN32
1002 : : /* Pointless setting these on Windows even if they exist in the struct */
1003 : 788 : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_INODE, _g_stat_ino (statbuf));
1004 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_UID, _g_stat_uid (statbuf));
1005 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_GID, _g_stat_gid (statbuf));
1006 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_RDEV, _g_stat_rdev (statbuf));
1007 : : #endif
1008 : : /* Mostly pointless on Windows.
1009 : : * Still, it allows for S_ISREG/S_ISDIR and IWRITE (read-only) checks.
1010 : : */
1011 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_MODE, _g_stat_mode (statbuf));
1012 : : #if defined (HAVE_STRUCT_STAT_ST_BLKSIZE)
1013 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCK_SIZE, _g_stat_blksize (statbuf));
1014 : : #endif
1015 : : #if defined (HAVE_STRUCT_STAT_ST_BLOCKS)
1016 : 788 : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCKS, _g_stat_blocks (statbuf));
1017 : 788 : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_ALLOCATED_SIZE,
1018 : 788 : _g_stat_blocks (statbuf) * G_GUINT64_CONSTANT (512));
1019 : : #elif defined (G_OS_WIN32)
1020 : : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_ALLOCATED_SIZE,
1021 : : statbuf->allocated_size);
1022 : :
1023 : : #endif
1024 : :
1025 : 788 : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, _g_stat_mtime (statbuf));
1026 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, _g_stat_mtim_nsec (statbuf) / 1000);
1027 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, _g_stat_mtim_nsec (statbuf));
1028 : :
1029 [ + - ]: 788 : if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_ATIME))
1030 : : {
1031 : 788 : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, _g_stat_atime (statbuf));
1032 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, _g_stat_atim_nsec (statbuf) / 1000);
1033 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, _g_stat_atim_nsec (statbuf));
1034 : : }
1035 : :
1036 : : #ifndef G_OS_WIN32
1037 : : /* Microsoft uses st_ctime for file creation time,
1038 : : * instead of file change time:
1039 : : * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions#generic-text-routine-mappings
1040 : : * Thank you, Microsoft!
1041 : : */
1042 : 788 : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED, _g_stat_ctime (statbuf));
1043 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, _g_stat_ctim_nsec (statbuf) / 1000);
1044 : 788 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_NSEC, _g_stat_ctim_nsec (statbuf));
1045 : : #endif
1046 : :
1047 : : #if defined (HAVE_STATX)
1048 [ + + ]: 788 : if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_BTIME))
1049 : : {
1050 : 787 : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->stx_btime.tv_sec);
1051 : 787 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->stx_btime.tv_nsec / 1000);
1052 : 787 : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->stx_btime.tv_nsec);
1053 : : }
1054 : : #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
1055 : : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime);
1056 : : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtimensec / 1000);
1057 : : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_birthtimensec);
1058 : : #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
1059 : : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim.tv_sec);
1060 : : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtim.tv_nsec / 1000);
1061 : : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_birthtim.tv_nsec);
1062 : : #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME)
1063 : : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime);
1064 : : #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM)
1065 : : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim);
1066 : : #elif defined (G_OS_WIN32)
1067 : : _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_ctim.tv_sec);
1068 : : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_ctim.tv_nsec / 1000);
1069 : : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_ctim.tv_nsec);
1070 : : #endif
1071 : :
1072 [ + + ]: 788 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
1073 : : G_FILE_ATTRIBUTE_ID_ETAG_VALUE))
1074 : : {
1075 : 80 : char *etag = _g_local_file_info_create_etag (statbuf);
1076 : 80 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ETAG_VALUE, etag);
1077 : 80 : g_free (etag);
1078 : : }
1079 : :
1080 [ + + ]: 788 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
1081 : : G_FILE_ATTRIBUTE_ID_ID_FILE))
1082 : : {
1083 : 76 : char *id = _g_local_file_info_create_file_id (statbuf);
1084 : 76 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ID_FILE, id);
1085 : 76 : g_free (id);
1086 : : }
1087 : :
1088 [ + + ]: 788 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
1089 : : G_FILE_ATTRIBUTE_ID_ID_FILESYSTEM))
1090 : : {
1091 : 76 : char *id = _g_local_file_info_create_fs_id (statbuf);
1092 : 76 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ID_FILESYSTEM, id);
1093 : 76 : g_free (id);
1094 : : }
1095 : 788 : }
1096 : :
1097 : : #ifndef G_OS_WIN32
1098 : :
1099 : : static char *
1100 : 0 : make_valid_utf8 (const char *name)
1101 : : {
1102 : : GString *string;
1103 : : const gchar *remainder, *invalid;
1104 : : gsize remaining_bytes, valid_bytes;
1105 : :
1106 : 0 : string = NULL;
1107 : 0 : remainder = name;
1108 : 0 : remaining_bytes = strlen (name);
1109 : :
1110 [ # # ]: 0 : while (remaining_bytes != 0)
1111 : : {
1112 [ # # ]: 0 : if (g_utf8_validate_len (remainder, remaining_bytes, &invalid))
1113 : 0 : break;
1114 : 0 : valid_bytes = invalid - remainder;
1115 : :
1116 [ # # ]: 0 : if (string == NULL)
1117 : 0 : string = g_string_sized_new (remaining_bytes);
1118 : :
1119 [ # # ]: 0 : g_string_append_len (string, remainder, valid_bytes);
1120 : : /* append U+FFFD REPLACEMENT CHARACTER */
1121 [ # # ]: 0 : g_string_append (string, "\357\277\275");
1122 : :
1123 : 0 : remaining_bytes -= valid_bytes + 1;
1124 : 0 : remainder = invalid + 1;
1125 : : }
1126 : :
1127 [ # # ]: 0 : if (string == NULL)
1128 : 0 : return g_strdup (name);
1129 : :
1130 : : g_string_append (string, remainder);
1131 : :
1132 [ # # ]: 0 : g_warn_if_fail (g_utf8_validate (string->str, -1, NULL));
1133 : :
1134 : 0 : return g_string_free (string, FALSE);
1135 : : }
1136 : :
1137 : : static char *
1138 : 3 : convert_pwd_string_to_utf8 (char *pwd_str)
1139 : : {
1140 : : char *utf8_string;
1141 : :
1142 [ - + ]: 3 : if (!g_utf8_validate (pwd_str, -1, NULL))
1143 : : {
1144 : 0 : utf8_string = g_locale_to_utf8 (pwd_str, -1, NULL, NULL, NULL);
1145 [ # # ]: 0 : if (utf8_string == NULL)
1146 : 0 : utf8_string = make_valid_utf8 (pwd_str);
1147 : : }
1148 : : else
1149 : 3 : utf8_string = g_strdup (pwd_str);
1150 : :
1151 : 3 : return utf8_string;
1152 : : }
1153 : :
1154 : : static void
1155 : 0 : uid_data_free (UidData *data)
1156 : : {
1157 : 0 : g_free (data->user_name);
1158 : 0 : g_free (data->real_name);
1159 : 0 : g_free (data);
1160 : 0 : }
1161 : :
1162 : : /* called with lock held */
1163 : : static UidData *
1164 : 152 : lookup_uid_data (uid_t uid)
1165 : : {
1166 : : UidData *data;
1167 : : char buffer[4096];
1168 : : struct passwd pwbuf;
1169 : : struct passwd *pwbufp;
1170 : : #ifndef __BIONIC__
1171 : : char *gecos, *comma;
1172 : : #endif
1173 : :
1174 [ + + ]: 152 : if (uid_cache == NULL)
1175 : 1 : uid_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)uid_data_free);
1176 : :
1177 : 152 : data = g_hash_table_lookup (uid_cache, GINT_TO_POINTER (uid));
1178 : :
1179 [ + + ]: 152 : if (data)
1180 : 151 : return data;
1181 : :
1182 : 1 : data = g_new0 (UidData, 1);
1183 : :
1184 : : #if defined(HAVE_GETPWUID_R)
1185 : 1 : getpwuid_r (uid, &pwbuf, buffer, sizeof(buffer), &pwbufp);
1186 : : #else
1187 : : pwbufp = getpwuid (uid);
1188 : : #endif
1189 : :
1190 [ + - ]: 1 : if (pwbufp != NULL)
1191 : : {
1192 [ + - + - ]: 1 : if (pwbufp->pw_name != NULL && pwbufp->pw_name[0] != 0)
1193 : 1 : data->user_name = convert_pwd_string_to_utf8 (pwbufp->pw_name);
1194 : :
1195 : : #ifndef __BIONIC__
1196 : 1 : gecos = pwbufp->pw_gecos;
1197 : :
1198 [ + - ]: 1 : if (gecos)
1199 : : {
1200 : 1 : comma = strchr (gecos, ',');
1201 [ - + ]: 1 : if (comma)
1202 : 0 : *comma = 0;
1203 : 1 : data->real_name = convert_pwd_string_to_utf8 (gecos);
1204 : : }
1205 : : #endif
1206 : : }
1207 : :
1208 : : /* Default fallbacks */
1209 [ - + ]: 1 : if (data->real_name == NULL)
1210 : : {
1211 [ # # ]: 0 : if (data->user_name != NULL)
1212 : 0 : data->real_name = g_strdup (data->user_name);
1213 : : else
1214 : 0 : data->real_name = g_strdup_printf ("user #%d", (int)uid);
1215 : : }
1216 : :
1217 [ - + ]: 1 : if (data->user_name == NULL)
1218 : 0 : data->user_name = g_strdup_printf ("%d", (int)uid);
1219 : :
1220 : 1 : g_hash_table_replace (uid_cache, GINT_TO_POINTER (uid), data);
1221 : :
1222 : 1 : return data;
1223 : : }
1224 : :
1225 : : static char *
1226 : 76 : get_username_from_uid (uid_t uid)
1227 : : {
1228 : : char *res;
1229 : : UidData *data;
1230 : :
1231 : 76 : G_LOCK (uid_cache);
1232 : 76 : data = lookup_uid_data (uid);
1233 : 76 : res = g_strdup (data->user_name);
1234 : 76 : G_UNLOCK (uid_cache);
1235 : :
1236 : 76 : return res;
1237 : : }
1238 : :
1239 : : static char *
1240 : 76 : get_realname_from_uid (uid_t uid)
1241 : : {
1242 : : char *res;
1243 : : UidData *data;
1244 : :
1245 : 76 : G_LOCK (uid_cache);
1246 : 76 : data = lookup_uid_data (uid);
1247 : 76 : res = g_strdup (data->real_name);
1248 : 76 : G_UNLOCK (uid_cache);
1249 : :
1250 : 76 : return res;
1251 : : }
1252 : :
1253 : : /* called with lock held */
1254 : : static char *
1255 : 76 : lookup_gid_name (gid_t gid)
1256 : : {
1257 : : char *name;
1258 : : #if defined (HAVE_GETGRGID_R)
1259 : : char buffer[4096];
1260 : : struct group gbuf;
1261 : : #endif
1262 : : struct group *gbufp;
1263 : :
1264 [ + + ]: 76 : if (gid_cache == NULL)
1265 : 1 : gid_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free);
1266 : :
1267 : 76 : name = g_hash_table_lookup (gid_cache, GINT_TO_POINTER (gid));
1268 : :
1269 [ + + ]: 76 : if (name)
1270 : 75 : return name;
1271 : :
1272 : : #if defined (HAVE_GETGRGID_R)
1273 : 1 : getgrgid_r (gid, &gbuf, buffer, sizeof(buffer), &gbufp);
1274 : : #else
1275 : : gbufp = getgrgid (gid);
1276 : : #endif
1277 : :
1278 [ + - ]: 1 : if (gbufp != NULL &&
1279 [ + - ]: 1 : gbufp->gr_name != NULL &&
1280 [ + - ]: 1 : gbufp->gr_name[0] != 0)
1281 : 1 : name = convert_pwd_string_to_utf8 (gbufp->gr_name);
1282 : : else
1283 : 0 : name = g_strdup_printf("%d", (int)gid);
1284 : :
1285 : 1 : g_hash_table_replace (gid_cache, GINT_TO_POINTER (gid), name);
1286 : :
1287 : 1 : return name;
1288 : : }
1289 : :
1290 : : static char *
1291 : 76 : get_groupname_from_gid (gid_t gid)
1292 : : {
1293 : : char *res;
1294 : : char *name;
1295 : :
1296 : 76 : G_LOCK (gid_cache);
1297 : 76 : name = lookup_gid_name (gid);
1298 : 76 : res = g_strdup (name);
1299 : 76 : G_UNLOCK (gid_cache);
1300 : 76 : return res;
1301 : : }
1302 : :
1303 : : #endif /* !G_OS_WIN32 */
1304 : :
1305 : : static char *
1306 : 162 : get_content_type (const char *basename,
1307 : : const char *path,
1308 : : GLocalFileStat *statbuf,
1309 : : gboolean is_symlink,
1310 : : gboolean symlink_broken,
1311 : : GFileQueryInfoFlags flags,
1312 : : gboolean fast)
1313 : : {
1314 [ + + + - ]: 162 : if (is_symlink &&
1315 [ + - ]: 14 : (symlink_broken || (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)))
1316 : 14 : return g_content_type_from_mime_type ("inode/symlink");
1317 [ + - + + ]: 148 : else if (statbuf != NULL && S_ISDIR(_g_stat_mode (statbuf)))
1318 : 48 : return g_content_type_from_mime_type ("inode/directory");
1319 : : #ifndef G_OS_WIN32
1320 [ + - - + ]: 100 : else if (statbuf != NULL && S_ISCHR(_g_stat_mode (statbuf)))
1321 : 0 : return g_content_type_from_mime_type ("inode/chardevice");
1322 [ + - - + ]: 100 : else if (statbuf != NULL && S_ISBLK(_g_stat_mode (statbuf)))
1323 : 0 : return g_content_type_from_mime_type ("inode/blockdevice");
1324 [ + - - + ]: 100 : else if (statbuf != NULL && S_ISFIFO(_g_stat_mode (statbuf)))
1325 : 0 : return g_content_type_from_mime_type ("inode/fifo");
1326 [ + - + - : 100 : else if (statbuf != NULL && S_ISREG(_g_stat_mode (statbuf)) && _g_stat_size (statbuf) == 0)
+ + ]
1327 : : {
1328 : : /* Don't sniff zero-length files in order to avoid reading files
1329 : : * that appear normal but are not (eg: files in /proc and /sys)
1330 : : */
1331 : 80 : return g_content_type_from_mime_type ("application/x-zerosize");
1332 : : }
1333 : : #endif
1334 : : #ifdef S_ISSOCK
1335 [ + - - + ]: 20 : else if (statbuf != NULL && S_ISSOCK(_g_stat_mode (statbuf)))
1336 : 0 : return g_content_type_from_mime_type ("inode/socket");
1337 : : #endif
1338 : : else
1339 : : {
1340 : : char *content_type;
1341 : : gboolean result_uncertain;
1342 : :
1343 : 20 : content_type = g_content_type_guess (basename, NULL, 0, &result_uncertain);
1344 : :
1345 : : #if !defined(G_OS_WIN32) && !defined(__APPLE__)
1346 [ + + + - : 20 : if (!fast && result_uncertain && path != NULL)
+ - ]
1347 : : {
1348 : : /* Sniff the first 16KiB of the file (sometimes less, if xdgmime
1349 : : * says it doesn’t need so much). Most files need less than 4KiB of
1350 : : * sniffing, but some disk images need more (see
1351 : : * https://gitlab.gnome.org/GNOME/glib/-/issues/3186). */
1352 : : guchar sniff_buffer[16384];
1353 : : gsize sniff_length;
1354 : : #ifdef O_NOATIME
1355 : : int errsv;
1356 : : #endif
1357 : : int fd;
1358 : :
1359 : 10 : sniff_length = _g_unix_content_type_get_sniff_len ();
1360 [ + + + - ]: 10 : if (sniff_length == 0 || sniff_length > sizeof (sniff_buffer))
1361 : 10 : sniff_length = sizeof (sniff_buffer);
1362 : :
1363 : : #ifdef O_NOATIME
1364 : 10 : fd = g_open (path, O_RDONLY | O_NOATIME | O_CLOEXEC, 0);
1365 : 10 : errsv = errno;
1366 [ - + - - ]: 10 : if (fd < 0 && errsv == EPERM)
1367 : : #endif
1368 : 0 : fd = g_open (path, O_RDONLY | O_CLOEXEC, 0);
1369 : :
1370 [ + - ]: 10 : if (fd != -1)
1371 : : {
1372 : : gssize res;
1373 : :
1374 : 10 : res = read (fd, sniff_buffer, sniff_length);
1375 : 10 : (void) g_close (fd, NULL);
1376 [ + - ]: 10 : if (res >= 0)
1377 : : {
1378 : 10 : g_free (content_type);
1379 : 10 : content_type = g_content_type_guess (basename, sniff_buffer, res, NULL);
1380 : : }
1381 : : }
1382 : : }
1383 : : #endif
1384 : :
1385 : 20 : return content_type;
1386 : : }
1387 : :
1388 : : }
1389 : :
1390 : : typedef enum {
1391 : : THUMBNAIL_SIZE_AUTO,
1392 : : THUMBNAIL_SIZE_NORMAL,
1393 : : THUMBNAIL_SIZE_LARGE,
1394 : : THUMBNAIL_SIZE_XLARGE,
1395 : : THUMBNAIL_SIZE_XXLARGE,
1396 : : THUMBNAIL_SIZE_LAST,
1397 : : } ThumbnailSize;
1398 : :
1399 : : static const char *
1400 : 988 : get_thumbnail_dirname_from_size (ThumbnailSize size)
1401 : : {
1402 [ + + + + : 988 : switch (size)
+ - ]
1403 : : {
1404 : 191 : case THUMBNAIL_SIZE_AUTO:
1405 : 191 : return NULL;
1406 : : break;
1407 : 194 : case THUMBNAIL_SIZE_NORMAL:
1408 : 194 : return "normal";
1409 : : break;
1410 : 197 : case THUMBNAIL_SIZE_LARGE:
1411 : 197 : return "large";
1412 : : break;
1413 : 200 : case THUMBNAIL_SIZE_XLARGE:
1414 : 200 : return "x-large";
1415 : : break;
1416 : 206 : case THUMBNAIL_SIZE_XXLARGE:
1417 : 206 : return "xx-large";
1418 : : break;
1419 : 0 : default:
1420 : : g_assert_not_reached ();
1421 : : }
1422 : :
1423 : : g_return_val_if_reached (NULL);
1424 : : }
1425 : :
1426 : : /* @stat_buf is the pre-calculated result of stat(path), or %NULL if that failed. */
1427 : : static void
1428 : 515 : get_thumbnail_attributes (const char *path,
1429 : : GFileInfo *info,
1430 : : const GLocalFileStat *stat_buf,
1431 : : ThumbnailSize size)
1432 : : {
1433 : : GChecksum *checksum;
1434 : : const char *dirname;
1435 : : char *uri;
1436 : 515 : char *filename = NULL;
1437 : : char *basename;
1438 : : guint32 failed_attr_id;
1439 : : guint32 is_valid_attr_id;
1440 : : guint32 path_attr_id;
1441 : :
1442 [ + + + + : 515 : switch (size)
+ - ]
1443 : : {
1444 : 103 : case THUMBNAIL_SIZE_AUTO:
1445 : 103 : failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED;
1446 : 103 : is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID;
1447 : 103 : path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH;
1448 : 103 : break;
1449 : 103 : case THUMBNAIL_SIZE_NORMAL:
1450 : 103 : failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_NORMAL;
1451 : 103 : is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_NORMAL;
1452 : 103 : path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_NORMAL;
1453 : 103 : break;
1454 : 103 : case THUMBNAIL_SIZE_LARGE:
1455 : 103 : failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_LARGE;
1456 : 103 : is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_LARGE;
1457 : 103 : path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_LARGE;
1458 : 103 : break;
1459 : 103 : case THUMBNAIL_SIZE_XLARGE:
1460 : 103 : failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XLARGE;
1461 : 103 : is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XLARGE;
1462 : 103 : path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XLARGE;
1463 : 103 : break;
1464 : 103 : case THUMBNAIL_SIZE_XXLARGE:
1465 : 103 : failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XXLARGE;
1466 : 103 : is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XXLARGE;
1467 : 103 : path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XXLARGE;
1468 : 103 : break;
1469 : 0 : default:
1470 : : g_assert_not_reached ();
1471 : : }
1472 : :
1473 : 515 : dirname = get_thumbnail_dirname_from_size (size);
1474 : 515 : uri = g_filename_to_uri (path, NULL, NULL);
1475 : :
1476 : 515 : checksum = g_checksum_new (G_CHECKSUM_MD5);
1477 : 515 : g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
1478 : :
1479 : 515 : basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
1480 : 515 : g_checksum_free (checksum);
1481 : :
1482 [ + + ]: 515 : if (dirname)
1483 : : {
1484 : 412 : filename = g_build_filename (g_get_user_cache_dir (),
1485 : : "thumbnails", dirname, basename,
1486 : : NULL);
1487 : :
1488 [ + + ]: 412 : if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
1489 : 376 : g_clear_pointer (&filename, g_free);
1490 : : }
1491 : : else
1492 : : {
1493 : : gssize i;
1494 : :
1495 [ + + ]: 561 : for (i = THUMBNAIL_SIZE_LAST - 1; i >= 0 ; i--)
1496 : : {
1497 : 473 : filename = g_build_filename (g_get_user_cache_dir (),
1498 : : "thumbnails",
1499 : : get_thumbnail_dirname_from_size (i),
1500 : : basename,
1501 : : NULL);
1502 [ + + ]: 473 : if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
1503 : 15 : break;
1504 : :
1505 : 458 : g_clear_pointer (&filename, g_free);
1506 : : }
1507 : : }
1508 : :
1509 [ + + ]: 515 : if (filename)
1510 : : {
1511 : 51 : _g_file_info_set_attribute_byte_string_by_id (info, path_attr_id, filename);
1512 : 51 : _g_file_info_set_attribute_boolean_by_id (info, is_valid_attr_id,
1513 : : thumbnail_verify (filename, uri, stat_buf));
1514 : : }
1515 : : else
1516 : : {
1517 : 464 : filename = g_build_filename (g_get_user_cache_dir (),
1518 : : "thumbnails", "fail",
1519 : : "gnome-thumbnail-factory",
1520 : : basename,
1521 : : NULL);
1522 : :
1523 [ + + ]: 464 : if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
1524 : : {
1525 : 42 : _g_file_info_set_attribute_boolean_by_id (info, failed_attr_id, TRUE);
1526 : 42 : _g_file_info_set_attribute_boolean_by_id (info, is_valid_attr_id,
1527 : : thumbnail_verify (filename, uri, stat_buf));
1528 : : }
1529 : : }
1530 : :
1531 : 515 : g_free (basename);
1532 : 515 : g_free (filename);
1533 : 515 : g_free (uri);
1534 : 515 : }
1535 : :
1536 : : #ifdef G_OS_WIN32
1537 : : static void
1538 : : win32_get_file_user_info (const gchar *filename,
1539 : : gchar **group_name,
1540 : : gchar **user_name,
1541 : : gchar **real_name)
1542 : : {
1543 : : PSECURITY_DESCRIPTOR psd = NULL;
1544 : : DWORD sd_size = 0; /* first call calculates the size required */
1545 : :
1546 : : wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1547 : : if ((GetFileSecurityW (wfilename,
1548 : : GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1549 : : NULL,
1550 : : sd_size,
1551 : : &sd_size) || (ERROR_INSUFFICIENT_BUFFER == GetLastError())) &&
1552 : : (psd = g_try_malloc (sd_size)) != NULL &&
1553 : : GetFileSecurityW (wfilename,
1554 : : GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1555 : : psd,
1556 : : sd_size,
1557 : : &sd_size))
1558 : : {
1559 : : PSID psid = 0;
1560 : : BOOL defaulted;
1561 : : SID_NAME_USE name_use = 0; /* don't care? */
1562 : : wchar_t *name = NULL;
1563 : : wchar_t *domain = NULL;
1564 : : DWORD name_len = 0;
1565 : : DWORD domain_len = 0;
1566 : : /* get the user name */
1567 : : do {
1568 : : if (!user_name)
1569 : : break;
1570 : : if (!GetSecurityDescriptorOwner (psd, &psid, &defaulted))
1571 : : break;
1572 : : if (!LookupAccountSidW (NULL, /* local machine */
1573 : : psid,
1574 : : name, &name_len,
1575 : : domain, &domain_len, /* no domain info yet */
1576 : : &name_use) && (ERROR_INSUFFICIENT_BUFFER != GetLastError()))
1577 : : break;
1578 : : name = g_try_malloc (name_len * sizeof (wchar_t));
1579 : : domain = g_try_malloc (domain_len * sizeof (wchar_t));
1580 : : if (name && domain &&
1581 : : LookupAccountSidW (NULL, /* local machine */
1582 : : psid,
1583 : : name, &name_len,
1584 : : domain, &domain_len, /* no domain info yet */
1585 : : &name_use))
1586 : : {
1587 : : *user_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
1588 : : }
1589 : : g_free (name);
1590 : : g_free (domain);
1591 : : } while (FALSE);
1592 : :
1593 : : /* get the group name */
1594 : : do {
1595 : : if (!group_name)
1596 : : break;
1597 : : if (!GetSecurityDescriptorGroup (psd, &psid, &defaulted))
1598 : : break;
1599 : : if (!LookupAccountSidW (NULL, /* local machine */
1600 : : psid,
1601 : : name, &name_len,
1602 : : domain, &domain_len, /* no domain info yet */
1603 : : &name_use) && (ERROR_INSUFFICIENT_BUFFER != GetLastError()))
1604 : : break;
1605 : : name = g_try_malloc (name_len * sizeof (wchar_t));
1606 : : domain = g_try_malloc (domain_len * sizeof (wchar_t));
1607 : : if (name && domain &&
1608 : : LookupAccountSidW (NULL, /* local machine */
1609 : : psid,
1610 : : name, &name_len,
1611 : : domain, &domain_len, /* no domain info yet */
1612 : : &name_use))
1613 : : {
1614 : : *group_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
1615 : : }
1616 : : g_free (name);
1617 : : g_free (domain);
1618 : : } while (FALSE);
1619 : :
1620 : : /* TODO: get real name */
1621 : :
1622 : : g_free (psd);
1623 : : }
1624 : : g_free (wfilename);
1625 : : }
1626 : : #endif /* G_OS_WIN32 */
1627 : :
1628 : : #ifndef G_OS_WIN32
1629 : : /* support for '.hidden' files */
1630 : : G_LOCK_DEFINE_STATIC (hidden_cache);
1631 : : static GHashTable *hidden_cache;
1632 : : static GSource *hidden_cache_source = NULL; /* Under the hidden_cache lock */
1633 : : static guint hidden_cache_ttl_secs = 5;
1634 : : static guint hidden_cache_ttl_jitter_secs = 2;
1635 : :
1636 : : typedef struct
1637 : : {
1638 : : GHashTable *hidden_files;
1639 : : gint64 timestamp_secs;
1640 : : } HiddenCacheData;
1641 : :
1642 : : static gboolean
1643 : 0 : remove_from_hidden_cache (gpointer user_data)
1644 : : {
1645 : : HiddenCacheData *data;
1646 : : GHashTableIter iter;
1647 : : gboolean retval;
1648 : : gint64 timestamp_secs;
1649 : :
1650 : 0 : G_LOCK (hidden_cache);
1651 : 0 : timestamp_secs = g_source_get_time (hidden_cache_source) / G_USEC_PER_SEC;
1652 : :
1653 : 0 : g_hash_table_iter_init (&iter, hidden_cache);
1654 [ # # ]: 0 : while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data))
1655 : : {
1656 [ # # ]: 0 : if (timestamp_secs > data->timestamp_secs + hidden_cache_ttl_secs)
1657 : 0 : g_hash_table_iter_remove (&iter);
1658 : : }
1659 : :
1660 [ # # ]: 0 : if (g_hash_table_size (hidden_cache) == 0)
1661 : : {
1662 : 0 : g_clear_pointer (&hidden_cache_source, g_source_unref);
1663 : 0 : retval = G_SOURCE_REMOVE;
1664 : : }
1665 : : else
1666 : 0 : retval = G_SOURCE_CONTINUE;
1667 : :
1668 : 0 : G_UNLOCK (hidden_cache);
1669 : :
1670 : 0 : return retval;
1671 : : }
1672 : :
1673 : : static GHashTable *
1674 : 4 : read_hidden_file (const gchar *dirname)
1675 : : {
1676 : 4 : gchar *contents = NULL;
1677 : : gchar *filename;
1678 : :
1679 : 4 : filename = g_build_path ("/", dirname, ".hidden", NULL);
1680 : 4 : (void) g_file_get_contents (filename, &contents, NULL, NULL);
1681 : 4 : g_free (filename);
1682 : :
1683 [ + + ]: 4 : if (contents != NULL)
1684 : : {
1685 : : GHashTable *table;
1686 : : gchar **lines;
1687 : : gint i;
1688 : :
1689 : 1 : table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1690 : :
1691 : 1 : lines = g_strsplit (contents, "\n", 0);
1692 : 1 : g_free (contents);
1693 : :
1694 [ + + ]: 4 : for (i = 0; lines[i]; i++)
1695 : : /* hash table takes the individual strings... */
1696 : 3 : g_hash_table_add (table, lines[i]);
1697 : :
1698 : : /* ... so we only free the container. */
1699 : 1 : g_free (lines);
1700 : :
1701 : 1 : return table;
1702 : : }
1703 : : else
1704 : 3 : return NULL;
1705 : : }
1706 : :
1707 : : static void
1708 : 0 : free_hidden_file_data (gpointer user_data)
1709 : : {
1710 : 0 : HiddenCacheData *data = user_data;
1711 : :
1712 : 0 : g_clear_pointer (&data->hidden_files, g_hash_table_unref);
1713 : 0 : g_free (data);
1714 : 0 : }
1715 : :
1716 : : static gboolean
1717 : 71 : file_is_hidden (const gchar *path,
1718 : : const gchar *basename)
1719 : : {
1720 : : HiddenCacheData *data;
1721 : : gboolean result;
1722 : : gchar *dirname;
1723 : : gpointer table;
1724 : :
1725 : 71 : dirname = g_path_get_dirname (path);
1726 : :
1727 : 71 : G_LOCK (hidden_cache);
1728 : :
1729 [ + + ]: 71 : if G_UNLIKELY (hidden_cache == NULL)
1730 : 1 : hidden_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
1731 : : g_free, free_hidden_file_data);
1732 : :
1733 [ + + ]: 71 : if (!g_hash_table_lookup_extended (hidden_cache, dirname,
1734 : : NULL, (gpointer *) &data))
1735 : : {
1736 : 4 : data = g_new0 (HiddenCacheData, 1);
1737 : 4 : data->hidden_files = table = read_hidden_file (dirname);
1738 : 4 : data->timestamp_secs = g_get_monotonic_time () / G_USEC_PER_SEC;
1739 : :
1740 : 4 : g_hash_table_insert (hidden_cache,
1741 : 4 : g_strdup (dirname),
1742 : : data);
1743 : :
1744 [ + + ]: 4 : if (!hidden_cache_source)
1745 : : {
1746 : 1 : hidden_cache_source =
1747 : 1 : g_timeout_source_new_seconds (hidden_cache_ttl_secs +
1748 : : hidden_cache_ttl_jitter_secs);
1749 : 1 : g_source_set_priority (hidden_cache_source, G_PRIORITY_DEFAULT);
1750 : 1 : g_source_set_static_name (hidden_cache_source,
1751 : : "[gio] remove_from_hidden_cache");
1752 : 1 : g_source_set_callback (hidden_cache_source,
1753 : : remove_from_hidden_cache,
1754 : : NULL, NULL);
1755 : 1 : g_source_attach (hidden_cache_source,
1756 : 1 : GLIB_PRIVATE_CALL (g_get_worker_context) ());
1757 : : }
1758 : : }
1759 : : else
1760 : 67 : table = data->hidden_files;
1761 : :
1762 [ + + + - ]: 71 : result = table != NULL && g_hash_table_contains (table, basename);
1763 : :
1764 : 71 : G_UNLOCK (hidden_cache);
1765 : :
1766 : 71 : g_free (dirname);
1767 : :
1768 : 71 : return result;
1769 : : }
1770 : : #endif /* !G_OS_WIN32 */
1771 : :
1772 : : void
1773 : 1487 : _g_local_file_info_get_nostat (GFileInfo *info,
1774 : : const char *basename,
1775 : : const char *path,
1776 : : GFileAttributeMatcher *attribute_matcher)
1777 : : {
1778 : 1487 : g_file_info_set_name (info, basename);
1779 : :
1780 [ + + ]: 1487 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
1781 : : G_FILE_ATTRIBUTE_ID_STANDARD_DISPLAY_NAME))
1782 : : {
1783 : 131 : char *display_name = g_filename_display_basename (path);
1784 : :
1785 : : /* look for U+FFFD REPLACEMENT CHARACTER */
1786 [ - + ]: 131 : if (strstr (display_name, "\357\277\275") != NULL)
1787 : : {
1788 : 0 : char *p = display_name;
1789 : 0 : display_name = g_strconcat (display_name, _(" (invalid encoding)"), NULL);
1790 : 0 : g_free (p);
1791 : : }
1792 : 131 : g_file_info_set_display_name (info, display_name);
1793 : 131 : g_free (display_name);
1794 : : }
1795 : :
1796 [ + + ]: 1487 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
1797 : : G_FILE_ATTRIBUTE_ID_STANDARD_EDIT_NAME))
1798 : : {
1799 : 131 : char *edit_name = g_filename_display_basename (path);
1800 : 131 : g_file_info_set_edit_name (info, edit_name);
1801 : 131 : g_free (edit_name);
1802 : : }
1803 : :
1804 : :
1805 [ + + ]: 1487 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
1806 : : G_FILE_ATTRIBUTE_ID_STANDARD_COPY_NAME))
1807 : : {
1808 : 131 : char *copy_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
1809 [ + - ]: 131 : if (copy_name)
1810 : 131 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_COPY_NAME, copy_name);
1811 : 131 : g_free (copy_name);
1812 : : }
1813 : 1487 : }
1814 : :
1815 : : static const char *
1816 : 152 : get_icon_name (const char *path,
1817 : : gboolean use_symbolic,
1818 : : gboolean *with_fallbacks_out)
1819 : : {
1820 : 152 : const char *name = NULL;
1821 : 152 : gboolean with_fallbacks = TRUE;
1822 : :
1823 [ - + ]: 152 : if (g_strcmp0 (path, g_get_home_dir ()) == 0)
1824 : : {
1825 [ # # ]: 0 : name = use_symbolic ? "user-home-symbolic" : "user-home";
1826 : 0 : with_fallbacks = FALSE;
1827 : : }
1828 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0)
1829 : : {
1830 [ # # ]: 0 : name = use_symbolic ? "user-desktop-symbolic" : "user-desktop";
1831 : 0 : with_fallbacks = FALSE;
1832 : : }
1833 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)) == 0)
1834 : : {
1835 [ # # ]: 0 : name = use_symbolic ? "folder-documents-symbolic" : "folder-documents";
1836 : : }
1837 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD)) == 0)
1838 : : {
1839 [ # # ]: 0 : name = use_symbolic ? "folder-download-symbolic" : "folder-download";
1840 : : }
1841 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_MUSIC)) == 0)
1842 : : {
1843 [ # # ]: 0 : name = use_symbolic ? "folder-music-symbolic" : "folder-music";
1844 : : }
1845 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)) == 0)
1846 : : {
1847 [ # # ]: 0 : name = use_symbolic ? "folder-pictures-symbolic" : "folder-pictures";
1848 : : }
1849 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE)) == 0)
1850 : : {
1851 [ # # ]: 0 : name = use_symbolic ? "folder-publicshare-symbolic" : "folder-publicshare";
1852 : : }
1853 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES)) == 0)
1854 : : {
1855 [ # # ]: 0 : name = use_symbolic ? "folder-templates-symbolic" : "folder-templates";
1856 : : }
1857 [ - + ]: 152 : else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS)) == 0)
1858 : : {
1859 [ # # ]: 0 : name = use_symbolic ? "folder-videos-symbolic" : "folder-videos";
1860 : : }
1861 : : else
1862 : : {
1863 : 152 : name = NULL;
1864 : : }
1865 : :
1866 [ + - ]: 152 : if (with_fallbacks_out != NULL)
1867 : 152 : *with_fallbacks_out = with_fallbacks;
1868 : :
1869 : 152 : return name;
1870 : : }
1871 : :
1872 : : static GIcon *
1873 : 152 : get_icon (const char *path,
1874 : : const char *content_type,
1875 : : gboolean use_symbolic)
1876 : : {
1877 : 152 : GIcon *icon = NULL;
1878 : : const char *icon_name;
1879 : : gboolean with_fallbacks;
1880 : :
1881 : 152 : icon_name = get_icon_name (path, use_symbolic, &with_fallbacks);
1882 [ - + ]: 152 : if (icon_name != NULL)
1883 : : {
1884 [ # # ]: 0 : if (with_fallbacks)
1885 : 0 : icon = g_themed_icon_new_with_default_fallbacks (icon_name);
1886 : : else
1887 : 0 : icon = g_themed_icon_new (icon_name);
1888 : : }
1889 : : else
1890 : : {
1891 [ + + ]: 152 : if (use_symbolic)
1892 : 76 : icon = g_content_type_get_symbolic_icon (content_type);
1893 : : else
1894 : 76 : icon = g_content_type_get_icon (content_type);
1895 : : }
1896 : :
1897 : 152 : return icon;
1898 : : }
1899 : :
1900 : : GFileInfo *
1901 : 1131 : _g_local_file_info_get (const char *basename,
1902 : : const char *path,
1903 : : GFileAttributeMatcher *attribute_matcher,
1904 : : GFileQueryInfoFlags flags,
1905 : : GLocalParentFileInfo *parent_info,
1906 : : GError **error)
1907 : : {
1908 : : GFileInfo *info;
1909 : : GLocalFileStat statbuf;
1910 : : GLocalFileStat statbuf2;
1911 : : int res;
1912 : : gboolean stat_ok;
1913 : : gboolean is_symlink, symlink_broken;
1914 : : char *symlink_target;
1915 : : GVfs *vfs;
1916 : : GVfsClass *class;
1917 : : guint64 device;
1918 : :
1919 : 1131 : info = g_file_info_new ();
1920 : :
1921 : : /* Make sure we don't set any unwanted attributes */
1922 : 1131 : g_file_info_set_attribute_mask (info, attribute_matcher);
1923 : :
1924 : 1131 : _g_local_file_info_get_nostat (info, basename, path, attribute_matcher);
1925 : :
1926 [ + + ]: 1131 : if (attribute_matcher == NULL)
1927 : : {
1928 : 301 : g_file_info_unset_attribute_mask (info);
1929 : 301 : return info;
1930 : : }
1931 : :
1932 : 830 : res = g_local_file_lstat (path,
1933 : : G_LOCAL_FILE_STAT_FIELD_BASIC_STATS | G_LOCAL_FILE_STAT_FIELD_BTIME,
1934 : : G_LOCAL_FILE_STAT_FIELD_ALL & (~G_LOCAL_FILE_STAT_FIELD_BTIME) & (~G_LOCAL_FILE_STAT_FIELD_ATIME),
1935 : : &statbuf);
1936 : :
1937 [ + + ]: 830 : if (res == -1)
1938 : : {
1939 : 110 : int errsv = errno;
1940 : :
1941 : : /* Don't bail out if we get Permission denied (SELinux?) */
1942 [ + + ]: 110 : if (errsv != EACCES)
1943 : : {
1944 : 108 : char *display_name = g_filename_display_name (path);
1945 : 108 : g_object_unref (info);
1946 : 216 : g_set_error (error, G_IO_ERROR,
1947 : 108 : g_io_error_from_errno (errsv),
1948 : : _("Error when getting information for file “%s”: %s"),
1949 : : display_name, g_strerror (errsv));
1950 : 108 : g_free (display_name);
1951 : 108 : return NULL;
1952 : : }
1953 : : }
1954 : :
1955 : : /* Even if stat() fails, try to get as much as other attributes possible */
1956 : 722 : stat_ok = res != -1;
1957 : :
1958 [ + + ]: 722 : if (stat_ok)
1959 : 720 : device = _g_stat_dev (&statbuf);
1960 : : else
1961 : 2 : device = 0;
1962 : :
1963 : : #ifdef S_ISLNK
1964 [ + + + + ]: 722 : is_symlink = stat_ok && S_ISLNK (_g_stat_mode (&statbuf));
1965 : : #elif defined (G_OS_WIN32)
1966 : : /* glib already checked the FILE_ATTRIBUTE_REPARSE_POINT for us */
1967 : : is_symlink = stat_ok &&
1968 : : (statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK ||
1969 : : statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT);
1970 : : #else
1971 : : is_symlink = FALSE;
1972 : : #endif
1973 : 722 : symlink_broken = FALSE;
1974 : :
1975 [ + + ]: 722 : if (is_symlink)
1976 : : {
1977 : 59 : g_file_info_set_is_symlink (info, TRUE);
1978 : :
1979 : : /* Unless NOFOLLOW was set we default to following symlinks */
1980 [ + + ]: 59 : if (!(flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS))
1981 : : {
1982 : 14 : res = g_local_file_stat (path,
1983 : : G_LOCAL_FILE_STAT_FIELD_BASIC_STATS | G_LOCAL_FILE_STAT_FIELD_BTIME,
1984 : : G_LOCAL_FILE_STAT_FIELD_ALL & (~G_LOCAL_FILE_STAT_FIELD_BTIME) & (~G_LOCAL_FILE_STAT_FIELD_ATIME),
1985 : : &statbuf2);
1986 : :
1987 : : /* Report broken links as symlinks */
1988 [ + + ]: 14 : if (res != -1)
1989 : : {
1990 : 12 : statbuf = statbuf2;
1991 : 12 : stat_ok = TRUE;
1992 : : }
1993 : : else
1994 : 2 : symlink_broken = TRUE;
1995 : : }
1996 : : }
1997 : : else
1998 : 663 : g_file_info_set_is_symlink (info, FALSE);
1999 : :
2000 [ + + ]: 722 : if (stat_ok)
2001 : 720 : set_info_from_stat (info, &statbuf, attribute_matcher);
2002 : :
2003 : : #ifndef G_OS_WIN32
2004 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2005 : : G_FILE_ATTRIBUTE_ID_STANDARD_IS_HIDDEN))
2006 : : {
2007 [ + - ]: 152 : g_file_info_set_is_hidden (info,
2008 : : (basename != NULL &&
2009 [ + + + + ]: 147 : (basename[0] == '.' ||
2010 [ + - ]: 136 : file_is_hidden (path, basename) ||
2011 [ - + ]: 65 : (stat_ok &&
2012 : 65 : _g_local_file_is_lost_found_dir (path, _g_stat_dev (&statbuf))))));
2013 : : }
2014 : :
2015 [ + - + - ]: 1604 : _g_file_info_set_attribute_boolean_by_id (info,
2016 : : G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP,
2017 [ + + ]: 722 : basename != NULL && basename[strlen (basename) - 1] == '~' &&
2018 [ + + ]: 160 : (stat_ok && S_ISREG (_g_stat_mode (&statbuf))));
2019 : : #else
2020 : : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP, FALSE);
2021 : :
2022 : : g_file_info_set_is_hidden (info, (statbuf.attributes & FILE_ATTRIBUTE_HIDDEN));
2023 : :
2024 : : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_ARCHIVE,
2025 : : (statbuf.attributes & FILE_ATTRIBUTE_ARCHIVE));
2026 : :
2027 : : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_SYSTEM,
2028 : : (statbuf.attributes & FILE_ATTRIBUTE_SYSTEM));
2029 : :
2030 : : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_MOUNTPOINT,
2031 : : (statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT));
2032 : :
2033 : : if (statbuf.reparse_tag != 0)
2034 : : _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_REPARSE_POINT_TAG, statbuf.reparse_tag);
2035 : :
2036 : : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP, FALSE);
2037 : : #endif
2038 : :
2039 : 722 : symlink_target = NULL;
2040 [ + + ]: 722 : if (is_symlink)
2041 : : {
2042 : : #if defined (S_ISLNK) || defined (G_OS_WIN32)
2043 : 59 : symlink_target = read_link (path);
2044 : : #endif
2045 [ + - + + ]: 118 : if (symlink_target &&
2046 : 59 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2047 : : G_FILE_ATTRIBUTE_ID_STANDARD_SYMLINK_TARGET))
2048 : 32 : g_file_info_set_symlink_target (info, symlink_target);
2049 : : }
2050 : :
2051 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2052 [ + - ]: 640 : G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
2053 : 640 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2054 [ - + ]: 640 : G_FILE_ATTRIBUTE_ID_STANDARD_ICON) ||
2055 : 640 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2056 : : G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON))
2057 : : {
2058 [ + - ]: 82 : char *content_type = get_content_type (basename, path, stat_ok ? &statbuf : NULL, is_symlink, symlink_broken, flags, FALSE);
2059 : :
2060 [ + - ]: 82 : if (content_type)
2061 : : {
2062 : 82 : g_file_info_set_content_type (info, content_type);
2063 : :
2064 [ + + ]: 82 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2065 : : G_FILE_ATTRIBUTE_ID_STANDARD_ICON)
2066 [ - + ]: 6 : || _g_file_attribute_matcher_matches_id (attribute_matcher,
2067 : : G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON))
2068 : : {
2069 : : GIcon *icon;
2070 : :
2071 : : /* non symbolic icon */
2072 : 76 : icon = get_icon (path, content_type, FALSE);
2073 [ + - ]: 76 : if (icon != NULL)
2074 : : {
2075 : 76 : g_file_info_set_icon (info, icon);
2076 : 76 : g_object_unref (icon);
2077 : : }
2078 : :
2079 : : /* symbolic icon */
2080 : 76 : icon = get_icon (path, content_type, TRUE);
2081 [ + - ]: 76 : if (icon != NULL)
2082 : : {
2083 : 76 : g_file_info_set_symbolic_icon (info, icon);
2084 : 76 : g_object_unref (icon);
2085 : : }
2086 : :
2087 : : }
2088 : :
2089 : 82 : g_free (content_type);
2090 : : }
2091 : : }
2092 : :
2093 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2094 : : G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))
2095 : : {
2096 [ + - ]: 80 : char *content_type = get_content_type (basename, path, stat_ok ? &statbuf : NULL, is_symlink, symlink_broken, flags, TRUE);
2097 : :
2098 [ + - ]: 80 : if (content_type)
2099 : : {
2100 : 80 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type);
2101 : 80 : g_free (content_type);
2102 : : }
2103 : : }
2104 : :
2105 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2106 : : G_FILE_ATTRIBUTE_ID_OWNER_USER))
2107 : : {
2108 : 76 : char *name = NULL;
2109 : :
2110 : : #ifdef G_OS_WIN32
2111 : : win32_get_file_user_info (path, NULL, &name, NULL);
2112 : : #else
2113 [ + - ]: 76 : if (stat_ok)
2114 : 76 : name = get_username_from_uid (_g_stat_uid (&statbuf));
2115 : : #endif
2116 [ + - ]: 76 : if (name)
2117 : 76 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_USER, name);
2118 : 76 : g_free (name);
2119 : : }
2120 : :
2121 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2122 : : G_FILE_ATTRIBUTE_ID_OWNER_USER_REAL))
2123 : : {
2124 : 76 : char *name = NULL;
2125 : : #ifdef G_OS_WIN32
2126 : : win32_get_file_user_info (path, NULL, NULL, &name);
2127 : : #else
2128 [ + - ]: 76 : if (stat_ok)
2129 : 76 : name = get_realname_from_uid (_g_stat_uid (&statbuf));
2130 : : #endif
2131 [ + - ]: 76 : if (name)
2132 : 76 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_USER_REAL, name);
2133 : 76 : g_free (name);
2134 : : }
2135 : :
2136 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2137 : : G_FILE_ATTRIBUTE_ID_OWNER_GROUP))
2138 : : {
2139 : 76 : char *name = NULL;
2140 : : #ifdef G_OS_WIN32
2141 : : win32_get_file_user_info (path, &name, NULL, NULL);
2142 : : #else
2143 [ + - ]: 76 : if (stat_ok)
2144 : 76 : name = get_groupname_from_gid (_g_stat_gid (&statbuf));
2145 : : #endif
2146 [ + - ]: 76 : if (name)
2147 : 76 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_GROUP, name);
2148 : 76 : g_free (name);
2149 : : }
2150 : :
2151 [ + + + - : 839 : if (stat_ok && parent_info && parent_info->device != 0 &&
+ + + + ]
2152 : 117 : _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT))
2153 : 78 : _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT,
2154 [ + + + + ]: 78 : (_g_stat_dev (&statbuf) != parent_info->device || _g_stat_ino (&statbuf) == parent_info->inode));
2155 : :
2156 [ + + ]: 722 : if (stat_ok)
2157 : 720 : get_access_rights (attribute_matcher, info, path, &statbuf, parent_info);
2158 : :
2159 : : #ifdef HAVE_SELINUX
2160 : 722 : get_selinux_context (path, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0);
2161 : : #endif
2162 : 722 : get_xattrs (path, TRUE, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0);
2163 : 722 : get_xattrs (path, FALSE, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0);
2164 : :
2165 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2166 [ + - ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH) ||
2167 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2168 [ - + ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID) ||
2169 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2170 : : G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED))
2171 : : {
2172 [ + - ]: 103 : get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_AUTO);
2173 : : }
2174 : :
2175 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2176 [ + - ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_NORMAL) ||
2177 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2178 [ - + ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_NORMAL) ||
2179 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2180 : : G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_NORMAL))
2181 : : {
2182 [ + - ]: 103 : get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_NORMAL);
2183 : : }
2184 : :
2185 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2186 [ + - ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_LARGE) ||
2187 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2188 [ - + ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_LARGE) ||
2189 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2190 : : G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_LARGE))
2191 : : {
2192 [ + - ]: 103 : get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_LARGE);
2193 : : }
2194 : :
2195 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2196 [ + - ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XLARGE) ||
2197 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2198 [ - + ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XLARGE) ||
2199 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2200 : : G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XLARGE))
2201 : : {
2202 [ + - ]: 103 : get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XLARGE);
2203 : : }
2204 : :
2205 [ + + ]: 722 : if (_g_file_attribute_matcher_matches_id (attribute_matcher,
2206 [ + - ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XXLARGE) ||
2207 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2208 [ - + ]: 619 : G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XXLARGE) ||
2209 : 619 : _g_file_attribute_matcher_matches_id (attribute_matcher,
2210 : : G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XXLARGE))
2211 : : {
2212 [ + - ]: 103 : get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XXLARGE);
2213 : : }
2214 : :
2215 : 722 : vfs = g_vfs_get_default ();
2216 : 722 : class = G_VFS_GET_CLASS (vfs);
2217 [ - + ]: 722 : if (class->local_file_add_info)
2218 : : {
2219 : 0 : class->local_file_add_info (vfs,
2220 : : path,
2221 : : device,
2222 : : attribute_matcher,
2223 : : info,
2224 : : NULL,
2225 : : &parent_info->extra_data,
2226 : : &parent_info->free_extra_data);
2227 : : }
2228 : :
2229 : 722 : g_file_info_unset_attribute_mask (info);
2230 : :
2231 : 722 : g_free (symlink_target);
2232 : :
2233 : 722 : return info;
2234 : : }
2235 : :
2236 : : GFileInfo *
2237 : 68 : _g_local_file_info_get_from_fd (int fd,
2238 : : const char *attributes,
2239 : : GError **error)
2240 : : {
2241 : : GLocalFileStat stat_buf;
2242 : : GFileAttributeMatcher *matcher;
2243 : : GFileInfo *info;
2244 : :
2245 [ - + ]: 68 : if (g_local_file_fstat (fd,
2246 : : G_LOCAL_FILE_STAT_FIELD_BASIC_STATS | G_LOCAL_FILE_STAT_FIELD_BTIME,
2247 : : G_LOCAL_FILE_STAT_FIELD_ALL & (~G_LOCAL_FILE_STAT_FIELD_BTIME) & (~G_LOCAL_FILE_STAT_FIELD_ATIME),
2248 : : &stat_buf) == -1)
2249 : : {
2250 : 0 : int errsv = errno;
2251 : :
2252 : 0 : g_set_error (error, G_IO_ERROR,
2253 : 0 : g_io_error_from_errno (errsv),
2254 : : _("Error when getting information for file descriptor: %s"),
2255 : : g_strerror (errsv));
2256 : 0 : return NULL;
2257 : : }
2258 : :
2259 : 68 : info = g_file_info_new ();
2260 : :
2261 : 68 : matcher = g_file_attribute_matcher_new (attributes);
2262 : :
2263 : : /* Make sure we don't set any unwanted attributes */
2264 : 68 : g_file_info_set_attribute_mask (info, matcher);
2265 : :
2266 : 68 : set_info_from_stat (info, &stat_buf, matcher);
2267 : :
2268 : : #ifdef HAVE_SELINUX
2269 [ - + - - ]: 68 : if (_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT) &&
2270 : 0 : is_selinux_enabled ())
2271 : : {
2272 : : char *context;
2273 [ # # ]: 0 : if (fgetfilecon_raw (fd, &context) >= 0)
2274 : : {
2275 : 0 : _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT, context);
2276 : 0 : freecon (context);
2277 : : }
2278 : : }
2279 : : #endif
2280 : :
2281 : 68 : get_xattrs_from_fd (fd, TRUE, info, matcher);
2282 : 68 : get_xattrs_from_fd (fd, FALSE, info, matcher);
2283 : :
2284 : 68 : g_file_attribute_matcher_unref (matcher);
2285 : :
2286 : 68 : g_file_info_unset_attribute_mask (info);
2287 : :
2288 : 68 : return info;
2289 : : }
2290 : :
2291 : : static gboolean
2292 : 260 : get_uint32 (const GFileAttributeValue *value,
2293 : : guint32 *val_out,
2294 : : GError **error)
2295 : : {
2296 [ - + ]: 260 : if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT32)
2297 : : {
2298 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
2299 : : _("Invalid attribute type (uint32 expected)"));
2300 : 0 : return FALSE;
2301 : : }
2302 : :
2303 : 260 : *val_out = value->u.uint32;
2304 : :
2305 : 260 : return TRUE;
2306 : : }
2307 : :
2308 : : #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
2309 : : static gboolean
2310 : 38 : get_uint64 (const GFileAttributeValue *value,
2311 : : guint64 *val_out,
2312 : : GError **error)
2313 : : {
2314 [ - + ]: 38 : if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT64)
2315 : : {
2316 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
2317 : : _("Invalid attribute type (uint64 expected)"));
2318 : 0 : return FALSE;
2319 : : }
2320 : :
2321 : 38 : *val_out = value->u.uint64;
2322 : :
2323 : 38 : return TRUE;
2324 : : }
2325 : : #endif
2326 : :
2327 : : #if defined(HAVE_SYMLINK)
2328 : : static gboolean
2329 : 0 : get_byte_string (const GFileAttributeValue *value,
2330 : : const char **val_out,
2331 : : GError **error)
2332 : : {
2333 [ # # ]: 0 : if (value->type != G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
2334 : : {
2335 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
2336 : : _("Invalid attribute type (byte string expected)"));
2337 : 0 : return FALSE;
2338 : : }
2339 : :
2340 : 0 : *val_out = value->u.string;
2341 : :
2342 : 0 : return TRUE;
2343 : : }
2344 : : #endif
2345 : :
2346 : : #ifdef HAVE_SELINUX
2347 : : static gboolean
2348 : 0 : get_string (const GFileAttributeValue *value,
2349 : : const char **val_out,
2350 : : GError **error)
2351 : : {
2352 [ # # ]: 0 : if (value->type != G_FILE_ATTRIBUTE_TYPE_STRING)
2353 : : {
2354 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
2355 : : _("Invalid attribute type (byte string expected)"));
2356 : 0 : return FALSE;
2357 : : }
2358 : :
2359 : 0 : *val_out = value->u.string;
2360 : :
2361 : 0 : return TRUE;
2362 : : }
2363 : : #endif
2364 : :
2365 : : static gboolean
2366 : 171 : set_unix_mode (char *filename,
2367 : : GFileQueryInfoFlags flags,
2368 : : const GFileAttributeValue *value,
2369 : : GError **error)
2370 : : {
2371 : 171 : guint32 val = 0;
2372 : 171 : int res = 0;
2373 : :
2374 [ - + ]: 171 : if (!get_uint32 (value, &val, error))
2375 : 0 : return FALSE;
2376 : :
2377 : : #if defined (HAVE_SYMLINK) || defined (G_OS_WIN32)
2378 [ + + ]: 171 : if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) {
2379 : : #ifdef HAVE_LCHMOD
2380 : 158 : res = lchmod (filename, val);
2381 : : #else
2382 : : gboolean is_symlink;
2383 : : #ifndef G_OS_WIN32
2384 : : struct stat statbuf;
2385 : : /* Calling chmod on a symlink changes permissions on the symlink.
2386 : : * We don't want to do this, so we need to check for a symlink */
2387 : : res = g_lstat (filename, &statbuf);
2388 : : is_symlink = (res == 0 && S_ISLNK (statbuf.st_mode));
2389 : : #else
2390 : : /* FIXME: implement lchmod for W32, should be doable */
2391 : : GWin32PrivateStat statbuf;
2392 : :
2393 : : res = GLIB_PRIVATE_CALL (g_win32_lstat_utf8) (filename, &statbuf);
2394 : : is_symlink = (res == 0 &&
2395 : : (statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK ||
2396 : : statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT));
2397 : : #endif
2398 : : if (is_symlink)
2399 : : {
2400 : : g_set_error_literal (error, G_IO_ERROR,
2401 : : G_IO_ERROR_NOT_SUPPORTED,
2402 : : _("Cannot set permissions on symlinks"));
2403 : : return FALSE;
2404 : : }
2405 : : else if (res == 0)
2406 : : res = g_chmod (filename, val);
2407 : : #endif
2408 : : } else
2409 : : #endif
2410 : 13 : res = g_chmod (filename, val);
2411 : :
2412 [ - + ]: 171 : if (res == -1)
2413 : : {
2414 : 0 : int errsv = errno;
2415 : :
2416 : 0 : g_set_error (error, G_IO_ERROR,
2417 : 0 : g_io_error_from_errno (errsv),
2418 : : _("Error setting permissions: %s"),
2419 : : g_strerror (errsv));
2420 : 0 : return FALSE;
2421 : : }
2422 : 171 : return TRUE;
2423 : : }
2424 : :
2425 : : #ifdef G_OS_UNIX
2426 : : static gboolean
2427 : 6 : set_unix_uid_gid (char *filename,
2428 : : const GFileAttributeValue *uid_value,
2429 : : const GFileAttributeValue *gid_value,
2430 : : GFileQueryInfoFlags flags,
2431 : : GError **error)
2432 : : {
2433 : : int res;
2434 : 6 : guint32 val = 0;
2435 : : uid_t uid;
2436 : : gid_t gid;
2437 : :
2438 [ + - ]: 6 : if (uid_value)
2439 : : {
2440 [ - + ]: 6 : if (!get_uint32 (uid_value, &val, error))
2441 : 0 : return FALSE;
2442 : 6 : uid = val;
2443 : : }
2444 : : else
2445 : 0 : uid = -1;
2446 : :
2447 [ + - ]: 6 : if (gid_value)
2448 : : {
2449 [ - + ]: 6 : if (!get_uint32 (gid_value, &val, error))
2450 : 0 : return FALSE;
2451 : 6 : gid = val;
2452 : : }
2453 : : else
2454 : 0 : gid = -1;
2455 : :
2456 : : #ifdef HAVE_LCHOWN
2457 [ + - ]: 6 : if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)
2458 : 6 : res = lchown (filename, uid, gid);
2459 : : else
2460 : : #endif
2461 : 0 : res = chown (filename, uid, gid);
2462 : :
2463 [ - + ]: 6 : if (res == -1)
2464 : : {
2465 : 0 : int errsv = errno;
2466 : :
2467 : 0 : g_set_error (error, G_IO_ERROR,
2468 : 0 : g_io_error_from_errno (errsv),
2469 : : _("Error setting owner: %s"),
2470 : : g_strerror (errsv));
2471 : 0 : return FALSE;
2472 : : }
2473 : 6 : return TRUE;
2474 : : }
2475 : : #endif
2476 : :
2477 : : #ifdef HAVE_SYMLINK
2478 : : static gboolean
2479 : 0 : set_symlink (char *filename,
2480 : : const GFileAttributeValue *value,
2481 : : GError **error)
2482 : : {
2483 : : const char *val;
2484 : : struct stat statbuf;
2485 : :
2486 [ # # ]: 0 : if (!get_byte_string (value, &val, error))
2487 : 0 : return FALSE;
2488 : :
2489 [ # # ]: 0 : if (val == NULL)
2490 : : {
2491 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
2492 : : _("symlink must be non-NULL"));
2493 : 0 : return FALSE;
2494 : : }
2495 : :
2496 [ # # ]: 0 : if (g_lstat (filename, &statbuf))
2497 : : {
2498 : 0 : int errsv = errno;
2499 : :
2500 : 0 : g_set_error (error, G_IO_ERROR,
2501 : 0 : g_io_error_from_errno (errsv),
2502 : : _("Error setting symlink: %s"),
2503 : : g_strerror (errsv));
2504 : 0 : return FALSE;
2505 : : }
2506 : :
2507 [ # # ]: 0 : if (!S_ISLNK (statbuf.st_mode))
2508 : : {
2509 : 0 : g_set_error_literal (error, G_IO_ERROR,
2510 : : G_IO_ERROR_NOT_SYMBOLIC_LINK,
2511 : : _("Error setting symlink: file is not a symlink"));
2512 : 0 : return FALSE;
2513 : : }
2514 : :
2515 [ # # ]: 0 : if (g_unlink (filename))
2516 : : {
2517 : 0 : int errsv = errno;
2518 : :
2519 : 0 : g_set_error (error, G_IO_ERROR,
2520 : 0 : g_io_error_from_errno (errsv),
2521 : : _("Error setting symlink: %s"),
2522 : : g_strerror (errsv));
2523 : 0 : return FALSE;
2524 : : }
2525 : :
2526 [ # # ]: 0 : if (symlink (filename, val) != 0)
2527 : : {
2528 : 0 : int errsv = errno;
2529 : :
2530 : 0 : g_set_error (error, G_IO_ERROR,
2531 : 0 : g_io_error_from_errno (errsv),
2532 : : _("Error setting symlink: %s"),
2533 : : g_strerror (errsv));
2534 : 0 : return FALSE;
2535 : : }
2536 : :
2537 : 0 : return TRUE;
2538 : : }
2539 : : #endif
2540 : :
2541 : : #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined(G_OS_WIN32)
2542 : : static int
2543 : 34 : lazy_stat (const char *filename,
2544 : : GStatBuf *statbuf,
2545 : : gboolean *called_stat)
2546 : : {
2547 : : int res;
2548 : :
2549 [ + + ]: 34 : if (*called_stat)
2550 : 2 : return 0;
2551 : :
2552 : 32 : res = g_stat (filename, statbuf);
2553 : :
2554 [ + - ]: 32 : if (res == 0)
2555 : 32 : *called_stat = TRUE;
2556 : :
2557 : 32 : return res;
2558 : : }
2559 : : #endif
2560 : :
2561 : : #if defined (G_OS_WIN32)
2562 : : /* From
2563 : : * https://support.microsoft.com/en-ca/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime
2564 : : * FT = UT * 10000000 + 116444736000000000.
2565 : : * Converts unix epoch time (a signed 64-bit integer) to FILETIME.
2566 : : * Can optionally use a more precise timestamp that has
2567 : : * a fraction of a second expressed in nanoseconds.
2568 : : * UT must be between January 1st of year 1601 and December 31st of year 30827.
2569 : : * nsec must be non-negative and < 1000000000.
2570 : : * Returns TRUE if conversion succeeded, FALSE otherwise.
2571 : : *
2572 : : * The function that does the reverse can be found in
2573 : : * glib/gstdio.c.
2574 : : */
2575 : : static gboolean
2576 : : _g_win32_unix_time_to_filetime (gint64 ut,
2577 : : gint32 nsec,
2578 : : FILETIME *ft,
2579 : : GError **error)
2580 : : {
2581 : : gint64 result;
2582 : : /* 1 unit of FILETIME is 100ns */
2583 : : const gint64 hundreds_of_nsec_per_sec = 10000000;
2584 : : /* The difference between January 1, 1601 UTC (FILETIME epoch) and UNIX epoch
2585 : : * in hundreds of nanoseconds.
2586 : : */
2587 : : const gint64 filetime_unix_epoch_offset = 116444736000000000;
2588 : : /* This is the maximum timestamp that SYSTEMTIME can
2589 : : * represent (last millisecond of the year 30827).
2590 : : * Since FILETIME and SYSTEMTIME are both used on Windows,
2591 : : * we use this as a limit (FILETIME can support slightly
2592 : : * larger interval, up to year 30828).
2593 : : */
2594 : : const gint64 max_systemtime = 0x7fff35f4f06c58f0;
2595 : :
2596 : : g_return_val_if_fail (ft != NULL, FALSE);
2597 : : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2598 : :
2599 : : if (nsec < 0)
2600 : : {
2601 : : g_set_error (error, G_IO_ERROR,
2602 : : G_IO_ERROR_INVALID_DATA,
2603 : : _("Extra nanoseconds %d for UNIX timestamp %lld are negative"),
2604 : : nsec, ut);
2605 : : return FALSE;
2606 : : }
2607 : :
2608 : : if (nsec >= hundreds_of_nsec_per_sec * 100)
2609 : : {
2610 : : g_set_error (error, G_IO_ERROR,
2611 : : G_IO_ERROR_INVALID_DATA,
2612 : : _("Extra nanoseconds %d for UNIX timestamp %lld reach 1 second"),
2613 : : nsec, ut);
2614 : : return FALSE;
2615 : : }
2616 : :
2617 : : if (ut >= (G_MAXINT64 / hundreds_of_nsec_per_sec) ||
2618 : : (ut * hundreds_of_nsec_per_sec) >= (G_MAXINT64 - filetime_unix_epoch_offset))
2619 : : {
2620 : : g_set_error (error, G_IO_ERROR,
2621 : : G_IO_ERROR_INVALID_DATA,
2622 : : _("UNIX timestamp %lld does not fit into 64 bits"),
2623 : : ut);
2624 : : return FALSE;
2625 : : }
2626 : :
2627 : : result = ut * hundreds_of_nsec_per_sec + filetime_unix_epoch_offset + nsec / 100;
2628 : :
2629 : : if (result >= max_systemtime || result < 0)
2630 : : {
2631 : : g_set_error (error, G_IO_ERROR,
2632 : : G_IO_ERROR_INVALID_DATA,
2633 : : _("UNIX timestamp %lld is outside of the range supported by Windows"),
2634 : : ut);
2635 : : return FALSE;
2636 : : }
2637 : :
2638 : : ft->dwLowDateTime = (DWORD) (result);
2639 : : ft->dwHighDateTime = (DWORD) (result >> 32);
2640 : :
2641 : : return TRUE;
2642 : : }
2643 : :
2644 : : static gboolean
2645 : : set_mtime_atime (const char *filename,
2646 : : const GFileAttributeValue *mtime_value,
2647 : : const GFileAttributeValue *mtime_usec_value,
2648 : : const GFileAttributeValue *mtime_nsec_value,
2649 : : const GFileAttributeValue *atime_value,
2650 : : const GFileAttributeValue *atime_usec_value,
2651 : : const GFileAttributeValue *atime_nsec_value,
2652 : : GError **error)
2653 : : {
2654 : : BOOL res;
2655 : : guint64 val = 0;
2656 : : guint32 val_usec = 0;
2657 : : guint32 val_nsec = 0;
2658 : : gunichar2 *filename_utf16;
2659 : : SECURITY_ATTRIBUTES sec = { sizeof (SECURITY_ATTRIBUTES), NULL, FALSE };
2660 : : HANDLE file_handle;
2661 : : FILETIME mtime;
2662 : : FILETIME atime;
2663 : : FILETIME *p_mtime = NULL;
2664 : : FILETIME *p_atime = NULL;
2665 : : DWORD gle;
2666 : : GStatBuf statbuf;
2667 : : gboolean got_stat = FALSE;
2668 : :
2669 : : /* ATIME */
2670 : : if (atime_value)
2671 : : {
2672 : : if (!get_uint64 (atime_value, &val, error))
2673 : : return FALSE;
2674 : : val_usec = 0;
2675 : : val_nsec = 0;
2676 : : }
2677 : : else
2678 : : {
2679 : : if (lazy_stat (filename, &statbuf, &got_stat) == 0)
2680 : : {
2681 : : val = statbuf.st_atime;
2682 : : #if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
2683 : : val_nsec = statbuf.st_atimensec;
2684 : : #elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
2685 : : val_nsec = statbuf.st_atim.tv_nsec;
2686 : : #endif
2687 : : }
2688 : : }
2689 : :
2690 : : if (atime_usec_value &&
2691 : : !get_uint32 (atime_usec_value, &val_usec, error))
2692 : : return FALSE;
2693 : :
2694 : : /* Convert to nanoseconds. Clamp the usec value if it’s going to overflow,
2695 : : * as %G_MAXINT32 will trigger a ‘too big’ error in
2696 : : * _g_win32_unix_time_to_filetime() anyway. */
2697 : : val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000);
2698 : :
2699 : : if (atime_nsec_value &&
2700 : : !get_uint32 (atime_nsec_value, &val_nsec, error))
2701 : : return FALSE;
2702 : : if (val_nsec > 0)
2703 : : {
2704 : : if (!_g_win32_unix_time_to_filetime (val, val_nsec, &atime, error))
2705 : : return FALSE;
2706 : : }
2707 : : else
2708 : : {
2709 : : if (!_g_win32_unix_time_to_filetime (val, val_usec, &atime, error))
2710 : : return FALSE;
2711 : : }
2712 : :
2713 : : p_atime = &atime;
2714 : :
2715 : : /* MTIME */
2716 : : if (mtime_value)
2717 : : {
2718 : : if (!get_uint64 (mtime_value, &val, error))
2719 : : return FALSE;
2720 : : val_usec = 0;
2721 : : val_nsec = 0;
2722 : : }
2723 : : else
2724 : : {
2725 : : if (lazy_stat (filename, &statbuf, &got_stat) == 0)
2726 : : {
2727 : : val = statbuf.st_mtime;
2728 : : #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
2729 : : val_nsec = statbuf.st_mtimensec;
2730 : : #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
2731 : : val_nsec = statbuf.st_mtim.tv_nsec;
2732 : : #endif
2733 : : }
2734 : : }
2735 : :
2736 : : if (mtime_usec_value &&
2737 : : !get_uint32 (mtime_usec_value, &val_usec, error))
2738 : : return FALSE;
2739 : :
2740 : : /* Convert to nanoseconds. Clamp the usec value if it’s going to overflow,
2741 : : * as %G_MAXINT32 will trigger a ‘too big’ error in
2742 : : * _g_win32_unix_time_to_filetime() anyway. */
2743 : : val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000);
2744 : :
2745 : : if (mtime_nsec_value &&
2746 : : !get_uint32 (mtime_nsec_value, &val_nsec, error))
2747 : : return FALSE;
2748 : : if (val_nsec > 0)
2749 : : {
2750 : : if (!_g_win32_unix_time_to_filetime (val, val_nsec, &mtime, error))
2751 : : return FALSE;
2752 : : }
2753 : : else
2754 : : {
2755 : : if (!_g_win32_unix_time_to_filetime (val, val_usec, &mtime, error))
2756 : : return FALSE;
2757 : : }
2758 : : p_mtime = &mtime;
2759 : :
2760 : : filename_utf16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, error);
2761 : :
2762 : : if (filename_utf16 == NULL)
2763 : : {
2764 : : g_prefix_error (error,
2765 : : _("File name “%s” cannot be converted to UTF-16"),
2766 : : filename);
2767 : : return FALSE;
2768 : : }
2769 : :
2770 : : file_handle = CreateFileW (filename_utf16,
2771 : : FILE_WRITE_ATTRIBUTES,
2772 : : FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
2773 : : &sec,
2774 : : OPEN_EXISTING,
2775 : : FILE_FLAG_BACKUP_SEMANTICS,
2776 : : NULL);
2777 : : gle = GetLastError ();
2778 : : g_clear_pointer (&filename_utf16, g_free);
2779 : :
2780 : : if (file_handle == INVALID_HANDLE_VALUE)
2781 : : {
2782 : : g_set_error (error, G_IO_ERROR,
2783 : : g_io_error_from_errno (gle),
2784 : : _("File “%s” cannot be opened: Windows Error %lu"),
2785 : : filename, gle);
2786 : :
2787 : : return FALSE;
2788 : : }
2789 : :
2790 : : res = SetFileTime (file_handle, NULL, p_atime, p_mtime);
2791 : : gle = GetLastError ();
2792 : : CloseHandle (file_handle);
2793 : :
2794 : : if (!res)
2795 : : g_set_error (error, G_IO_ERROR,
2796 : : g_io_error_from_errno (gle),
2797 : : _("Error setting modification or access time for file “%s”: %lu"),
2798 : : filename, gle);
2799 : :
2800 : : return res;
2801 : : }
2802 : : #elif defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT)
2803 : : static gboolean
2804 : 36 : set_mtime_atime (char *filename,
2805 : : const GFileAttributeValue *mtime_value,
2806 : : const GFileAttributeValue *mtime_usec_value,
2807 : : const GFileAttributeValue *mtime_nsec_value,
2808 : : const GFileAttributeValue *atime_value,
2809 : : const GFileAttributeValue *atime_usec_value,
2810 : : const GFileAttributeValue *atime_nsec_value,
2811 : : GError **error)
2812 : : {
2813 : : int res;
2814 : 36 : guint64 val = 0;
2815 : : GStatBuf statbuf;
2816 : 36 : gboolean got_stat = FALSE;
2817 : : #ifdef HAVE_UTIMENSAT
2818 : 36 : struct timespec times_n[2] = { {0, 0}, {0, 0} };
2819 : : /* ATIME */
2820 [ + + ]: 36 : if (atime_value)
2821 : : {
2822 [ - + ]: 6 : if (!get_uint64 (atime_value, &val, error))
2823 : 0 : return FALSE;
2824 : 6 : times_n[0].tv_sec = val;
2825 : : }
2826 : : else
2827 : : {
2828 [ + - ]: 30 : if (lazy_stat (filename, &statbuf, &got_stat) == 0)
2829 : : {
2830 : 30 : times_n[0].tv_sec = statbuf.st_atime;
2831 : : #if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
2832 : : times_n[0].tv_nsec = statbuf.st_atimensec;
2833 : : #elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
2834 : 30 : times_n[0].tv_nsec = statbuf.st_atim.tv_nsec;
2835 : : #endif
2836 : : }
2837 : : }
2838 : :
2839 [ + + ]: 36 : if (atime_usec_value)
2840 : : {
2841 : 6 : guint32 val_usec = 0;
2842 : :
2843 [ - + ]: 6 : if (!get_uint32 (atime_usec_value, &val_usec, error))
2844 : 0 : return FALSE;
2845 : :
2846 : 6 : times_n[0].tv_nsec = val_usec * 1000;
2847 : : }
2848 : :
2849 [ + + ]: 36 : if (atime_nsec_value)
2850 : : {
2851 : 7 : guint32 val_nsec = 0;
2852 : :
2853 [ - + ]: 7 : if (!get_uint32 (atime_nsec_value, &val_nsec, error))
2854 : 0 : return FALSE;
2855 : 7 : times_n[0].tv_nsec = val_nsec;
2856 : : }
2857 : :
2858 : : /* MTIME */
2859 [ + + ]: 36 : if (mtime_value)
2860 : : {
2861 [ - + ]: 32 : if (!get_uint64 (mtime_value, &val, error))
2862 : 0 : return FALSE;
2863 : 32 : times_n[1].tv_sec = val;
2864 : : }
2865 : : else
2866 : : {
2867 [ + - ]: 4 : if (lazy_stat (filename, &statbuf, &got_stat) == 0)
2868 : : {
2869 : 4 : times_n[1].tv_sec = statbuf.st_mtime;
2870 : : #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
2871 : : times_n[1].tv_nsec = statbuf.st_mtimensec;
2872 : : #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
2873 : 4 : times_n[1].tv_nsec = statbuf.st_mtim.tv_nsec;
2874 : : #endif
2875 : : }
2876 : : }
2877 : :
2878 [ + + ]: 36 : if (mtime_usec_value)
2879 : : {
2880 : 32 : guint32 val_usec = 0;
2881 : :
2882 [ - + ]: 32 : if (!get_uint32 (mtime_usec_value, &val_usec, error))
2883 : 0 : return FALSE;
2884 : :
2885 : 32 : times_n[1].tv_nsec = val_usec * 1000;
2886 : : }
2887 : :
2888 [ + + ]: 36 : if (mtime_nsec_value)
2889 : : {
2890 : 32 : guint32 val_nsec = 0;
2891 : :
2892 [ - + ]: 32 : if (!get_uint32 (mtime_nsec_value, &val_nsec, error))
2893 : 0 : return FALSE;
2894 : 32 : times_n[1].tv_nsec = val_nsec;
2895 : : }
2896 : :
2897 : 36 : res = utimensat (AT_FDCWD, filename, times_n, 0);
2898 : :
2899 : : #else /* HAVE_UTIMES */
2900 : :
2901 : : struct timeval times[2] = { {0, 0}, {0, 0} };
2902 : :
2903 : : /* ATIME */
2904 : : if (atime_value)
2905 : : {
2906 : : if (!get_uint64 (atime_value, &val, error))
2907 : : return FALSE;
2908 : :
2909 : : times[0].tv_sec = val;
2910 : : }
2911 : : else
2912 : : {
2913 : : if (lazy_stat (filename, &statbuf, &got_stat) == 0)
2914 : : {
2915 : : times[0].tv_sec = statbuf.st_atime;
2916 : : #if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
2917 : : times[0].tv_usec = statbuf.st_atimensec / 1000;
2918 : : #elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
2919 : : times[0].tv_usec = statbuf.st_atim.tv_nsec / 1000;
2920 : : #endif
2921 : : }
2922 : : }
2923 : :
2924 : : if (atime_usec_value)
2925 : : {
2926 : : guint32 val_usec = 0;
2927 : :
2928 : : if (!get_uint32 (atime_usec_value, &val_usec, error))
2929 : : return FALSE;
2930 : :
2931 : : times[0].tv_usec = val_usec;
2932 : : }
2933 : :
2934 : : /* MTIME */
2935 : : if (mtime_value)
2936 : : {
2937 : : if (!get_uint64 (mtime_value, &val, error))
2938 : : return FALSE;
2939 : :
2940 : : times[1].tv_sec = val;
2941 : : }
2942 : : else
2943 : : {
2944 : : if (lazy_stat (filename, &statbuf, &got_stat) == 0)
2945 : : {
2946 : : times[1].tv_sec = statbuf.st_mtime;
2947 : : #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
2948 : : times[1].tv_usec = statbuf.st_mtimensec / 1000;
2949 : : #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
2950 : : times[1].tv_usec = statbuf.st_mtim.tv_nsec / 1000;
2951 : : #endif
2952 : : }
2953 : : }
2954 : :
2955 : : if (mtime_usec_value)
2956 : : {
2957 : : guint32 val_usec = 0;
2958 : :
2959 : : if (!get_uint32 (mtime_usec_value, &val_usec, error))
2960 : : return FALSE;
2961 : :
2962 : : times[1].tv_usec = val_usec;
2963 : : }
2964 : :
2965 : : res = utimes (filename, times);
2966 : : #endif
2967 : :
2968 [ - + ]: 36 : if (res == -1)
2969 : : {
2970 : 0 : int errsv = errno;
2971 : :
2972 : 0 : g_set_error (error, G_IO_ERROR,
2973 : 0 : g_io_error_from_errno (errsv),
2974 : : _("Error setting modification or access time: %s"),
2975 : : g_strerror (errsv));
2976 : 0 : return FALSE;
2977 : : }
2978 : 36 : return TRUE;
2979 : : }
2980 : : #endif
2981 : :
2982 : :
2983 : : #ifdef HAVE_SELINUX
2984 : : static gboolean
2985 : 0 : set_selinux_context (char *filename,
2986 : : const GFileAttributeValue *value,
2987 : : GError **error)
2988 : : {
2989 : : const char *val;
2990 : :
2991 [ # # ]: 0 : if (!get_string (value, &val, error))
2992 : 0 : return FALSE;
2993 : :
2994 [ # # ]: 0 : if (val == NULL)
2995 : : {
2996 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
2997 : : _("SELinux context must be non-NULL"));
2998 : 0 : return FALSE;
2999 : : }
3000 : :
3001 [ # # ]: 0 : if (!is_selinux_enabled ())
3002 : : {
3003 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
3004 : : _("SELinux is not enabled on this system"));
3005 : 0 : return FALSE;
3006 : : }
3007 : :
3008 [ # # ]: 0 : if (setfilecon_raw (filename, val) < 0)
3009 : : {
3010 : 0 : int errsv = errno;
3011 : :
3012 : 0 : g_set_error (error, G_IO_ERROR,
3013 : 0 : g_io_error_from_errno (errsv),
3014 : : _("Error setting SELinux context: %s"),
3015 : : g_strerror (errsv));
3016 : 0 : return FALSE;
3017 : : }
3018 : :
3019 : 0 : return TRUE;
3020 : : }
3021 : : #endif
3022 : :
3023 : :
3024 : : gboolean
3025 : 191 : _g_local_file_info_set_attribute (char *filename,
3026 : : const char *attribute,
3027 : : GFileAttributeType type,
3028 : : gpointer value_p,
3029 : : GFileQueryInfoFlags flags,
3030 : : GCancellable *cancellable,
3031 : : GError **error)
3032 : : {
3033 : 191 : GFileAttributeValue value = { 0 };
3034 : : GVfsClass *class;
3035 : : GVfs *vfs;
3036 : :
3037 : 191 : _g_file_attribute_value_set_from_pointer (&value, type, value_p, FALSE);
3038 : :
3039 [ + + ]: 191 : if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)
3040 : 143 : return set_unix_mode (filename, flags, &value, error);
3041 : :
3042 : : #ifdef G_OS_UNIX
3043 [ - + ]: 48 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0)
3044 : 0 : return set_unix_uid_gid (filename, &value, NULL, flags, error);
3045 [ - + ]: 48 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_GID) == 0)
3046 : 0 : return set_unix_uid_gid (filename, NULL, &value, flags, error);
3047 : : #endif
3048 : :
3049 : : #ifdef HAVE_SYMLINK
3050 [ - + ]: 48 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET) == 0)
3051 : 0 : return set_symlink (filename, &value, error);
3052 : : #endif
3053 : :
3054 : : #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
3055 [ - + ]: 48 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0)
3056 : 0 : return set_mtime_atime (filename, &value, NULL, NULL, NULL, NULL, NULL, error);
3057 [ - + ]: 48 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC) == 0)
3058 : 0 : return set_mtime_atime (filename, NULL, &value, NULL, NULL, NULL, NULL, error);
3059 [ + + ]: 48 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC) == 0)
3060 : 1 : return set_mtime_atime (filename, NULL, NULL, &value, NULL, NULL, NULL, error);
3061 [ - + ]: 47 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0)
3062 : 0 : return set_mtime_atime (filename, NULL, NULL, NULL, &value, NULL, NULL, error);
3063 [ - + ]: 47 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC) == 0)
3064 : 0 : return set_mtime_atime (filename, NULL, NULL, NULL, NULL, &value, NULL, error);
3065 [ + + ]: 47 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC) == 0)
3066 : 1 : return set_mtime_atime (filename, NULL, NULL, NULL, NULL, NULL, &value, error);
3067 : : #endif
3068 : :
3069 : : #ifdef HAVE_XATTR
3070 [ + - - + : 46 : else if (g_str_has_prefix (attribute, "xattr::"))
+ - + + ]
3071 : 5 : return set_xattr (filename, attribute, &value, error);
3072 [ + - - + : 41 : else if (g_str_has_prefix (attribute, "xattr-sys::"))
+ - + + ]
3073 : 6 : return set_xattr (filename, attribute, &value, error);
3074 : : #endif
3075 : :
3076 : : #ifdef HAVE_SELINUX
3077 [ - + ]: 35 : else if (strcmp (attribute, G_FILE_ATTRIBUTE_SELINUX_CONTEXT) == 0)
3078 : 0 : return set_selinux_context (filename, &value, error);
3079 : : #endif
3080 : :
3081 : 35 : vfs = g_vfs_get_default ();
3082 : 35 : class = G_VFS_GET_CLASS (vfs);
3083 [ - + ]: 35 : if (class->local_file_set_attributes)
3084 : : {
3085 : : GFileInfo *info;
3086 : :
3087 : 0 : info = g_file_info_new ();
3088 : 0 : g_file_info_set_attribute (info,
3089 : : attribute,
3090 : : type,
3091 : : value_p);
3092 [ # # ]: 0 : if (!class->local_file_set_attributes (vfs, filename,
3093 : : info,
3094 : : flags, cancellable,
3095 : : error))
3096 : : {
3097 : 0 : g_object_unref (info);
3098 : 0 : return FALSE;
3099 : : }
3100 : :
3101 [ # # ]: 0 : if (g_file_info_get_attribute_status (info, attribute) == G_FILE_ATTRIBUTE_STATUS_SET)
3102 : : {
3103 : 0 : g_object_unref (info);
3104 : 0 : return TRUE;
3105 : : }
3106 : :
3107 : 0 : g_object_unref (info);
3108 : : }
3109 : :
3110 : 35 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
3111 : : _("Setting attribute %s not supported"), attribute);
3112 : 35 : return FALSE;
3113 : : }
3114 : :
3115 : : gboolean
3116 : 36 : _g_local_file_info_set_attributes (char *filename,
3117 : : GFileInfo *info,
3118 : : GFileQueryInfoFlags flags,
3119 : : GCancellable *cancellable,
3120 : : GError **error)
3121 : : {
3122 : : GFileAttributeValue *value;
3123 : : #ifdef G_OS_UNIX
3124 : : GFileAttributeValue *uid, *gid;
3125 : : #endif
3126 : : #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
3127 : : GFileAttributeValue *mtime, *mtime_usec, *mtime_nsec, *atime, *atime_usec, *atime_nsec;
3128 : : #endif
3129 : : #if defined (G_OS_UNIX) || defined (G_OS_WIN32)
3130 : : GFileAttributeStatus status;
3131 : : #endif
3132 : : gboolean res;
3133 : : GVfsClass *class;
3134 : : GVfs *vfs;
3135 : :
3136 : : /* Handles setting multiple specified data in a single set, and takes care
3137 : : of ordering restrictions when setting attributes */
3138 : :
3139 : 36 : res = TRUE;
3140 : :
3141 : : /* Set symlink first, since this recreates the file */
3142 : : #ifdef HAVE_SYMLINK
3143 : 36 : value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
3144 [ - + ]: 36 : if (value)
3145 : : {
3146 [ # # ]: 0 : if (!set_symlink (filename, value, error))
3147 : : {
3148 : 0 : value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
3149 : 0 : res = FALSE;
3150 : : /* Don't set error multiple times */
3151 : 0 : error = NULL;
3152 : : }
3153 : : else
3154 : 0 : value->status = G_FILE_ATTRIBUTE_STATUS_SET;
3155 : :
3156 : : }
3157 : : #endif
3158 : :
3159 : : #ifdef G_OS_UNIX
3160 : : /* Group uid and gid setting into one call
3161 : : * Change ownership before permissions, since ownership changes can
3162 : : change permissions (e.g. setuid)
3163 : : */
3164 : 36 : uid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_UID);
3165 : 36 : gid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_GID);
3166 : :
3167 [ + + - + ]: 36 : if (uid || gid)
3168 : : {
3169 [ - + ]: 6 : if (!set_unix_uid_gid (filename, uid, gid, flags, error))
3170 : : {
3171 : 0 : status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
3172 : 0 : res = FALSE;
3173 : : /* Don't set error multiple times */
3174 : 0 : error = NULL;
3175 : : }
3176 : : else
3177 : 6 : status = G_FILE_ATTRIBUTE_STATUS_SET;
3178 [ + - ]: 6 : if (uid)
3179 : 6 : uid->status = status;
3180 [ + - ]: 6 : if (gid)
3181 : 6 : gid->status = status;
3182 : : }
3183 : : #endif
3184 : :
3185 : 36 : value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_MODE);
3186 [ + + ]: 36 : if (value)
3187 : : {
3188 [ - + ]: 28 : if (!set_unix_mode (filename, flags, value, error))
3189 : : {
3190 : 0 : value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
3191 : 0 : res = FALSE;
3192 : : /* Don't set error multiple times */
3193 : 0 : error = NULL;
3194 : : }
3195 : : else
3196 : 28 : value->status = G_FILE_ATTRIBUTE_STATUS_SET;
3197 : :
3198 : : }
3199 : :
3200 : : #if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
3201 : : /* Group all time settings into one call
3202 : : * Change times as the last thing to avoid it changing due to metadata changes
3203 : : */
3204 : :
3205 : 36 : mtime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
3206 : 36 : mtime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
3207 : 36 : mtime_nsec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC);
3208 : 36 : atime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
3209 : 36 : atime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
3210 : 36 : atime_nsec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC);
3211 : :
3212 [ + + + - : 36 : if (mtime || mtime_usec || mtime_nsec || atime || atime_usec || atime_nsec)
+ - + + +
- - + ]
3213 : : {
3214 [ - + ]: 34 : if (!set_mtime_atime (filename, mtime, mtime_usec, mtime_nsec, atime, atime_usec, atime_nsec, error))
3215 : : {
3216 : 0 : status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
3217 : 0 : res = FALSE;
3218 : : /* Don't set error multiple times */
3219 : 0 : error = NULL;
3220 : : }
3221 : : else
3222 : 34 : status = G_FILE_ATTRIBUTE_STATUS_SET;
3223 : :
3224 [ + + ]: 34 : if (mtime)
3225 : 32 : mtime->status = status;
3226 [ + + ]: 34 : if (mtime_usec)
3227 : 32 : mtime_usec->status = status;
3228 [ + + ]: 34 : if (mtime_nsec)
3229 : 31 : mtime_nsec->status = status;
3230 [ + + ]: 34 : if (atime)
3231 : 6 : atime->status = status;
3232 [ + + ]: 34 : if (atime_usec)
3233 : 6 : atime_usec->status = status;
3234 [ + + ]: 34 : if (atime_nsec)
3235 : 6 : atime_nsec->status = status;
3236 : : }
3237 : : #endif
3238 : :
3239 : : /* xattrs are handled by default callback */
3240 : :
3241 : :
3242 : : /* SELinux context */
3243 : : #ifdef HAVE_SELINUX
3244 [ - + ]: 36 : if (is_selinux_enabled ()) {
3245 : 0 : value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT);
3246 [ # # ]: 0 : if (value)
3247 : : {
3248 [ # # ]: 0 : if (!set_selinux_context (filename, value, error))
3249 : : {
3250 : 0 : value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
3251 : 0 : res = FALSE;
3252 : : /* Don't set error multiple times */
3253 : 0 : error = NULL;
3254 : : }
3255 : : else
3256 : 0 : value->status = G_FILE_ATTRIBUTE_STATUS_SET;
3257 : : }
3258 : : }
3259 : : #endif
3260 : :
3261 : 36 : vfs = g_vfs_get_default ();
3262 : 36 : class = G_VFS_GET_CLASS (vfs);
3263 [ - + ]: 36 : if (class->local_file_set_attributes)
3264 : : {
3265 [ # # ]: 0 : if (!class->local_file_set_attributes (vfs, filename,
3266 : : info,
3267 : : flags, cancellable,
3268 : : error))
3269 : : {
3270 : 0 : res = FALSE;
3271 : : /* Don't set error multiple times */
3272 : 0 : error = NULL;
3273 : : }
3274 : : }
3275 : :
3276 : 36 : return res;
3277 : : }
|