X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fglocalfileinfo.c;h=7c46837cee5689294bbc76cadb109b3b1e965b06;hb=a3d86afa81ff34ce797a3928fd619ead219a37af;hp=f48f59ffd6f0b5b74cec31b18ec6c76321d6c46b;hpb=d013d46b986cd5b04944e2d6348bb8d24abaf63b;p=platform%2Fupstream%2Fglib.git diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index f48f59f..7c46837 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -1,3 +1,5 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + /* GIO - GLib Input, Output and Streaming Library * * Copyright (C) 2006-2007 Red Hat, Inc. @@ -13,26 +15,25 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: Alexander Larsson */ -#include +#include "config.h" + +#include +#ifdef HAVE_SYS_TIME_H #include +#endif #include #include #include -#include #include #include -#ifdef HAVE_GRP_H +#ifdef G_OS_UNIX #include -#endif -#ifdef HAVE_PWD_H #include #endif #ifdef HAVE_SELINUX @@ -52,17 +53,47 @@ #endif /* HAVE_XATTR */ #include -#include +#include +#include +#include -#include "glibintl.h" +#ifdef G_OS_UNIX +#include +#include "glib-unix.h" +#include "glib-private.h" +#endif + +#include "thumbnail-verify.h" + +#ifdef G_OS_WIN32 +#include +#include +#ifndef W_OK +#define W_OK 2 +#endif +#ifndef R_OK +#define R_OK 4 +#endif +#ifndef X_OK +#define X_OK 0 /* not really */ +#endif +#ifndef S_ISREG +#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +#endif +#ifndef S_IXUSR +#define S_IXUSR _S_IEXEC +#endif +#endif #include "glocalfileinfo.h" #include "gioerror.h" #include "gthemedicon.h" -#include "gcontenttype.h" #include "gcontenttypeprivate.h" +#include "glibintl.h" -#include "gioalias.h" struct ThumbMD5Context { guint32 buf[4]; @@ -70,6 +101,8 @@ struct ThumbMD5Context { unsigned char in[64]; }; +#ifndef G_OS_WIN32 + typedef struct { char *user_name; char *real_name; @@ -81,25 +114,27 @@ static GHashTable *uid_cache = NULL; G_LOCK_DEFINE_STATIC (gid_cache); static GHashTable *gid_cache = NULL; +#endif /* !G_OS_WIN32 */ + char * -_g_local_file_info_create_etag (struct stat *statbuf) +_g_local_file_info_create_etag (GLocalFileStat *statbuf) { - GTimeVal tv; - - tv.tv_sec = statbuf->st_mtime; + glong sec, usec; + + sec = statbuf->st_mtime; #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) - tv.tv_usec = statbuf->st_mtimensec / 1000; + usec = statbuf->st_mtimensec / 1000; #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) - tv.tv_usec = statbuf->st_mtim.tv_nsec / 1000; + usec = statbuf->st_mtim.tv_nsec / 1000; #else - tv.tv_usec = 0; + usec = 0; #endif - return g_strdup_printf ("%lu:%lu", tv.tv_sec, tv.tv_usec); + return g_strdup_printf ("%lu:%lu", sec, usec); } static char * -_g_local_file_info_create_file_id (struct stat *statbuf) +_g_local_file_info_create_file_id (GLocalFileStat *statbuf) { return g_strdup_printf ("l%" G_GUINT64_FORMAT ":%" G_GUINT64_FORMAT, (guint64) statbuf->st_dev, @@ -107,13 +142,15 @@ _g_local_file_info_create_file_id (struct stat *statbuf) } static char * -_g_local_file_info_create_fs_id (struct stat *statbuf) +_g_local_file_info_create_fs_id (GLocalFileStat *statbuf) { return g_strdup_printf ("l%" G_GUINT64_FORMAT, (guint64) statbuf->st_dev); } +#ifdef S_ISLNK + static gchar * read_link (const gchar *full_name) { @@ -147,6 +184,9 @@ read_link (const gchar *full_name) #endif } +#endif /* S_ISLNK */ + +#ifdef HAVE_SELINUX /* Get the SELinux security context */ static void get_selinux_context (const char *path, @@ -154,10 +194,9 @@ get_selinux_context (const char *path, GFileAttributeMatcher *attribute_matcher, gboolean follow_symlinks) { -#ifdef HAVE_SELINUX char *context; - if (!g_file_attribute_matcher_matches (attribute_matcher, "selinux:context")) + if (!_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT)) return; if (is_selinux_enabled ()) @@ -175,12 +214,12 @@ get_selinux_context (const char *path, if (context) { - g_file_info_set_attribute_string (info, "selinux:context", context); - freecon(context); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT, context); + freecon (context); } } -#endif } +#endif #ifdef HAVE_XATTR @@ -283,7 +322,7 @@ hex_escape_string (const char *str, *p++ = hex_digits[c & 0xf]; } } - *p++ = 0; + *p = 0; *free_return = TRUE; return escaped_str; @@ -417,7 +456,7 @@ get_xattrs (const char *path, if (user) all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr"); else - all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr_sys"); + all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr-sys"); if (all) { @@ -456,18 +495,20 @@ get_xattrs (const char *path, if (user) { escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr); - gio_attr = g_strconcat ("xattr:", escaped_attr, NULL); + gio_attr = g_strconcat ("xattr::", escaped_attr, NULL); } else { escaped_attr = hex_escape_string (attr, &free_escaped_attr); - gio_attr = g_strconcat ("xattr_sys:", escaped_attr, NULL); + gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL); } if (free_escaped_attr) g_free (escaped_attr); get_one_xattr (path, info, gio_attr, attr, follow_symlinks); + + g_free (gio_attr); } len = strlen (attr) + 1; @@ -487,7 +528,7 @@ get_xattrs (const char *path, attr2 = strchr (attr, ':'); if (attr2) { - attr2++; /* Skip ':' */ + attr2 += 2; /* Skip '::' */ unescaped_attribute = hex_unescape_string (attr2, NULL, &free_unescaped_attribute); if (user) a = g_strconcat ("user.", unescaped_attribute, NULL); @@ -518,7 +559,7 @@ get_one_xattr_from_fd (int fd, char *value_p; ssize_t len; - len = g_fgetxattr (fd, xattr, value, sizeof (value)-1); + len = g_fgetxattr (fd, xattr, value, sizeof (value) - 1); value_p = NULL; if (len >= 0) @@ -530,7 +571,7 @@ get_one_xattr_from_fd (int fd, if (len < 0) return; - value_p = g_malloc (len+1); + value_p = g_malloc (len + 1); len = g_fgetxattr (fd, xattr, value_p, len); @@ -570,7 +611,7 @@ get_xattrs_from_fd (int fd, if (user) all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr"); else - all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr_sys"); + all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr-sys"); if (all) { @@ -609,18 +650,19 @@ get_xattrs_from_fd (int fd, if (user) { escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr); - gio_attr = g_strconcat ("xattr:", escaped_attr, NULL); + gio_attr = g_strconcat ("xattr::", escaped_attr, NULL); } else { escaped_attr = hex_escape_string (attr, &free_escaped_attr); - gio_attr = g_strconcat ("xattr_sys:", escaped_attr, NULL); + gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL); } if (free_escaped_attr) g_free (escaped_attr); get_one_xattr_from_fd (fd, info, gio_attr, attr); + g_free (gio_attr); } len = strlen (attr) + 1; @@ -675,34 +717,34 @@ set_xattr (char *filename, if (attr_value == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Attribute value must be non-NULL")); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Attribute value must be non-NULL")); return FALSE; } if (attr_value->type != G_FILE_ATTRIBUTE_TYPE_STRING) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid attribute type (string expected)")); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid attribute type (string expected)")); return FALSE; } if (!name_is_valid (escaped_attribute)) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid extended attribute name")); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid extended attribute name")); return FALSE; } - if (g_str_has_prefix (escaped_attribute, "xattr:")) + if (g_str_has_prefix (escaped_attribute, "xattr::")) { - escaped_attribute += 6; + escaped_attribute += strlen ("xattr::"); is_user = TRUE; } else { - g_assert (g_str_has_prefix (escaped_attribute, "xattr_sys:")); - escaped_attribute += 10; + g_warn_if_fail (g_str_has_prefix (escaped_attribute, "xattr-sys::")); + escaped_attribute += strlen ("xattr-sys::"); is_user = FALSE; } @@ -731,7 +773,7 @@ set_xattr (char *filename, g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error setting extended attribute '%s': %s"), - escaped_attribute, g_strerror (errno)); + escaped_attribute, g_strerror (errsv)); return FALSE; } @@ -746,18 +788,26 @@ _g_local_file_info_get_parent_info (const char *dir, GFileAttributeMatcher *attribute_matcher, GLocalParentFileInfo *parent_info) { - struct stat statbuf; + GStatBuf statbuf; int res; - + + parent_info->extra_data = NULL; + parent_info->free_extra_data = NULL; parent_info->writable = FALSE; parent_info->is_sticky = FALSE; + parent_info->has_trash_dir = FALSE; parent_info->device = 0; - if (g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME) || - g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE) || - g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH) || - g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME) || + _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE) || + _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH) || + _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT)) { + /* FIXME: Windows: The underlying _waccess() call in the C + * library is mostly pointless as it only looks at the READONLY + * FAT-style attribute of the file, it doesn't check the ACL at + * all. + */ parent_info->writable = (g_access (dir, W_OK) == 0); res = g_stat (dir, &statbuf); @@ -769,34 +819,51 @@ _g_local_file_info_get_parent_info (const char *dir, */ if (res == 0) { +#ifdef S_ISVTX parent_info->is_sticky = (statbuf.st_mode & S_ISVTX) != 0; +#else + parent_info->is_sticky = FALSE; +#endif parent_info->owner = statbuf.st_uid; parent_info->device = statbuf.st_dev; + /* No need to find trash dir if it's not writable anyway */ + if (parent_info->writable && + _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH)) + parent_info->has_trash_dir = _g_local_file_has_trash_dir (dir, statbuf.st_dev); } } } +void +_g_local_file_info_free_parent_info (GLocalParentFileInfo *parent_info) +{ + if (parent_info->extra_data && + parent_info->free_extra_data) + parent_info->free_extra_data (parent_info->extra_data); +} + static void get_access_rights (GFileAttributeMatcher *attribute_matcher, GFileInfo *info, const gchar *path, - struct stat *statbuf, + GLocalFileStat *statbuf, GLocalParentFileInfo *parent_info) { - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, - g_access (path, R_OK) == 0); + /* FIXME: Windows: The underlyin _waccess() is mostly pointless */ + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ)) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ, + g_access (path, R_OK) == 0); - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, - g_access (path, W_OK) == 0); + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE)) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE, + g_access (path, W_OK) == 0); - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, - g_access (path, X_OK) == 0); + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE)) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE, + g_access (path, X_OK) == 0); if (parent_info) @@ -808,35 +875,36 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher, { if (parent_info->is_sticky) { +#ifndef G_OS_WIN32 uid_t uid = geteuid (); if (uid == statbuf->st_uid || uid == parent_info->owner || uid == 0) +#endif writable = TRUE; } else writable = TRUE; } - if (g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, - writable); + if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME)) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME, + writable); - if (g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, - writable); + if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE)) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, + writable); - /* TODO: This means we can move it, but we should also look for a trash dir */ - if (g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, - writable); + if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH)) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, + writable && parent_info->has_trash_dir); } } static void set_info_from_stat (GFileInfo *info, - struct stat *statbuf, + GLocalFileStat *statbuf, GFileAttributeMatcher *attribute_matcher) { GFileType file_type; @@ -847,6 +915,7 @@ set_info_from_stat (GFileInfo *info, file_type = G_FILE_TYPE_REGULAR; else if (S_ISDIR (statbuf->st_mode)) file_type = G_FILE_TYPE_DIRECTORY; +#ifndef G_OS_WIN32 else if (S_ISCHR (statbuf->st_mode) || S_ISBLK (statbuf->st_mode) || S_ISFIFO (statbuf->st_mode) @@ -855,6 +924,7 @@ set_info_from_stat (GFileInfo *info, #endif ) file_type = G_FILE_TYPE_SPECIAL; +#endif #ifdef S_ISLNK else if (S_ISLNK (statbuf->st_mode)) file_type = G_FILE_TYPE_SYMBOLIC_LINK; @@ -863,66 +933,74 @@ set_info_from_stat (GFileInfo *info, g_file_info_set_file_type (info, file_type); g_file_info_set_size (info, statbuf->st_size); - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE, statbuf->st_dev); - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE, statbuf->st_ino); - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, statbuf->st_mode); - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_NLINK, statbuf->st_nlink); - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, statbuf->st_uid); - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, statbuf->st_gid); - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_RDEV, statbuf->st_rdev); -#if defined (HAVE_STRUCT_STAT_BLKSIZE) - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE, statbuf->st_blksize); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_DEVICE, statbuf->st_dev); +#ifndef G_OS_WIN32 + /* Pointless setting these on Windows even if they exist in the struct */ + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_INODE, statbuf->st_ino); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_NLINK, statbuf->st_nlink); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_UID, statbuf->st_uid); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_GID, statbuf->st_gid); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_RDEV, statbuf->st_rdev); +#endif + /* FIXME: st_mode is mostly pointless on Windows, too. Set the attribute or not? */ + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_MODE, statbuf->st_mode); +#if defined (HAVE_STRUCT_STAT_ST_BLKSIZE) + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCK_SIZE, statbuf->st_blksize); #endif -#if defined (HAVE_STRUCT_STAT_BLOCKS) - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_BLOCKS, statbuf->st_blocks); +#if defined (HAVE_STRUCT_STAT_ST_BLOCKS) + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCKS, statbuf->st_blocks); + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_ALLOCATED_SIZE, + statbuf->st_blocks * G_GUINT64_CONSTANT (512)); #endif - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED, statbuf->st_mtime); + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, statbuf->st_mtime); #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, statbuf->st_mtimensec / 1000); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtimensec / 1000); #elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, statbuf->st_mtim.tv_nsec / 1000); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtim.tv_nsec / 1000); #endif - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS, statbuf->st_atime); + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, statbuf->st_atime); #if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC) - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, statbuf->st_atimensec / 1000); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atimensec / 1000); #elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000); #endif - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED, statbuf->st_ctime); + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED, statbuf->st_ctime); #if defined (HAVE_STRUCT_STAT_ST_CTIMENSEC) - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000); #elif defined (HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC) - g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, statbuf->st_ctim.tv_nsec / 1000); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, statbuf->st_ctim.tv_nsec / 1000); #endif - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_ETAG_VALUE)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_ETAG_VALUE)) { char *etag = _g_local_file_info_create_etag (statbuf); - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, etag); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ETAG_VALUE, etag); g_free (etag); } - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_ID_FILE)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_ID_FILE)) { char *id = _g_local_file_info_create_file_id (statbuf); - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE, id); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ID_FILE, id); g_free (id); } - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_ID_FS)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_ID_FILESYSTEM)) { char *id = _g_local_file_info_create_fs_id (statbuf); - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FS, id); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ID_FILESYSTEM, id); g_free (id); } } +#ifndef G_OS_WIN32 + static char * make_valid_utf8 (const char *name) { @@ -956,7 +1034,7 @@ make_valid_utf8 (const char *name) g_string_append (string, remainder); - g_assert (g_utf8_validate (string->str, -1, NULL)); + g_warn_if_fail (g_utf8_validate (string->str, -1, NULL)); return g_string_free (string, FALSE); } @@ -1019,6 +1097,7 @@ lookup_uid_data (uid_t uid) if (pwbufp->pw_name != NULL && pwbufp->pw_name[0] != 0) data->user_name = convert_pwd_string_to_utf8 (pwbufp->pw_name); +#ifndef __BIONIC__ gecos = pwbufp->pw_gecos; if (gecos) @@ -1028,6 +1107,7 @@ lookup_uid_data (uid_t uid) *comma = 0; data->real_name = convert_pwd_string_to_utf8 (gecos); } +#endif } /* Default fallbacks */ @@ -1036,11 +1116,11 @@ lookup_uid_data (uid_t uid) if (data->user_name != NULL) data->real_name = g_strdup (data->user_name); else - data->real_name = g_strdup_printf("user #%d", (int)uid); + data->real_name = g_strdup_printf ("user #%d", (int)uid); } if (data->user_name == NULL) - data->user_name = g_strdup_printf("%d", (int)uid); + data->user_name = g_strdup_printf ("%d", (int)uid); g_hash_table_replace (uid_cache, GINT_TO_POINTER (uid), data); @@ -1075,7 +1155,6 @@ get_realname_from_uid (uid_t uid) return res; } - /* called with lock held */ static char * lookup_gid_name (gid_t gid) @@ -1126,10 +1205,12 @@ get_groupname_from_gid (gid_t gid) return res; } +#endif /* !G_OS_WIN32 */ + static char * get_content_type (const char *basename, const char *path, - struct stat *statbuf, + GLocalFileStat *statbuf, gboolean is_symlink, gboolean symlink_broken, GFileQueryInfoFlags flags, @@ -1137,17 +1218,19 @@ get_content_type (const char *basename, { if (is_symlink && (symlink_broken || (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS))) - return g_strdup ("inode/symlink"); - else if (S_ISDIR(statbuf->st_mode)) + return g_strdup ("inode/symlink"); + else if (statbuf != NULL && S_ISDIR(statbuf->st_mode)) return g_strdup ("inode/directory"); - else if (S_ISCHR(statbuf->st_mode)) +#ifndef G_OS_WIN32 + else if (statbuf != NULL && S_ISCHR(statbuf->st_mode)) return g_strdup ("inode/chardevice"); - else if (S_ISBLK(statbuf->st_mode)) + else if (statbuf != NULL && S_ISBLK(statbuf->st_mode)) return g_strdup ("inode/blockdevice"); - else if (S_ISFIFO(statbuf->st_mode)) + else if (statbuf != NULL && S_ISFIFO(statbuf->st_mode)) return g_strdup ("inode/fifo"); +#endif #ifdef S_ISSOCK - else if (S_ISSOCK(statbuf->st_mode)) + else if (statbuf != NULL && S_ISSOCK(statbuf->st_mode)) return g_strdup ("inode/socket"); #endif else @@ -1167,15 +1250,20 @@ get_content_type (const char *basename, sniff_length = _g_unix_content_type_get_sniff_len (); if (sniff_length > 4096) sniff_length = 4096; - - fd = open (path, O_RDONLY); + +#ifdef O_NOATIME + fd = g_open (path, O_RDONLY | O_NOATIME, 0); + if (fd < 0 && errno == EPERM) +#endif + fd = g_open (path, O_RDONLY, 0); + if (fd != -1) { ssize_t res; res = read (fd, sniff_buffer, sniff_length); - close (fd); - if (res > 0) + (void) g_close (fd, NULL); + if (res >= 0) { g_free (content_type); content_type = g_content_type_guess (basename, sniff_buffer, res, NULL); @@ -1189,9 +1277,11 @@ get_content_type (const char *basename, } +/* @stat_buf is the pre-calculated result of stat(path), or %NULL if that failed. */ static void -get_thumbnail_attributes (const char *path, - GFileInfo *info) +get_thumbnail_attributes (const char *path, + GFileInfo *info, + const GLocalFileStat *stat_buf) { GChecksum *checksum; char *uri; @@ -1201,33 +1291,383 @@ get_thumbnail_attributes (const char *path, uri = g_filename_to_uri (path, NULL, NULL); checksum = g_checksum_new (G_CHECKSUM_MD5); - g_checksum_update (checksum, (const gchar *) uri, strlen (uri)); + g_checksum_update (checksum, (const guchar *) uri, strlen (uri)); basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL); g_checksum_free (checksum); - filename = g_build_filename (g_get_home_dir(), - ".thumbnails", "normal", basename, + filename = g_build_filename (g_get_user_cache_dir (), + "thumbnails", "large", basename, NULL); if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) - g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename); + { + _g_file_info_set_attribute_byte_string_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH, filename); + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID, + thumbnail_verify (filename, uri, stat_buf)); + } else { g_free (filename); - filename = g_build_filename (g_get_home_dir(), - ".thumbnails", "fail", - "gnome-thumbnail-factory", - basename, + filename = g_build_filename (g_get_user_cache_dir (), + "thumbnails", "normal", basename, NULL); if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE); + { + _g_file_info_set_attribute_byte_string_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH, filename); + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID, + thumbnail_verify (filename, uri, stat_buf)); + } + else + { + g_free (filename); + filename = g_build_filename (g_get_user_cache_dir (), + "thumbnails", "fail", + "gnome-thumbnail-factory", + basename, + NULL); + + if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + { + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED, TRUE); + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID, + thumbnail_verify (filename, uri, stat_buf)); + } + } } g_free (basename); g_free (filename); + g_free (uri); +} + +#ifdef G_OS_WIN32 +static void +win32_get_file_user_info (const gchar *filename, + gchar **group_name, + gchar **user_name, + gchar **real_name) +{ + PSECURITY_DESCRIPTOR psd = NULL; + DWORD sd_size = 0; /* first call calculates the size required */ + + wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); + if ((GetFileSecurityW (wfilename, + GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, + NULL, + sd_size, + &sd_size) || (ERROR_INSUFFICIENT_BUFFER == GetLastError())) && + (psd = g_try_malloc (sd_size)) != NULL && + GetFileSecurityW (wfilename, + GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, + psd, + sd_size, + &sd_size)) + { + PSID psid = 0; + BOOL defaulted; + SID_NAME_USE name_use = 0; /* don't care? */ + wchar_t *name = NULL; + wchar_t *domain = NULL; + DWORD name_len = 0; + DWORD domain_len = 0; + /* get the user name */ + do { + if (!user_name) + break; + if (!GetSecurityDescriptorOwner (psd, &psid, &defaulted)) + break; + if (!LookupAccountSidW (NULL, /* local machine */ + psid, + name, &name_len, + domain, &domain_len, /* no domain info yet */ + &name_use) && (ERROR_INSUFFICIENT_BUFFER != GetLastError())) + break; + name = g_try_malloc (name_len * sizeof (wchar_t)); + domain = g_try_malloc (domain_len * sizeof (wchar_t)); + if (name && domain && + LookupAccountSidW (NULL, /* local machine */ + psid, + name, &name_len, + domain, &domain_len, /* no domain info yet */ + &name_use)) + { + *user_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL); + } + g_free (name); + g_free (domain); + } while (FALSE); + + /* get the group name */ + do { + if (!group_name) + break; + if (!GetSecurityDescriptorGroup (psd, &psid, &defaulted)) + break; + if (!LookupAccountSidW (NULL, /* local machine */ + psid, + name, &name_len, + domain, &domain_len, /* no domain info yet */ + &name_use) && (ERROR_INSUFFICIENT_BUFFER != GetLastError())) + break; + name = g_try_malloc (name_len * sizeof (wchar_t)); + domain = g_try_malloc (domain_len * sizeof (wchar_t)); + if (name && domain && + LookupAccountSidW (NULL, /* local machine */ + psid, + name, &name_len, + domain, &domain_len, /* no domain info yet */ + &name_use)) + { + *group_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL); + } + g_free (name); + g_free (domain); + } while (FALSE); + + /* TODO: get real name */ + + g_free (psd); + } + g_free (wfilename); +} +#endif /* G_OS_WIN32 */ + +#ifndef G_OS_WIN32 +/* support for '.hidden' files */ +G_LOCK_DEFINE_STATIC (hidden_cache); +static GHashTable *hidden_cache; + +static gboolean +remove_from_hidden_cache (gpointer user_data) +{ + G_LOCK (hidden_cache); + g_hash_table_remove (hidden_cache, user_data); + G_UNLOCK (hidden_cache); + + return FALSE; +} + +static GHashTable * +read_hidden_file (const gchar *dirname) +{ + gchar *contents = NULL; + gchar *filename; + + filename = g_build_path ("/", dirname, ".hidden", NULL); + (void) g_file_get_contents (filename, &contents, NULL, NULL); + g_free (filename); + + if (contents != NULL) + { + GHashTable *table; + gchar **lines; + gint i; + + table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + lines = g_strsplit (contents, "\n", 0); + g_free (contents); + + for (i = 0; lines[i]; i++) + /* hash table takes the individual strings... */ + g_hash_table_add (table, lines[i]); + + /* ... so we only free the container. */ + g_free (lines); + + return table; + } + else + return NULL; } +static void +maybe_unref_hash_table (gpointer data) +{ + if (data != NULL) + g_hash_table_unref (data); +} + +static gboolean +file_is_hidden (const gchar *path, + const gchar *basename) +{ + gboolean result; + gchar *dirname; + gpointer table; + + dirname = g_path_get_dirname (path); + + G_LOCK (hidden_cache); + + if G_UNLIKELY (hidden_cache == NULL) + hidden_cache = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, maybe_unref_hash_table); + + if (!g_hash_table_lookup_extended (hidden_cache, dirname, + NULL, &table)) + { + gchar *mydirname; + GSource *remove_from_cache_source; + + g_hash_table_insert (hidden_cache, + mydirname = g_strdup (dirname), + table = read_hidden_file (dirname)); + + remove_from_cache_source = g_timeout_source_new_seconds (5); + g_source_set_priority (remove_from_cache_source, G_PRIORITY_DEFAULT); + g_source_set_callback (remove_from_cache_source, + remove_from_hidden_cache, + mydirname, + NULL); + g_source_attach (remove_from_cache_source, + GLIB_PRIVATE_CALL (g_get_worker_context) ()); + g_source_unref (remove_from_cache_source); + } + + result = table != NULL && g_hash_table_contains (table, basename); + + G_UNLOCK (hidden_cache); + + g_free (dirname); + + return result; +} +#endif /* !G_OS_WIN32 */ + +void +_g_local_file_info_get_nostat (GFileInfo *info, + const char *basename, + const char *path, + GFileAttributeMatcher *attribute_matcher) +{ + g_file_info_set_name (info, basename); + + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_DISPLAY_NAME)) + { + char *display_name = g_filename_display_basename (path); + + /* look for U+FFFD REPLACEMENT CHARACTER */ + if (strstr (display_name, "\357\277\275") != NULL) + { + char *p = display_name; + display_name = g_strconcat (display_name, _(" (invalid encoding)"), NULL); + g_free (p); + } + g_file_info_set_display_name (info, display_name); + g_free (display_name); + } + + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_EDIT_NAME)) + { + char *edit_name = g_filename_display_basename (path); + g_file_info_set_edit_name (info, edit_name); + g_free (edit_name); + } + + + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_COPY_NAME)) + { + char *copy_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL); + if (copy_name) + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_COPY_NAME, copy_name); + g_free (copy_name); + } +} + +static const char * +get_icon_name (const char *path, + const char *content_type, + gboolean use_symbolic, + gboolean *with_fallbacks_out) +{ + const char *name = NULL; + gboolean with_fallbacks = TRUE; + + if (strcmp (path, g_get_home_dir ()) == 0) + { + name = use_symbolic ? "user-home-symbolic" : "user-home"; + with_fallbacks = FALSE; + } + else if (strcmp (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0) + { + name = use_symbolic ? "user-desktop-symbolic" : "user-desktop"; + with_fallbacks = FALSE; + } + else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)) == 0) + { + name = use_symbolic ? "folder-documents-symbolic" : "folder-documents"; + } + else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD)) == 0) + { + name = use_symbolic ? "folder-download-symbolic" : "folder-download"; + } + else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_MUSIC)) == 0) + { + name = use_symbolic ? "folder-music-symbolic" : "folder-music"; + } + else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)) == 0) + { + name = use_symbolic ? "folder-pictures-symbolic" : "folder-pictures"; + } + else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE)) == 0) + { + name = use_symbolic ? "folder-publicshare-symbolic" : "folder-publicshare"; + } + else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES)) == 0) + { + name = use_symbolic ? "folder-templates-symbolic" : "folder-templates"; + } + else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS)) == 0) + { + name = use_symbolic ? "folder-videos-symbolic" : "folder-videos"; + } + else if (g_strcmp0 (content_type, "inode/directory") == 0) + { + name = use_symbolic ? "folder-symbolic" : "folder"; + } + else + { + name = NULL; + } + + if (with_fallbacks_out != NULL) + *with_fallbacks_out = with_fallbacks; + + return name; +} + +static GIcon * +get_icon (const char *path, + const char *content_type, + gboolean use_symbolic) +{ + GIcon *icon = NULL; + const char *icon_name; + gboolean with_fallbacks; + + icon_name = get_icon_name (path, content_type, use_symbolic, &with_fallbacks); + if (icon_name != NULL) + { + if (with_fallbacks) + icon = g_themed_icon_new_with_default_fallbacks (icon_name); + else + icon = g_themed_icon_new (icon_name); + } + else + { + if (use_symbolic) + icon = g_content_type_get_symbolic_icon (content_type); + else + icon = g_content_type_get_icon (content_type); + } + + return icon; +} GFileInfo * _g_local_file_info_get (const char *basename, @@ -1238,40 +1678,94 @@ _g_local_file_info_get (const char *basename, GError **error) { GFileInfo *info; - struct stat statbuf; + GLocalFileStat statbuf; +#ifdef S_ISLNK struct stat statbuf2; +#endif int res; + gboolean stat_ok; gboolean is_symlink, symlink_broken; +#ifdef G_OS_WIN32 + DWORD dos_attributes; +#endif + char *symlink_target; + GVfs *vfs; + GVfsClass *class; + guint64 device; info = g_file_info_new (); /* Make sure we don't set any unwanted attributes */ g_file_info_set_attribute_mask (info, attribute_matcher); - g_file_info_set_name (info, basename); + _g_local_file_info_get_nostat (info, basename, path, attribute_matcher); - /* Avoid stat in trivial case */ if (attribute_matcher == NULL) - return info; + { + g_file_info_unset_attribute_mask (info); + return info; + } +#ifndef G_OS_WIN32 res = g_lstat (path, &statbuf); +#else + { + wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, error); + int len; + + if (wpath == NULL) + { + g_object_unref (info); + return NULL; + } + + len = wcslen (wpath); + while (len > 0 && G_IS_DIR_SEPARATOR (wpath[len-1])) + len--; + if (len > 0 && + (!g_path_is_absolute (path) || len > g_path_skip_root (path) - path)) + wpath[len] = '\0'; + + res = _wstati64 (wpath, &statbuf); + dos_attributes = GetFileAttributesW (wpath); + + g_free (wpath); + } +#endif + if (res == -1) { - g_object_unref (info); - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error stating file '%s': %s"), - path, g_strerror (errno)); - return NULL; + int errsv = errno; + + /* Don't bail out if we get Permission denied (SELinux?) */ + if (errsv != EACCES) + { + char *display_name = g_filename_display_name (path); + g_object_unref (info); + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errsv), + _("Error when getting information for file '%s': %s"), + display_name, g_strerror (errsv)); + g_free (display_name); + return NULL; + } } - + + /* Even if stat() fails, try to get as much as other attributes possible */ + stat_ok = res != -1; + + if (stat_ok) + device = statbuf.st_dev; + else + device = 0; + #ifdef S_ISLNK - is_symlink = S_ISLNK (statbuf.st_mode); + is_symlink = stat_ok && S_ISLNK (statbuf.st_mode); #else is_symlink = FALSE; #endif symlink_broken = FALSE; - +#ifdef S_ISLNK if (is_symlink) { g_file_info_set_is_symlink (info, TRUE); @@ -1281,206 +1775,228 @@ _g_local_file_info_get (const char *basename, { res = stat (path, &statbuf2); - /* Report broken links as symlinks */ + /* Report broken links as symlinks */ if (res != -1) - statbuf = statbuf2; + { + statbuf = statbuf2; + stat_ok = TRUE; + } else symlink_broken = TRUE; } } +#endif - set_info_from_stat (info, &statbuf, attribute_matcher); - - if (basename != NULL && basename[0] == '.') - g_file_info_set_is_hidden (info, TRUE); + if (stat_ok) + set_info_from_stat (info, &statbuf, attribute_matcher); - if (basename != NULL && basename[strlen (basename) -1] == '~') - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STD_IS_BACKUP, TRUE); +#ifdef G_OS_UNIX + if (stat_ok && _g_local_file_is_lost_found_dir (path, statbuf.st_dev)) + g_file_info_set_is_hidden (info, TRUE); +#endif - if (is_symlink && - g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET)) +#ifndef G_OS_WIN32 + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_IS_HIDDEN)) { - char *link = read_link (path); - g_file_info_set_symlink_target (info, link); - g_free (link); + if (basename != NULL && + (basename[0] == '.' || + file_is_hidden (path, basename))) + g_file_info_set_is_hidden (info, TRUE); } - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_DISPLAY_NAME)) - { - char *display_name = g_filename_display_basename (path); - - if (strstr (display_name, "\357\277\275") != NULL) - { - char *p = display_name; - display_name = g_strconcat (display_name, _(" (invalid encoding)"), NULL); - g_free (p); - } - g_file_info_set_display_name (info, display_name); - g_free (display_name); - } - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_EDIT_NAME)) - { - char *edit_name = g_filename_display_basename (path); - g_file_info_set_edit_name (info, edit_name); - g_free (edit_name); - } + if (basename != NULL && basename[strlen (basename) -1] == '~' && + (stat_ok && S_ISREG (statbuf.st_mode))) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP, TRUE); +#else + if (dos_attributes & FILE_ATTRIBUTE_HIDDEN) + g_file_info_set_is_hidden (info, TRUE); - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_COPY_NAME)) + if (dos_attributes & FILE_ATTRIBUTE_ARCHIVE) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_ARCHIVE, TRUE); + + if (dos_attributes & FILE_ATTRIBUTE_SYSTEM) + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_SYSTEM, TRUE); +#endif + + symlink_target = NULL; +#ifdef S_ISLNK + if (is_symlink) { - char *copy_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL); - if (copy_name) - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STD_COPY_NAME, copy_name); - g_free (copy_name); + symlink_target = read_link (path); + if (symlink_target && + _g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_SYMLINK_TARGET)) + g_file_info_set_symlink_target (info, symlink_target); } - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_CONTENT_TYPE) || - g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_ICON)) +#endif + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) || + _g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_ICON) || + _g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON)) { - char *content_type = get_content_type (basename, path, &statbuf, is_symlink, symlink_broken, flags, FALSE); + char *content_type = get_content_type (basename, path, stat_ok ? &statbuf : NULL, is_symlink, symlink_broken, flags, FALSE); if (content_type) { g_file_info_set_content_type (info, content_type); - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_ICON)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_ICON) + || _g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON)) { - char *mimetype_icon, *generic_mimetype_icon, *type_icon, *p; - char *icon_names[3]; GIcon *icon; - int i; - mimetype_icon = g_strdup (content_type); - - while ((p = strchr(mimetype_icon, '/')) != NULL) - *p = '-'; - - p = strchr (content_type, '/'); - if (p == NULL) - p = content_type + strlen (content_type); - - generic_mimetype_icon = g_malloc (p - content_type + strlen ("-x-generic") + 1); - memcpy (generic_mimetype_icon, content_type, p - content_type); - memcpy (generic_mimetype_icon + (p - content_type), "-x-generic", strlen ("-x-generic")); - generic_mimetype_icon[(p - content_type) + strlen ("-x-generic")] = 0; - - /* TODO: Special case desktop dir? That could be expensive with xdg dirs... */ - if (strcmp (path, g_get_home_dir ()) == 0) - type_icon = "user-home"; - else if (S_ISDIR (statbuf.st_mode)) - type_icon = "folder"; - else if (statbuf.st_mode & S_IXUSR) - type_icon = "application-x-executable"; - else - type_icon = "text-x-generic"; - - i = 0; - icon_names[i++] = mimetype_icon; - icon_names[i++] = generic_mimetype_icon; - if (strcmp (generic_mimetype_icon, type_icon) != 0 && - strcmp (mimetype_icon, type_icon) != 0) - icon_names[i++] = type_icon; - - icon = g_themed_icon_new_from_names (icon_names, i); - g_file_info_set_icon (info, icon); - - g_object_unref (icon); - g_free (mimetype_icon); - g_free (generic_mimetype_icon); + /* non symbolic icon */ + icon = get_icon (path, content_type, FALSE); + if (icon != NULL) + { + g_file_info_set_icon (info, icon); + g_object_unref (icon); + } + + /* symbolic icon */ + icon = get_icon (path, content_type, TRUE); + if (icon != NULL) + { + g_file_info_set_symbolic_icon (info, icon); + g_object_unref (icon); + } + } g_free (content_type); } } - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_FAST_CONTENT_TYPE)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE)) { - char *content_type = get_content_type (basename, path, &statbuf, is_symlink, symlink_broken, flags, TRUE); + char *content_type = get_content_type (basename, path, stat_ok ? &statbuf : NULL, is_symlink, symlink_broken, flags, TRUE); if (content_type) { - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STD_FAST_CONTENT_TYPE, content_type); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type); g_free (content_type); } } - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_OWNER_USER)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_OWNER_USER)) { - char *name; + char *name = NULL; - name = get_username_from_uid (statbuf.st_uid); +#ifdef G_OS_WIN32 + win32_get_file_user_info (path, NULL, &name, NULL); +#else + if (stat_ok) + name = get_username_from_uid (statbuf.st_uid); +#endif if (name) - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER, name); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_USER, name); g_free (name); } - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_OWNER_USER_REAL)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_OWNER_USER_REAL)) { - char *name; - - name = get_realname_from_uid (statbuf.st_uid); + char *name = NULL; +#ifdef G_OS_WIN32 + win32_get_file_user_info (path, NULL, NULL, &name); +#else + if (stat_ok) + name = get_realname_from_uid (statbuf.st_uid); +#endif if (name) - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL, name); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_USER_REAL, name); g_free (name); } - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_OWNER_GROUP)) + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_OWNER_GROUP)) { - char *name; - - name = get_groupname_from_gid (statbuf.st_gid); + char *name = NULL; +#ifdef G_OS_WIN32 + win32_get_file_user_info (path, &name, NULL, NULL); +#else + if (stat_ok) + name = get_groupname_from_gid (statbuf.st_gid); +#endif if (name) - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP, name); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_GROUP, name); g_free (name); } - if (parent_info && parent_info->device != 0 && - g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT) && + if (stat_ok && parent_info && parent_info->device != 0 && + _g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT) && statbuf.st_dev != parent_info->device) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT, TRUE); + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT, TRUE); - get_access_rights (attribute_matcher, info, path, &statbuf, parent_info); + if (stat_ok) + get_access_rights (attribute_matcher, info, path, &statbuf, parent_info); +#ifdef HAVE_SELINUX get_selinux_context (path, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0); +#endif get_xattrs (path, TRUE, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0); get_xattrs (path, FALSE, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0); - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_THUMBNAIL_PATH)) - get_thumbnail_attributes (path, info); - + if (_g_file_attribute_matcher_matches_id (attribute_matcher, + G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH)) + { + if (stat_ok) + get_thumbnail_attributes (path, info, &statbuf); + else + get_thumbnail_attributes (path, info, NULL); + } + + vfs = g_vfs_get_default (); + class = G_VFS_GET_CLASS (vfs); + if (class->local_file_add_info) + { + class->local_file_add_info (vfs, + path, + device, + attribute_matcher, + info, + NULL, + &parent_info->extra_data, + &parent_info->free_extra_data); + } + g_file_info_unset_attribute_mask (info); + g_free (symlink_target); + return info; } GFileInfo * -_g_local_file_info_get_from_fd (int fd, - char *attributes, - GError **error) +_g_local_file_info_get_from_fd (int fd, + const char *attributes, + GError **error) { - struct stat stat_buf; + GLocalFileStat stat_buf; GFileAttributeMatcher *matcher; GFileInfo *info; - if (fstat (fd, &stat_buf) == -1) +#ifdef G_OS_WIN32 +#define FSTAT _fstati64 +#else +#define FSTAT fstat +#endif + + if (FSTAT (fd, &stat_buf) == -1) { + int errsv = errno; + g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error stating file descriptor: %s"), - g_strerror (errno)); + g_io_error_from_errno (errsv), + _("Error when getting information for file descriptor: %s"), + g_strerror (errsv)); return NULL; } @@ -1494,14 +2010,14 @@ _g_local_file_info_get_from_fd (int fd, set_info_from_stat (info, &stat_buf, matcher); #ifdef HAVE_SELINUX - if (g_file_attribute_matcher_matches (matcher, "selinux:context") && + if (_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT) && is_selinux_enabled ()) { char *context; if (fgetfilecon_raw (fd, &context) >= 0) { - g_file_info_set_attribute_string (info, "selinux:context", context); - freecon(context); + _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT, context); + freecon (context); } } #endif @@ -1523,8 +2039,8 @@ get_uint32 (const GFileAttributeValue *value, { if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT32) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid attribute type (uint32 expected)")); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid attribute type (uint32 expected)")); return FALSE; } @@ -1533,6 +2049,7 @@ get_uint32 (const GFileAttributeValue *value, return TRUE; } +#ifdef HAVE_UTIMES static gboolean get_uint64 (const GFileAttributeValue *value, guint64 *val_out, @@ -1540,8 +2057,8 @@ get_uint64 (const GFileAttributeValue *value, { if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT64) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid attribute type (uint64 expected)")); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid attribute type (uint64 expected)")); return FALSE; } @@ -1549,6 +2066,7 @@ get_uint64 (const GFileAttributeValue *value, return TRUE; } +#endif #if defined(HAVE_SYMLINK) static gboolean @@ -1558,8 +2076,27 @@ get_byte_string (const GFileAttributeValue *value, { if (value->type != G_FILE_ATTRIBUTE_TYPE_BYTE_STRING) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid attribute type (byte string expected)")); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid attribute type (byte string expected)")); + return FALSE; + } + + *val_out = value->u.string; + + return TRUE; +} +#endif + +#ifdef HAVE_SELINUX +static gboolean +get_string (const GFileAttributeValue *value, + const char **val_out, + GError **error) +{ + if (value->type != G_FILE_ATTRIBUTE_TYPE_STRING) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid attribute type (byte string expected)")); return FALSE; } @@ -1571,26 +2108,53 @@ get_byte_string (const GFileAttributeValue *value, static gboolean set_unix_mode (char *filename, + GFileQueryInfoFlags flags, const GFileAttributeValue *value, GError **error) { - guint32 val; + guint32 val = 0; + int res = 0; if (!get_uint32 (value, &val, error)) return FALSE; - - if (g_chmod (filename, val) == -1) + +#ifdef HAVE_SYMLINK + if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) { +#ifdef HAVE_LCHMOD + res = lchmod (filename, val); +#else + struct stat statbuf; + /* Calling chmod on a symlink changes permissions on the symlink. + * We don't want to do this, so we need to check for a symlink */ + res = g_lstat (filename, &statbuf); + if (res == 0 && S_ISLNK (statbuf.st_mode)) + { + g_set_error_literal (error, G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + _("Cannot set permissions on symlinks")); + return FALSE; + } + else if (res == 0) + res = g_chmod (filename, val); +#endif + } else +#endif + res = g_chmod (filename, val); + + if (res == -1) { + int errsv = errno; + g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), + g_io_error_from_errno (errsv), _("Error setting permissions: %s"), - g_strerror (errno)); + g_strerror (errsv)); return FALSE; } return TRUE; } -#ifdef HAVE_CHOWN +#ifdef G_OS_UNIX static gboolean set_unix_uid_gid (char *filename, const GFileAttributeValue *uid_value, @@ -1599,7 +2163,7 @@ set_unix_uid_gid (char *filename, GError **error) { int res; - guint32 val; + guint32 val = 0; uid_t uid; gid_t gid; @@ -1621,17 +2185,21 @@ set_unix_uid_gid (char *filename, else gid = -1; +#ifdef HAVE_LCHOWN if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) res = lchown (filename, uid, gid); else +#endif res = chown (filename, uid, gid); if (res == -1) { + int errsv = errno; + g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), + g_io_error_from_errno (errsv), _("Error setting owner: %s"), - g_strerror (errno)); + g_strerror (errsv)); return FALSE; } return TRUE; @@ -1652,43 +2220,49 @@ set_symlink (char *filename, if (val == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("symlink must be non-NULL")); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("symlink must be non-NULL")); return FALSE; } if (g_lstat (filename, &statbuf)) { + int errsv = errno; + g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), + g_io_error_from_errno (errsv), _("Error setting symlink: %s"), - g_strerror (errno)); + g_strerror (errsv)); return FALSE; } if (!S_ISLNK (statbuf.st_mode)) { - g_set_error (error, G_IO_ERROR, - G_IO_ERROR_NOT_SYMBOLIC_LINK, - _("Error setting symlink: file is not a symlink")); + g_set_error_literal (error, G_IO_ERROR, + G_IO_ERROR_NOT_SYMBOLIC_LINK, + _("Error setting symlink: file is not a symlink")); return FALSE; } if (g_unlink (filename)) { + int errsv = errno; + g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), + g_io_error_from_errno (errsv), _("Error setting symlink: %s"), - g_strerror (errno)); + g_strerror (errsv)); return FALSE; } if (symlink (filename, val) != 0) { + int errsv = errno; + g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), + g_io_error_from_errno (errsv), _("Error setting symlink: %s"), - g_strerror (errno)); + g_strerror (errsv)); return FALSE; } @@ -1696,6 +2270,7 @@ set_symlink (char *filename, } #endif +#ifdef HAVE_UTIMES static int lazy_stat (char *filename, struct stat *statbuf, @@ -1715,7 +2290,6 @@ lazy_stat (char *filename, } -#ifdef HAVE_UTIMES static gboolean set_mtime_atime (char *filename, const GFileAttributeValue *mtime_value, @@ -1725,8 +2299,8 @@ set_mtime_atime (char *filename, GError **error) { int res; - guint64 val; - guint32 val_usec; + guint64 val = 0; + guint32 val_usec = 0; struct stat statbuf; gboolean got_stat = FALSE; struct timeval times[2] = { {0, 0}, {0, 0} }; @@ -1785,60 +2359,149 @@ set_mtime_atime (char *filename, times[1].tv_usec = val_usec; } - res = utimes(filename, times); + res = utimes (filename, times); if (res == -1) { + int errsv = errno; + g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error setting owner: %s"), - g_strerror (errno)); + g_io_error_from_errno (errsv), + _("Error setting modification or access time: %s"), + g_strerror (errsv)); return FALSE; } return TRUE; } #endif + +#ifdef HAVE_SELINUX +static gboolean +set_selinux_context (char *filename, + const GFileAttributeValue *value, + GError **error) +{ + const char *val; + + if (!get_string (value, &val, error)) + return FALSE; + + if (val == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("SELinux context must be non-NULL")); + return FALSE; + } + + if (is_selinux_enabled ()) { + security_context_t val_s; + + val_s = g_strdup (val); + + if (setfilecon_raw (filename, val_s) < 0) + { + int errsv = errno; + + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errsv), + _("Error setting SELinux context: %s"), + g_strerror (errsv)); + return FALSE; + } + g_free (val_s); + } else { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("SELinux is not enabled on this system")); + return FALSE; + } + + return TRUE; +} +#endif + + gboolean -_g_local_file_info_set_attribute (char *filename, - const char *attribute, - const GFileAttributeValue *value, - GFileQueryInfoFlags flags, - GCancellable *cancellable, - GError **error) +_g_local_file_info_set_attribute (char *filename, + const char *attribute, + GFileAttributeType type, + gpointer value_p, + GFileQueryInfoFlags flags, + GCancellable *cancellable, + GError **error) { + GFileAttributeValue value = { 0 }; + GVfsClass *class; + GVfs *vfs; + + _g_file_attribute_value_set_from_pointer (&value, type, value_p, FALSE); + if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0) - return set_unix_mode (filename, value, error); + return set_unix_mode (filename, flags, &value, error); -#ifdef HAVE_CHOWN +#ifdef G_OS_UNIX else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0) - return set_unix_uid_gid (filename, value, NULL, flags, error); + return set_unix_uid_gid (filename, &value, NULL, flags, error); else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_GID) == 0) - return set_unix_uid_gid (filename, NULL, value, flags, error); + return set_unix_uid_gid (filename, NULL, &value, flags, error); #endif #ifdef HAVE_SYMLINK - else if (strcmp (attribute, G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET) == 0) - return set_symlink (filename, value, error); + else if (strcmp (attribute, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET) == 0) + return set_symlink (filename, &value, error); #endif #ifdef HAVE_UTIMES else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0) - return set_mtime_atime (filename, value, NULL, NULL, NULL, error); + return set_mtime_atime (filename, &value, NULL, NULL, NULL, error); else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC) == 0) - return set_mtime_atime (filename, NULL, value, NULL, NULL, error); + return set_mtime_atime (filename, NULL, &value, NULL, NULL, error); else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0) - return set_mtime_atime (filename, NULL, NULL, value, NULL, error); + return set_mtime_atime (filename, NULL, NULL, &value, NULL, error); else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC) == 0) - return set_mtime_atime (filename, NULL, NULL, NULL, value, error); + return set_mtime_atime (filename, NULL, NULL, NULL, &value, error); #endif #ifdef HAVE_XATTR - else if (g_str_has_prefix (attribute, "xattr:")) - return set_xattr (filename, attribute, value, error); - else if (g_str_has_prefix (attribute, "xattr_sys:")) - return set_xattr (filename, attribute, value, error); + else if (g_str_has_prefix (attribute, "xattr::")) + return set_xattr (filename, attribute, &value, error); + else if (g_str_has_prefix (attribute, "xattr-sys::")) + return set_xattr (filename, attribute, &value, error); #endif - + +#ifdef HAVE_SELINUX + else if (strcmp (attribute, G_FILE_ATTRIBUTE_SELINUX_CONTEXT) == 0) + return set_selinux_context (filename, &value, error); +#endif + + vfs = g_vfs_get_default (); + class = G_VFS_GET_CLASS (vfs); + if (class->local_file_set_attributes) + { + GFileInfo *info; + + info = g_file_info_new (); + g_file_info_set_attribute (info, + attribute, + type, + value_p); + if (!class->local_file_set_attributes (vfs, filename, + info, + flags, cancellable, + error)) + { + g_object_unref (info); + return FALSE; + } + + if (g_file_info_get_attribute_status (info, attribute) == G_FILE_ATTRIBUTE_STATUS_SET) + { + g_object_unref (info); + return TRUE; + } + + g_object_unref (info); + } + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Setting attribute %s not supported"), attribute); return FALSE; @@ -1851,10 +2514,17 @@ _g_local_file_info_set_attributes (char *filename, GCancellable *cancellable, GError **error) { - GFileAttributeValue *value, *uid, *gid; + GFileAttributeValue *value; +#ifdef G_OS_UNIX + GFileAttributeValue *uid, *gid; +#ifdef HAVE_UTIMES GFileAttributeValue *mtime, *mtime_usec, *atime, *atime_usec; +#endif GFileAttributeStatus status; +#endif gboolean res; + GVfsClass *class; + GVfs *vfs; /* Handles setting multiple specified data in a single set, and takes care of ordering restrictions when setting attributes */ @@ -1863,7 +2533,7 @@ _g_local_file_info_set_attributes (char *filename, /* Set symlink first, since this recreates the file */ #ifdef HAVE_SYMLINK - value = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET); + value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET); if (value) { if (!set_symlink (filename, value, error)) @@ -1879,13 +2549,13 @@ _g_local_file_info_set_attributes (char *filename, } #endif -#ifdef HAVE_CHOWN +#ifdef G_OS_UNIX /* Group uid and gid setting into one call * Change ownership before permissions, since ownership changes can change permissions (e.g. setuid) */ - uid = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_UNIX_UID); - gid = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_UNIX_GID); + uid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_UID); + gid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_GID); if (uid || gid) { @@ -1905,10 +2575,10 @@ _g_local_file_info_set_attributes (char *filename, } #endif - value = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE); + value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_MODE); if (value) { - if (!set_unix_mode (filename, value, error)) + if (!set_unix_mode (filename, flags, value, error)) { value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING; res = FALSE; @@ -1925,10 +2595,10 @@ _g_local_file_info_set_attributes (char *filename, * Change times as the last thing to avoid it changing due to metadata changes */ - mtime = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); - mtime_usec = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC); - atime = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_ACCESS); - atime_usec = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC); + mtime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); + mtime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC); + atime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS); + atime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC); if (mtime || mtime_usec || atime || atime_usec) { @@ -1955,5 +2625,40 @@ _g_local_file_info_set_attributes (char *filename, /* xattrs are handled by default callback */ + + /* SELinux context */ +#ifdef HAVE_SELINUX + if (is_selinux_enabled ()) { + value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT); + if (value) + { + if (!set_selinux_context (filename, value, error)) + { + value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING; + res = FALSE; + /* Don't set error multiple times */ + error = NULL; + } + else + value->status = G_FILE_ATTRIBUTE_STATUS_SET; + } + } +#endif + + vfs = g_vfs_get_default (); + class = G_VFS_GET_CLASS (vfs); + if (class->local_file_set_attributes) + { + if (!class->local_file_set_attributes (vfs, filename, + info, + flags, cancellable, + error)) + { + res = FALSE; + /* Don't set error multiple times */ + error = NULL; + } + } + return res; }