diff options
Diffstat (limited to 'gio/glocalfileinfo.c')
-rw-r--r-- | gio/glocalfileinfo.c | 1730 |
1 files changed, 0 insertions, 1730 deletions
diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c deleted file mode 100644 index 5aec5198..00000000 --- a/gio/glocalfileinfo.c +++ /dev/null @@ -1,1730 +0,0 @@ -#include <config.h> - -#include <sys/time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> -#ifdef HAVE_SELINUX -#include <selinux/selinux.h> -#endif - -#include <sys/types.h> -#ifdef HAVE_XATTR - -#if defined HAVE_SYS_XATTR_H - #include <sys/xattr.h> -#elif defined HAVE_ATTR_XATTR_H - #include <attr/xattr.h> -#else - #error "Neither <sys/xattr.h> nor <attr/xattr.h> is present but extended attribute support is enabled." -#endif /* defined HAVE_SYS_XATTR_H || HAVE_ATTR_XATTR_H */ - -#endif /* HAVE_XATTR */ - -#include <glib/gstdio.h> -#include <glib/gi18n-lib.h> - -#include "glocalfileinfo.h" -#include "gioerror.h" -#include "gcontenttype.h" -#include "gcontenttypeprivate.h" - -typedef struct { - char *user_name; - char *real_name; -} UidData; - -G_LOCK_DEFINE_STATIC (uid_cache); -GHashTable *uid_cache = NULL; - -G_LOCK_DEFINE_STATIC (gid_cache); -GHashTable *gid_cache = NULL; - -char * -_g_local_file_info_create_etag (struct stat *statbuf) -{ - GTimeVal tv; - - tv.tv_sec = statbuf->st_mtime; -#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) - tv.tv_usec = statbuf->st_mtimensec / 1000; -#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) - tv.tv_usec = statbuf->st_mtim.tv_nsec / 1000; -#else - tv.tv_usec = 0; -#endif - - return g_strdup_printf ("%ld:%ld", tv.tv_sec, tv.tv_usec); -} - -static gchar * -read_link (const gchar *full_name) -{ -#ifdef HAVE_READLINK - gchar *buffer; - guint size; - - size = 256; - buffer = g_malloc (size); - - while (1) - { - int read_size; - - read_size = readlink (full_name, buffer, size); - if (read_size < 0) - { - g_free (buffer); - return NULL; - } - if (read_size < size) - { - buffer[read_size] = 0; - return buffer; - } - size *= 2; - buffer = g_realloc (buffer, size); - } -#else - return NULL; -#endif -} - -/* Get the SELinux security context */ -static void -get_selinux_context (const char *path, - GFileInfo *info, - GFileAttributeMatcher *attribute_matcher, - gboolean follow_symlinks) -{ -#ifdef HAVE_SELINUX - char *context; - - if (!g_file_attribute_matcher_matches (attribute_matcher, "selinux:context")) - return; - - if (is_selinux_enabled ()) - { - if (follow_symlinks) - { - if (lgetfilecon_raw (path, &context) < 0) - return; - } - else - { - if (getfilecon_raw (path, &context) < 0) - return; - } - - if (context) - { - g_file_info_set_attribute_string (info, "selinux:context", context); - freecon(context); - } - } -#endif -} - -#ifdef HAVE_XATTR - -static gboolean -valid_char (char c) -{ - return c >= 32 && c <= 126 && c != '\\'; -} - -static gboolean -name_is_valid (const char *str) -{ - while (*str) - { - if (!valid_char (*str++)) - return FALSE; - } - return TRUE; -} - -static char * -hex_escape_string (const char *str, gboolean *free_return) -{ - int num_invalid, i; - char *escaped_str, *p; - unsigned char c; - static char *hex_digits = "0123456789abcdef"; - int len; - - len = strlen (str); - - num_invalid = 0; - for (i = 0; i < len; i++) - { - if (!valid_char (str[i])) - num_invalid++; - } - - if (num_invalid == 0) - { - *free_return = FALSE; - return (char *)str; - } - - escaped_str = g_malloc (len + num_invalid*3 + 1); - - p = escaped_str; - for (i = 0; i < len; i++) - { - if (valid_char (str[i])) - *p++ = str[i]; - else - { - c = str[i]; - *p++ = '\\'; - *p++ = 'x'; - *p++ = hex_digits[(c >> 4) & 0xf]; - *p++ = hex_digits[c & 0xf]; - } - } - *p++ = 0; - - *free_return = TRUE; - return escaped_str; -} - -static char * -hex_unescape_string (const char *str, int *out_len, gboolean *free_return) -{ - int i; - char *unescaped_str, *p; - unsigned char c; - int len; - - len = strlen (str); - - if (strchr (str, '\\') == NULL) - { - if (out_len) - *out_len = len; - *free_return = FALSE; - return (char *)str; - } - - unescaped_str = g_malloc (len + 1); - - p = unescaped_str; - for (i = 0; i < len; i++) - { - if (str[i] == '\\' && - str[i+1] == 'x' && - len - i >= 4) - { - c = - (g_ascii_xdigit_value (str[i+2]) << 4) | - g_ascii_xdigit_value (str[i+3]); - *p++ = c; - i += 3; - } - else - *p++ = str[i]; - } - *p++ = 0; - - if (out_len) - *out_len = p - unescaped_str; - *free_return = TRUE; - return unescaped_str; -} - -static void -escape_xattr (GFileInfo *info, - const char *gio_attr, /* gio attribute name */ - const char *value, /* Is zero terminated */ - size_t len /* not including zero termination */) -{ - char *escaped_val; - gboolean free_escaped_val; - - escaped_val = hex_escape_string (value, &free_escaped_val); - - g_file_info_set_attribute_string (info, gio_attr, escaped_val); - - if (free_escaped_val) - g_free (escaped_val); -} - -static void -get_one_xattr (const char *path, - GFileInfo *info, - const char *gio_attr, - const char *xattr, - gboolean follow_symlinks) -{ - char value[64]; - char *value_p; - ssize_t len; - - if (follow_symlinks) - len = getxattr (path, xattr, value, sizeof (value)-1); - else - len = lgetxattr (path, xattr,value, sizeof (value)-1); - - value_p = NULL; - if (len >= 0) - value_p = value; - else if (len == -1 && errno == ERANGE) - { - if (follow_symlinks) - len = getxattr (path, xattr, NULL, 0); - else - len = lgetxattr (path, xattr, NULL, 0); - - if (len < 0) - return; - - value_p = g_malloc (len+1); - - if (follow_symlinks) - len = getxattr (path, xattr, value_p, len); - else - len = lgetxattr (path, xattr, value_p, len); - - if (len < 0) - { - g_free (value_p); - return; - } - } - else - return; - - /* Null terminate */ - value_p[len] = 0; - - escape_xattr (info, gio_attr, value_p, len); - - if (value_p != value) - g_free (value_p); -} - -#endif /* defined HAVE_XATTR */ - -static void -get_xattrs (const char *path, - gboolean user, - GFileInfo *info, - GFileAttributeMatcher *matcher, - gboolean follow_symlinks) -{ -#ifdef HAVE_XATTR - gboolean all; - gsize list_size; - ssize_t list_res_size; - size_t len; - char *list; - const char *attr, *attr2; - - if (user) - all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr"); - else - all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr_sys"); - - if (all) - { - if (follow_symlinks) - list_res_size = listxattr (path, NULL, 0); - else - list_res_size = llistxattr (path, NULL, 0); - - if (list_res_size == -1 || - list_res_size == 0) - return; - - list_size = list_res_size; - list = g_malloc (list_size); - - retry: - - if (follow_symlinks) - list_res_size = listxattr (path, list, list_size); - else - list_res_size = llistxattr (path, list, list_size); - - if (list_res_size == -1 && errno == ERANGE) - { - list_size = list_size * 2; - list = g_realloc (list, list_size); - goto retry; - } - - if (list_res_size == -1) - return; - - attr = list; - while (list_res_size > 0) - { - if ((user && g_str_has_prefix (attr, "user.")) || - (!user && !g_str_has_prefix (attr, "user."))) - { - char *escaped_attr, *gio_attr; - gboolean free_escaped_attr; - - if (user) - { - escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr); - 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); - } - - if (free_escaped_attr) - g_free (escaped_attr); - - get_one_xattr (path, info, gio_attr, attr, follow_symlinks); - } - - len = strlen (attr) + 1; - attr += len; - list_res_size -= len; - } - - g_free (list); - } - else - { - while ((attr = g_file_attribute_matcher_enumerate_next (matcher)) != NULL) - { - char *unescaped_attribute, *a; - gboolean free_unescaped_attribute; - - attr2 = strchr (attr, ':'); - if (attr2) - { - attr2++; /* Skip ':' */ - unescaped_attribute = hex_unescape_string (attr2, NULL, &free_unescaped_attribute); - if (user) - a = g_strconcat ("user.", unescaped_attribute, NULL); - else - a = unescaped_attribute; - - get_one_xattr (path, info, attr, a, follow_symlinks); - - if (user) - g_free (a); - - if (free_unescaped_attribute) - g_free (unescaped_attribute); - } - } - } -#endif /* defined HAVE_XATTR */ -} - -#ifdef HAVE_XATTR -static void -get_one_xattr_from_fd (int fd, - GFileInfo *info, - const char *gio_attr, - const char *xattr) -{ - char value[64]; - char *value_p; - ssize_t len; - - len = fgetxattr (fd, xattr, value, sizeof (value)-1); - - value_p = NULL; - if (len >= 0) - value_p = value; - else if (len == -1 && errno == ERANGE) - { - len = fgetxattr (fd, xattr, NULL, 0); - - if (len < 0) - return; - - value_p = g_malloc (len+1); - - len = fgetxattr (fd, xattr, value_p, len); - - if (len < 0) - { - g_free (value_p); - return; - } - } - else - return; - - /* Null terminate */ - value_p[len] = 0; - - escape_xattr (info, gio_attr, value_p, len); - - if (value_p != value) - g_free (value_p); -} -#endif /* defined HAVE_XATTR */ - -static void -get_xattrs_from_fd (int fd, - gboolean user, - GFileInfo *info, - GFileAttributeMatcher *matcher) -{ -#ifdef HAVE_XATTR - gboolean all; - gsize list_size; - ssize_t list_res_size; - size_t len; - char *list; - const char *attr, *attr2; - - if (user) - all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr"); - else - all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr_sys"); - - if (all) - { - list_res_size = flistxattr (fd, NULL, 0); - - if (list_res_size == -1 || - list_res_size == 0) - return; - - list_size = list_res_size; - list = g_malloc (list_size); - - retry: - - list_res_size = flistxattr (fd, list, list_size); - - if (list_res_size == -1 && errno == ERANGE) - { - list_size = list_size * 2; - list = g_realloc (list, list_size); - goto retry; - } - - if (list_res_size == -1) - return; - - attr = list; - while (list_res_size > 0) - { - if ((user && g_str_has_prefix (attr, "user.")) || - (!user && !g_str_has_prefix (attr, "user."))) - { - char *escaped_attr, *gio_attr; - gboolean free_escaped_attr; - - if (user) - { - escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr); - 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); - } - - if (free_escaped_attr) - g_free (escaped_attr); - - get_one_xattr_from_fd (fd, info, gio_attr, attr); - } - - len = strlen (attr) + 1; - attr += len; - list_res_size -= len; - } - - g_free (list); - } - else - { - while ((attr = g_file_attribute_matcher_enumerate_next (matcher)) != NULL) - { - char *unescaped_attribute, *a; - gboolean free_unescaped_attribute; - - attr2 = strchr (attr, ':'); - if (attr2) - { - attr2++; /* Skip ':' */ - unescaped_attribute = hex_unescape_string (attr2, NULL, &free_unescaped_attribute); - if (user) - a = g_strconcat ("user.", unescaped_attribute, NULL); - else - a = unescaped_attribute; - - get_one_xattr_from_fd (fd, info, attr, a); - - if (user) - g_free (a); - - if (free_unescaped_attribute) - g_free (unescaped_attribute); - } - } - } -#endif /* defined HAVE_XATTR */ -} - -#ifdef HAVE_XATTR -static gboolean -set_xattr (char *filename, - const char *escaped_attribute, - const GFileAttributeValue *attr_value, - GError **error) -{ - char *attribute, *value; - gboolean free_attribute, free_value; - int val_len, res, errsv; - gboolean is_user; - char *a; - - 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)")); - return FALSE; - } - - if (!name_is_valid (escaped_attribute)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid extended attribute name")); - return FALSE; - } - - if (g_str_has_prefix (escaped_attribute, "xattr:")) - { - escaped_attribute += 6; - is_user = TRUE; - } - else - { - g_assert (g_str_has_prefix (escaped_attribute, "xattr_sys:")); - escaped_attribute += 10; - is_user = FALSE; - } - - attribute = hex_unescape_string (escaped_attribute, NULL, &free_attribute); - value = hex_unescape_string (attr_value->u.string, &val_len, &free_value); - - - if (is_user) - a = g_strconcat ("user.", attribute, NULL); - else - a = attribute; - - res = setxattr (filename, a, value, val_len, 0); - errsv = errno; - - if (is_user) - g_free (a); - - if (free_attribute) - g_free (attribute); - - if (free_value) - g_free (value); - - if (res == -1) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errsv), - _("Error setting extended attribute '%s': %s"), - escaped_attribute, g_strerror (errno)); - return FALSE; - } - - return TRUE; -} - -#endif - - -void -_g_local_file_info_get_parent_info (const char *dir, - GFileAttributeMatcher *attribute_matcher, - GLocalParentFileInfo *parent_info) -{ - struct stat statbuf; - int res; - - parent_info->writable = FALSE; - parent_info->is_sticky = FALSE; - - 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)) - { - parent_info->writable = (g_access (dir, W_OK) == 0); - - if (parent_info->writable) - { - res = g_stat (dir, &statbuf); - - /* - * The sticky bit (S_ISVTX) on a directory means that a file in that directory can be - * renamed or deleted only by the owner of the file, by the owner of the directory, and - * by a privileged process. - */ - if (res == 0) - { - parent_info->is_sticky = (statbuf.st_mode & S_ISVTX) != 0; - parent_info->owner = statbuf.st_uid; - } - } - } -} - -static void -get_access_rights (GFileAttributeMatcher *attribute_matcher, - GFileInfo *info, - const gchar *path, - struct stat *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); - - 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 (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 (parent_info) - { - gboolean writable; - - writable = FALSE; - if (parent_info->writable) - { - if (parent_info->is_sticky) - { - uid_t uid = geteuid (); - - if (uid == statbuf->st_uid || - uid == parent_info->owner || - uid == 0) - 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 (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)) - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, - writable); - } -} - -static void -set_info_from_stat (GFileInfo *info, struct stat *statbuf, - GFileAttributeMatcher *attribute_matcher) -{ - GFileType file_type; - - file_type = G_FILE_TYPE_UNKNOWN; - - if (S_ISREG (statbuf->st_mode)) - file_type = G_FILE_TYPE_REGULAR; - else if (S_ISDIR (statbuf->st_mode)) - file_type = G_FILE_TYPE_DIRECTORY; - else if (S_ISCHR (statbuf->st_mode) || - S_ISBLK (statbuf->st_mode) || - S_ISFIFO (statbuf->st_mode) -#ifdef S_ISSOCK - || S_ISSOCK (statbuf->st_mode) -#endif - ) - file_type = G_FILE_TYPE_SPECIAL; -#ifdef S_ISLNK - else if (S_ISLNK (statbuf->st_mode)) - file_type = G_FILE_TYPE_SYMBOLIC_LINK; -#endif - - 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_uid); - 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); -#endif -#if defined (HAVE_STRUCT_STAT_BLOCKS) - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_BLOCKS, statbuf->st_blocks); -#endif - - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_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); -#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); -#endif - - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_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); -#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); -#endif - - g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_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); -#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); -#endif - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_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_free (etag); - } - -} - -static char * -make_valid_utf8 (const char *name) -{ - GString *string; - const gchar *remainder, *invalid; - gint remaining_bytes, valid_bytes; - - string = NULL; - remainder = name; - remaining_bytes = strlen (name); - - while (remaining_bytes != 0) - { - if (g_utf8_validate (remainder, remaining_bytes, &invalid)) - break; - valid_bytes = invalid - remainder; - - if (string == NULL) - string = g_string_sized_new (remaining_bytes); - - g_string_append_len (string, remainder, valid_bytes); - /* append U+FFFD REPLACEMENT CHARACTER */ - g_string_append (string, "\357\277\275"); - - remaining_bytes -= valid_bytes + 1; - remainder = invalid + 1; - } - - if (string == NULL) - return g_strdup (name); - - g_string_append (string, remainder); - - g_assert (g_utf8_validate (string->str, -1, NULL)); - - return g_string_free (string, FALSE); -} - -static char * -convert_pwd_string_to_utf8 (char *pwd_str) -{ - char *utf8_string; - - if (!g_utf8_validate (pwd_str, -1, NULL)) - { - utf8_string = g_locale_to_utf8 (pwd_str, -1, NULL, NULL, NULL); - if (utf8_string == NULL) - utf8_string = make_valid_utf8 (pwd_str); - } - else - utf8_string = g_strdup (pwd_str); - - return utf8_string; -} - -static void -uid_data_free (UidData *data) -{ - g_free (data->user_name); - g_free (data->real_name); - g_free (data); -} - -/* called with lock held */ -static UidData * -lookup_uid_data (uid_t uid) -{ - UidData *data; - char buffer[4096]; - struct passwd pwbuf; - struct passwd *pwbufp; - char *gecos, *comma; - - if (uid_cache == NULL) - uid_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)uid_data_free); - - data = g_hash_table_lookup (uid_cache, GINT_TO_POINTER (uid)); - - if (data) - return data; - - data = g_new0 (UidData, 1); - - getpwuid_r (uid, &pwbuf, buffer, sizeof(buffer), &pwbufp); - - if (pwbufp != NULL) - { - if (pwbufp->pw_name != NULL && pwbufp->pw_name[0] != 0) - data->user_name = convert_pwd_string_to_utf8 (pwbufp->pw_name); - - gecos = pwbufp->pw_gecos; - - if (gecos) - { - comma = strchr (gecos, ','); - if (comma) - *comma = 0; - data->real_name = convert_pwd_string_to_utf8 (gecos); - } - } - - /* Default fallbacks */ - if (data->real_name == NULL) - { - if (data->user_name != NULL) - data->real_name = g_strdup (data->user_name); - else - data->real_name = g_strdup_printf("user #%d", (int)uid); - } - - if (data->user_name == NULL) - data->user_name = g_strdup_printf("%d", (int)uid); - - g_hash_table_replace (uid_cache, GINT_TO_POINTER (uid), data); - - return data; -} - -static char * -get_username_from_uid (uid_t uid) -{ - char *res; - UidData *data; - - G_LOCK (uid_cache); - data = lookup_uid_data (uid); - res = g_strdup (data->user_name); - G_UNLOCK (uid_cache); - - return res; -} - -static char * -get_realname_from_uid (uid_t uid) -{ - char *res; - UidData *data; - - G_LOCK (uid_cache); - data = lookup_uid_data (uid); - res = g_strdup (data->real_name); - G_UNLOCK (uid_cache); - - return res; -} - - -/* called with lock held */ -static char * -lookup_gid_name (gid_t gid) -{ - char *name; - char buffer[4096]; - struct group gbuf; - struct group *gbufp; - - if (gid_cache == NULL) - gid_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free); - - name = g_hash_table_lookup (gid_cache, GINT_TO_POINTER (gid)); - - if (name) - return name; - - getgrgid_r (gid, &gbuf, buffer, sizeof(buffer), &gbufp); - - if (gbufp != NULL && - gbufp->gr_name != NULL && - gbufp->gr_name[0] != 0) - name = convert_pwd_string_to_utf8 (gbufp->gr_name); - else - name = g_strdup_printf("%d", (int)gid); - - g_hash_table_replace (gid_cache, GINT_TO_POINTER (gid), name); - - return name; -} - -static char * -get_groupname_from_gid (gid_t gid) -{ - char *res; - char *name; - - G_LOCK (gid_cache); - name = lookup_gid_name (gid); - res = g_strdup (name); - G_UNLOCK (gid_cache); - return res; -} - -static char * -get_content_type (const char *basename, - const char *path, - struct stat *statbuf, - gboolean is_symlink, - gboolean symlink_broken, - GFileGetInfoFlags flags, - gboolean fast) -{ - if (is_symlink && - (symlink_broken || (flags & G_FILE_GET_INFO_NOFOLLOW_SYMLINKS))) - return g_strdup ("inode/symlink"); - else if (S_ISDIR(statbuf->st_mode)) - return g_strdup ("inode/directory"); - else if (S_ISCHR(statbuf->st_mode)) - return g_strdup ("inode/chardevice"); - else if (S_ISBLK(statbuf->st_mode)) - return g_strdup ("inode/blockdevice"); - else if (S_ISFIFO(statbuf->st_mode)) - return g_strdup ("inode/fifo"); -#ifdef S_ISSOCK - else if (S_ISSOCK(statbuf->st_mode)) - return g_strdup ("inode/socket"); -#endif - else - { - char *content_type; - gboolean result_uncertain; - - content_type = g_content_type_guess (basename, NULL, 0, &result_uncertain); - -#ifndef G_OS_WIN32 - if (!fast && result_uncertain && path != NULL) - { - guchar sniff_buffer[4096]; - gsize sniff_length; - int fd; - - sniff_length = _g_unix_content_type_get_sniff_len (); - if (sniff_length > 4096) - sniff_length = 4096; - - fd = open (path, O_RDONLY); - if (fd != -1) - { - ssize_t res; - - res = read (fd, sniff_buffer, sniff_length); - close (fd); - if (res != -1) - { - g_free (content_type); - content_type = g_content_type_guess (basename, sniff_buffer, sniff_length, NULL); - } - } - } -#endif - - return content_type; - } - -} - -GFileInfo * -_g_local_file_info_get (const char *basename, - const char *path, - GFileAttributeMatcher *attribute_matcher, - GFileGetInfoFlags flags, - GLocalParentFileInfo *parent_info, - GError **error) -{ - GFileInfo *info; - struct stat statbuf; - struct stat statbuf2; - int res; - gboolean is_symlink, symlink_broken; - - 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); - - /* Avoid stat in trivial case */ - if (attribute_matcher == NULL) - return info; - - res = g_lstat (path, &statbuf); - 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; - } - -#ifdef S_ISLNK - is_symlink = S_ISLNK (statbuf.st_mode); -#else - is_symlink = FALSE; -#endif - symlink_broken = FALSE; - - if (is_symlink) - { - g_file_info_set_is_symlink (info, TRUE); - - /* Unless NOFOLLOW was set we default to following symlinks */ - if (!(flags & G_FILE_GET_INFO_NOFOLLOW_SYMLINKS)) - { - res = stat (path, &statbuf2); - - /* Report broken links as symlinks */ - if (res != -1) - { - statbuf = statbuf2; - symlink_broken = TRUE; - } - } - } - - set_info_from_stat (info, &statbuf, attribute_matcher); - - if (basename != NULL && basename[0] == '.') - g_file_info_set_is_hidden (info, TRUE); - - if (basename != NULL && basename[strlen (basename) -1] == '~') - g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STD_IS_BACKUP, TRUE); - - if (is_symlink && - g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET)) - { - char *link = read_link (path); - g_file_info_set_symlink_target (info, link); - g_free (link); - } - - 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 (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_CONTENT_TYPE)) - { - char *content_type = get_content_type (basename, path, &statbuf, is_symlink, symlink_broken, flags, FALSE); - - if (content_type) - { - g_file_info_set_content_type (info, content_type); - g_free (content_type); - } - } - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_FAST_CONTENT_TYPE)) - { - char *content_type = get_content_type (basename, path, &statbuf, is_symlink, symlink_broken, flags, FALSE); - - if (content_type) - { - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STD_FAST_CONTENT_TYPE, content_type); - g_free (content_type); - } - } - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_STD_ICON)) - { - /* TODO */ - } - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_OWNER_USER)) - { - char *name; - - name = get_username_from_uid (statbuf.st_uid); - if (name) - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER, name); - } - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_OWNER_USER_REAL)) - { - char *name; - - name = get_realname_from_uid (statbuf.st_uid); - if (name) - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL, name); - } - - if (g_file_attribute_matcher_matches (attribute_matcher, - G_FILE_ATTRIBUTE_OWNER_GROUP)) - { - char *name; - - name = get_groupname_from_gid (statbuf.st_gid); - if (name) - g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP, name); - } - - - get_access_rights (attribute_matcher, info, path, &statbuf, parent_info); - - get_selinux_context (path, info, attribute_matcher, (flags & G_FILE_GET_INFO_NOFOLLOW_SYMLINKS) == 0); - get_xattrs (path, TRUE, info, attribute_matcher, (flags & G_FILE_GET_INFO_NOFOLLOW_SYMLINKS) == 0); - get_xattrs (path, FALSE, info, attribute_matcher, (flags & G_FILE_GET_INFO_NOFOLLOW_SYMLINKS) == 0); - - g_file_info_unset_attribute_mask (info); - - return info; -} - -GFileInfo * -_g_local_file_info_get_from_fd (int fd, - char *attributes, - GError **error) -{ - struct stat stat_buf; - GFileAttributeMatcher *matcher; - GFileInfo *info; - - if (fstat (fd, &stat_buf) == -1) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error stating file descriptor: %s"), - g_strerror (errno)); - return NULL; - } - - info = g_file_info_new (); - - matcher = g_file_attribute_matcher_new (attributes); - - /* Make sure we don't set any unwanted attributes */ - g_file_info_set_attribute_mask (info, matcher); - - set_info_from_stat (info, &stat_buf, matcher); - -#ifdef HAVE_SELINUX - if (g_file_attribute_matcher_matches (matcher, "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); - } - } -#endif - - get_xattrs_from_fd (fd, TRUE, info, matcher); - get_xattrs_from_fd (fd, FALSE, info, matcher); - - g_file_attribute_matcher_unref (matcher); - - g_file_info_unset_attribute_mask (info); - - return info; -} - -static gboolean -get_uint32 (const GFileAttributeValue *value, - guint32 *val_out, - GError **error) -{ - 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)")); - return FALSE; - } - - *val_out = value->u.uint32; - - return TRUE; -} - -static gboolean -get_uint64 (const GFileAttributeValue *value, - guint64 *val_out, - GError **error) -{ - 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)")); - return FALSE; - } - - *val_out = value->u.uint64; - - return TRUE; -} - -#if defined(HAVE_SYMLINK) -static gboolean -get_byte_string (const GFileAttributeValue *value, - const char **val_out, - GError **error) -{ - 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)")); - return FALSE; - } - - *val_out = value->u.string; - - return TRUE; -} -#endif - -static gboolean -set_unix_mode (char *filename, - const GFileAttributeValue *value, - GError **error) -{ - guint32 val; - - if (!get_uint32 (value, &val, error)) - return FALSE; - - if (g_chmod (filename, val) == -1) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error setting permissions: %s"), - g_strerror (errno)); - return FALSE; - } - return TRUE; -} - -#ifdef HAVE_CHOWN -static gboolean -set_unix_uid_gid (char *filename, - const GFileAttributeValue *uid_value, - const GFileAttributeValue *gid_value, - GFileGetInfoFlags flags, - GError **error) -{ - int res; - guint32 val; - uid_t uid; - gid_t gid; - - if (uid_value) - { - if (!get_uint32 (uid_value, &val, error)) - return FALSE; - uid = val; - } - else - uid = -1; - - if (gid_value) - { - if (!get_uint32 (gid_value, &val, error)) - return FALSE; - gid = val; - } - else - gid = -1; - - if (flags & G_FILE_GET_INFO_NOFOLLOW_SYMLINKS) - res = lchown (filename, uid, gid); - else - res = chown (filename, uid, gid); - - if (res == -1) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error setting owner: %s"), - g_strerror (errno)); - return FALSE; - } - return TRUE; -} -#endif - -#ifdef HAVE_SYMLINK -static gboolean -set_symlink (char *filename, - const GFileAttributeValue *value, - GError **error) -{ - const char *val; - struct stat statbuf; - - if (!get_byte_string (value, &val, error)) - return FALSE; - - if (val == NULL) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("symlink must be non-NULL")); - return FALSE; - } - - if (g_lstat (filename, &statbuf)) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error setting symlink: %s"), - g_strerror (errno)); - 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")); - return FALSE; - } - - if (g_unlink (filename)) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error setting symlink: %s"), - g_strerror (errno)); - return FALSE; - } - - if (symlink (filename, val) != 0) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error setting symlink: %s"), - g_strerror (errno)); - return FALSE; - } - - return TRUE; -} -#endif - -static int -lazy_stat (char *filename, struct stat *statbuf, gboolean *called_stat) -{ - int res; - - if (*called_stat) - return 0; - - res = g_stat (filename, statbuf); - - if (res == 0) - *called_stat = TRUE; - - return res; -} - - -#ifdef HAVE_UTIMES -static gboolean -set_mtime_atime (char *filename, - const GFileAttributeValue *mtime_value, - const GFileAttributeValue *mtime_usec_value, - const GFileAttributeValue *atime_value, - const GFileAttributeValue *atime_usec_value, - GError **error) -{ - int res; - guint64 val; - guint32 val_usec; - struct stat statbuf; - gboolean got_stat = FALSE; - struct timeval times[2] = { {0, 0}, {0, 0} }; - - /* ATIME */ - if (atime_value) - { - if (!get_uint64 (atime_value, &val, error)) - return FALSE; - times[0].tv_sec = val; - } - else - { - if (lazy_stat (filename, &statbuf, &got_stat) == 0) - { - times[0].tv_sec = statbuf.st_mtime; -#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC) - times[0].tv_usec = statbuf.st_atimensec / 1000; -#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) - times[0].tv_usec = statbuf.st_atim.tv_nsec / 1000; -#endif - } - } - - if (atime_usec_value) - { - if (!get_uint32 (atime_usec_value, &val_usec, error)) - return FALSE; - times[0].tv_usec = val_usec; - } - - /* MTIME */ - if (mtime_value) - { - if (!get_uint64 (mtime_value, &val, error)) - return FALSE; - times[1].tv_sec = val; - } - else - { - if (lazy_stat (filename, &statbuf, &got_stat) == 0) - { - times[1].tv_sec = statbuf.st_mtime; -#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) - times[1].tv_usec = statbuf.st_mtimensec / 1000; -#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) - times[1].tv_usec = statbuf.st_mtim.tv_nsec / 1000; -#endif - } - } - - if (mtime_usec_value) - { - if (!get_uint32 (mtime_usec_value, &val_usec, error)) - return FALSE; - times[1].tv_usec = val_usec; - } - - res = utimes(filename, times); - if (res == -1) - { - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errno), - _("Error setting owner: %s"), - g_strerror (errno)); - return FALSE; - } - return TRUE; -} -#endif - -gboolean -_g_local_file_info_set_attribute (char *filename, - const char *attribute, - const GFileAttributeValue *value, - GFileGetInfoFlags flags, - GCancellable *cancellable, - GError **error) -{ - if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0) - return set_unix_mode (filename, value, error); - -#ifdef HAVE_CHOWN - else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0) - 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); -#endif - -#ifdef HAVE_SYMLINK - else if (strcmp (attribute, G_FILE_ATTRIBUTE_STD_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); - else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC) == 0) - 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); - else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC) == 0) - return set_mtime_atime (filename, NULL, NULL, NULL, value, error); -#endif - - else if (g_str_has_prefix (attribute, "xattr:") == 0) - return set_xattr (filename, attribute, value, error); - else if (g_str_has_prefix (attribute, "xattr_sys:") == 0) - return set_xattr (filename, attribute, value, error); - - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - _("Setting attribute %s not supported"), attribute); - return FALSE; -} - -gboolean -_g_local_file_info_set_attributes (char *filename, - GFileInfo *info, - GFileGetInfoFlags flags, - GCancellable *cancellable, - GError **error) -{ - GFileAttributeValue *value, *uid, *gid; - GFileAttributeValue *mtime, *mtime_usec, *atime, *atime_usec; - GFileAttributeStatus status; - gboolean res; - - /* Handles setting multiple specified data in a single set, and takes care - of ordering restrictions when setting attributes */ - - res = TRUE; - - /* Set symlink first, since this recreates the file */ -#ifdef HAVE_SYMLINK - value = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET); - if (value) - { - if (!set_symlink (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 - -#ifdef HAVE_CHOWN - /* 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); - - if (uid || gid) - { - if (!set_unix_uid_gid (filename, uid, gid, flags, error)) - { - status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING; - res = FALSE; - /* Don't set error multiple times */ - error = NULL; - } - else - status = G_FILE_ATTRIBUTE_STATUS_SET; - if (uid) - uid->status = status; - if (gid) - gid->status = status; - } -#endif - - value = g_file_info_get_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE); - if (value) - { - if (!set_unix_mode (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; - - } - -#ifdef HAVE_UTIMES - /* Group all time settings into one call - * 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); - - if (mtime || mtime_usec || atime || atime_usec) - { - if (!set_mtime_atime (filename, mtime, mtime_usec, atime, atime_usec, error)) - { - status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING; - res = FALSE; - /* Don't set error multiple times */ - error = NULL; - } - else - status = G_FILE_ATTRIBUTE_STATUS_SET; - - if (mtime) - mtime->status = status; - if (mtime_usec) - mtime_usec->status = status; - if (atime) - atime->status = status; - if (atime_usec) - atime_usec->status = status; - } -#endif - - /* xattrs are handled by default callback */ - - return res; -} |