LCOV - code coverage report
Current view: top level - glib/gio - glocalfileinfo.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 835 1115 74.9 %
Date: 2024-04-16 05:15:53 Functions: 46 54 85.2 %
Branches: 483 812 59.5 %

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

Generated by: LCOV version 1.14