LCOV - code coverage report
Current view: top level - gio - glocalfileinfo.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 74.9 % 1115 835
Test Date: 2024-11-26 05:23:01 Functions: 85.2 % 54 46
Branches: - 0 0

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

Generated by: LCOV version 2.0-1