glib/gio/gfileinfo.c

3059 lines
82 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
/**
* SECTION:gfileinfo
* @short_description: File Information and Attributes
* @include: gio/gio.h
* @see_also: #GFile, [GFileAttribute][gio-GFileAttribute]
*
* Functionality for manipulating basic metadata for files. #GFileInfo
* implements methods for getting information that all files should
* contain, and allows for manipulation of extended attributes.
*
* See [GFileAttribute][gio-GFileAttribute] for more information on how
* GIO handles file attributes.
*
* To obtain a #GFileInfo for a #GFile, use g_file_query_info() (or its
* async variant). To obtain a #GFileInfo for a file input or output
* stream, use g_file_input_stream_query_info() or
* g_file_output_stream_query_info() (or their async variants).
*
* To change the actual attributes of a file, you should then set the
* attribute in the #GFileInfo and call g_file_set_attributes_from_info()
* or g_file_set_attributes_async() on a GFile.
*
* However, not all attributes can be changed in the file. For instance,
* the actual size of a file cannot be changed via g_file_info_set_size().
* You may call g_file_query_settable_attributes() and
* g_file_query_writable_namespaces() to discover the settable attributes
* of a particular file at runtime.
*
* The direct accessors, such as g_file_info_get_name(), are slightly more
* optimized than the generic attribute accessors, such as
* g_file_info_get_attribute_byte_string().This optimization will matter
* only if calling the API in a tight loop.
*
* It is an error to call these accessors without specifying their required file
* attributes when creating the #GFileInfo. Use g_file_info_has_attribute() or
* g_file_info_list_attributes() to check what attributes are specified for a
* #GFileInfo.
*
* #GFileAttributeMatcher allows for searching through a #GFileInfo for
* attributes.
**/
#include "config.h"
#include <string.h>
#include "gfileinfo.h"
#include "gfileinfo-priv.h"
#include "gfileattribute-priv.h"
#include "gicon.h"
#include "glibintl.h"
/* We use this nasty thing, because NULL is a valid attribute matcher (matches nothing) */
#define NO_ATTRIBUTE_MASK ((GFileAttributeMatcher *)1)
typedef struct {
guint32 attribute;
GFileAttributeValue value;
} GFileAttribute;
struct _GFileInfo
{
GObject parent_instance;
GArray *attributes;
GFileAttributeMatcher *mask;
};
struct _GFileInfoClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE (GFileInfo, g_file_info, G_TYPE_OBJECT)
typedef struct {
guint32 id;
guint32 attribute_id_counter;
} NSInfo;
G_LOCK_DEFINE_STATIC (attribute_hash);
static int namespace_id_counter = 0;
static GHashTable *ns_hash = NULL;
static GHashTable *attribute_hash = NULL;
static char ***global_attributes = NULL;
/* Attribute ids are 32bit, we split it up like this:
* |------------|--------------------|
* 12 bit 20 bit
* namespace attribute id
*
* This way the attributes gets sorted in namespace order
*/
#define NS_POS 20
#define NS_MASK ((guint32)((1<<12) - 1))
#define ID_POS 0
#define ID_MASK ((guint32)((1<<20) - 1))
#define GET_NS(_attr_id) \
(((guint32) (_attr_id) >> NS_POS) & NS_MASK)
#define GET_ID(_attr_id) \
(((guint32)(_attr_id) >> ID_POS) & ID_MASK)
#define MAKE_ATTR_ID(_ns, _id) \
( ((((guint32) _ns) & NS_MASK) << NS_POS) | \
((((guint32) _id) & ID_MASK) << ID_POS) )
static NSInfo *
_lookup_namespace (const char *namespace)
{
NSInfo *ns_info;
ns_info = g_hash_table_lookup (ns_hash, namespace);
if (ns_info == NULL)
{
ns_info = g_new0 (NSInfo, 1);
ns_info->id = ++namespace_id_counter;
g_hash_table_insert (ns_hash, g_strdup (namespace), ns_info);
global_attributes = g_realloc (global_attributes, (ns_info->id + 1) * sizeof (char **));
global_attributes[ns_info->id] = g_new (char *, 1);
global_attributes[ns_info->id][0] = g_strconcat (namespace, "::*", NULL);
}
return ns_info;
}
static guint32
_lookup_attribute (const char *attribute)
{
guint32 attr_id, id;
char *ns;
const char *colon;
NSInfo *ns_info;
attr_id = GPOINTER_TO_UINT (g_hash_table_lookup (attribute_hash, attribute));
if (attr_id != 0)
return attr_id;
colon = strstr (attribute, "::");
if (colon)
ns = g_strndup (attribute, colon - attribute);
else
ns = g_strdup ("");
ns_info = _lookup_namespace (ns);
g_free (ns);
id = ++ns_info->attribute_id_counter;
global_attributes[ns_info->id] = g_realloc (global_attributes[ns_info->id], (id + 1) * sizeof (char *));
global_attributes[ns_info->id][id] = g_strdup (attribute);
attr_id = MAKE_ATTR_ID (ns_info->id, id);
g_hash_table_insert (attribute_hash, global_attributes[ns_info->id][id], GUINT_TO_POINTER (attr_id));
return attr_id;
}
static void
ensure_attribute_hash (void)
{
if (attribute_hash != NULL)
return;
ns_hash = g_hash_table_new (g_str_hash, g_str_equal);
attribute_hash = g_hash_table_new (g_str_hash, g_str_equal);
#define REGISTER_ATTRIBUTE(name) G_STMT_START{\
guint _u G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */; \
_u = _lookup_attribute (G_FILE_ATTRIBUTE_ ## name); \
/* use for generating the ID: g_print ("#define G_FILE_ATTRIBUTE_ID_%s (%u + %u)\n", #name + 17, _u & ~ID_MASK, _u & ID_MASK); */ \
g_assert (_u == G_FILE_ATTRIBUTE_ID_ ## name); \
}G_STMT_END
REGISTER_ATTRIBUTE (STANDARD_TYPE);
REGISTER_ATTRIBUTE (STANDARD_IS_HIDDEN);
REGISTER_ATTRIBUTE (STANDARD_IS_BACKUP);
REGISTER_ATTRIBUTE (STANDARD_IS_SYMLINK);
REGISTER_ATTRIBUTE (STANDARD_IS_VIRTUAL);
REGISTER_ATTRIBUTE (STANDARD_NAME);
REGISTER_ATTRIBUTE (STANDARD_DISPLAY_NAME);
REGISTER_ATTRIBUTE (STANDARD_EDIT_NAME);
REGISTER_ATTRIBUTE (STANDARD_COPY_NAME);
REGISTER_ATTRIBUTE (STANDARD_DESCRIPTION);
REGISTER_ATTRIBUTE (STANDARD_ICON);
REGISTER_ATTRIBUTE (STANDARD_CONTENT_TYPE);
REGISTER_ATTRIBUTE (STANDARD_FAST_CONTENT_TYPE);
REGISTER_ATTRIBUTE (STANDARD_SIZE);
REGISTER_ATTRIBUTE (STANDARD_ALLOCATED_SIZE);
REGISTER_ATTRIBUTE (STANDARD_SYMLINK_TARGET);
REGISTER_ATTRIBUTE (STANDARD_TARGET_URI);
REGISTER_ATTRIBUTE (STANDARD_SORT_ORDER);
REGISTER_ATTRIBUTE (STANDARD_SYMBOLIC_ICON);
REGISTER_ATTRIBUTE (STANDARD_IS_VOLATILE);
REGISTER_ATTRIBUTE (ETAG_VALUE);
REGISTER_ATTRIBUTE (ID_FILE);
REGISTER_ATTRIBUTE (ID_FILESYSTEM);
REGISTER_ATTRIBUTE (ACCESS_CAN_READ);
REGISTER_ATTRIBUTE (ACCESS_CAN_WRITE);
REGISTER_ATTRIBUTE (ACCESS_CAN_EXECUTE);
REGISTER_ATTRIBUTE (ACCESS_CAN_DELETE);
REGISTER_ATTRIBUTE (ACCESS_CAN_TRASH);
REGISTER_ATTRIBUTE (ACCESS_CAN_RENAME);
REGISTER_ATTRIBUTE (MOUNTABLE_CAN_MOUNT);
REGISTER_ATTRIBUTE (MOUNTABLE_CAN_UNMOUNT);
REGISTER_ATTRIBUTE (MOUNTABLE_CAN_EJECT);
REGISTER_ATTRIBUTE (MOUNTABLE_UNIX_DEVICE);
REGISTER_ATTRIBUTE (MOUNTABLE_UNIX_DEVICE_FILE);
REGISTER_ATTRIBUTE (MOUNTABLE_HAL_UDI);
REGISTER_ATTRIBUTE (MOUNTABLE_CAN_START);
REGISTER_ATTRIBUTE (MOUNTABLE_CAN_START_DEGRADED);
REGISTER_ATTRIBUTE (MOUNTABLE_CAN_STOP);
REGISTER_ATTRIBUTE (MOUNTABLE_START_STOP_TYPE);
REGISTER_ATTRIBUTE (MOUNTABLE_CAN_POLL);
REGISTER_ATTRIBUTE (MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC);
REGISTER_ATTRIBUTE (TIME_MODIFIED);
REGISTER_ATTRIBUTE (TIME_MODIFIED_USEC);
REGISTER_ATTRIBUTE (TIME_ACCESS);
REGISTER_ATTRIBUTE (TIME_ACCESS_USEC);
REGISTER_ATTRIBUTE (TIME_CHANGED);
REGISTER_ATTRIBUTE (TIME_CHANGED_USEC);
REGISTER_ATTRIBUTE (TIME_CREATED);
REGISTER_ATTRIBUTE (TIME_CREATED_USEC);
REGISTER_ATTRIBUTE (TIME_MODIFIED_NSEC);
REGISTER_ATTRIBUTE (TIME_ACCESS_NSEC);
REGISTER_ATTRIBUTE (TIME_CREATED_NSEC);
REGISTER_ATTRIBUTE (TIME_CHANGED_NSEC);
REGISTER_ATTRIBUTE (UNIX_DEVICE);
REGISTER_ATTRIBUTE (UNIX_INODE);
REGISTER_ATTRIBUTE (UNIX_MODE);
REGISTER_ATTRIBUTE (UNIX_NLINK);
REGISTER_ATTRIBUTE (UNIX_UID);
REGISTER_ATTRIBUTE (UNIX_GID);
REGISTER_ATTRIBUTE (UNIX_RDEV);
REGISTER_ATTRIBUTE (UNIX_BLOCK_SIZE);
REGISTER_ATTRIBUTE (UNIX_BLOCKS);
REGISTER_ATTRIBUTE (UNIX_IS_MOUNTPOINT);
REGISTER_ATTRIBUTE (DOS_IS_ARCHIVE);
REGISTER_ATTRIBUTE (DOS_IS_SYSTEM);
REGISTER_ATTRIBUTE (DOS_IS_MOUNTPOINT);
REGISTER_ATTRIBUTE (DOS_REPARSE_POINT_TAG);
REGISTER_ATTRIBUTE (OWNER_USER);
REGISTER_ATTRIBUTE (OWNER_USER_REAL);
REGISTER_ATTRIBUTE (OWNER_GROUP);
REGISTER_ATTRIBUTE (THUMBNAIL_PATH);
REGISTER_ATTRIBUTE (THUMBNAILING_FAILED);
REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID);
REGISTER_ATTRIBUTE (THUMBNAIL_PATH_NORMAL);
REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_NORMAL);
REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_NORMAL);
REGISTER_ATTRIBUTE (THUMBNAIL_PATH_LARGE);
REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_LARGE);
REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_LARGE);
REGISTER_ATTRIBUTE (THUMBNAIL_PATH_XLARGE);
REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_XLARGE);
REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_XLARGE);
REGISTER_ATTRIBUTE (THUMBNAIL_PATH_XXLARGE);
REGISTER_ATTRIBUTE (THUMBNAILING_FAILED_XXLARGE);
REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID_XXLARGE);
REGISTER_ATTRIBUTE (PREVIEW_ICON);
REGISTER_ATTRIBUTE (FILESYSTEM_SIZE);
REGISTER_ATTRIBUTE (FILESYSTEM_FREE);
REGISTER_ATTRIBUTE (FILESYSTEM_TYPE);
REGISTER_ATTRIBUTE (FILESYSTEM_READONLY);
REGISTER_ATTRIBUTE (FILESYSTEM_USE_PREVIEW);
REGISTER_ATTRIBUTE (GVFS_BACKEND);
REGISTER_ATTRIBUTE (SELINUX_CONTEXT);
REGISTER_ATTRIBUTE (TRASH_ITEM_COUNT);
REGISTER_ATTRIBUTE (TRASH_ORIG_PATH);
REGISTER_ATTRIBUTE (TRASH_DELETION_DATE);
#undef REGISTER_ATTRIBUTE
}
static guint32
lookup_namespace (const char *namespace)
{
NSInfo *ns_info;
guint32 id;
G_LOCK (attribute_hash);
ensure_attribute_hash ();
ns_info = _lookup_namespace (namespace);
id = 0;
if (ns_info)
id = ns_info->id;
G_UNLOCK (attribute_hash);
return id;
}
static char *
get_attribute_for_id (int attribute)
{
char *s;
G_LOCK (attribute_hash);
s = global_attributes[GET_NS (attribute)][GET_ID (attribute)];
G_UNLOCK (attribute_hash);
return s;
}
static guint32
lookup_attribute (const char *attribute)
{
guint32 attr_id;
G_LOCK (attribute_hash);
ensure_attribute_hash ();
attr_id = _lookup_attribute (attribute);
G_UNLOCK (attribute_hash);
return attr_id;
}
static void
g_file_info_finalize (GObject *object)
{
GFileInfo *info;
guint i;
GFileAttribute *attrs;
info = G_FILE_INFO (object);
attrs = (GFileAttribute *)info->attributes->data;
for (i = 0; i < info->attributes->len; i++)
_g_file_attribute_value_clear (&attrs[i].value);
g_array_free (info->attributes, TRUE);
if (info->mask != NO_ATTRIBUTE_MASK)
g_file_attribute_matcher_unref (info->mask);
G_OBJECT_CLASS (g_file_info_parent_class)->finalize (object);
}
static void
g_file_info_class_init (GFileInfoClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = g_file_info_finalize;
}
static void
g_file_info_init (GFileInfo *info)
{
info->mask = NO_ATTRIBUTE_MASK;
info->attributes = g_array_new (FALSE, FALSE,
sizeof (GFileAttribute));
}
/**
* g_file_info_new:
*
* Creates a new file info structure.
*
* Returns: a #GFileInfo.
**/
GFileInfo *
g_file_info_new (void)
{
return g_object_new (G_TYPE_FILE_INFO, NULL);
}
/**
* g_file_info_copy_into:
* @src_info: source to copy attributes from.
* @dest_info: destination to copy attributes to.
*
* First clears all of the [GFileAttribute][gio-GFileAttribute] of @dest_info,
* and then copies all of the file attributes from @src_info to @dest_info.
**/
void
g_file_info_copy_into (GFileInfo *src_info,
GFileInfo *dest_info)
{
GFileAttribute *source, *dest;
guint i;
g_return_if_fail (G_IS_FILE_INFO (src_info));
g_return_if_fail (G_IS_FILE_INFO (dest_info));
dest = (GFileAttribute *)dest_info->attributes->data;
for (i = 0; i < dest_info->attributes->len; i++)
_g_file_attribute_value_clear (&dest[i].value);
g_array_set_size (dest_info->attributes,
src_info->attributes->len);
source = (GFileAttribute *)src_info->attributes->data;
dest = (GFileAttribute *)dest_info->attributes->data;
for (i = 0; i < src_info->attributes->len; i++)
{
dest[i].attribute = source[i].attribute;
dest[i].value.type = G_FILE_ATTRIBUTE_TYPE_INVALID;
_g_file_attribute_value_set (&dest[i].value, &source[i].value);
}
if (dest_info->mask != NO_ATTRIBUTE_MASK)
g_file_attribute_matcher_unref (dest_info->mask);
if (src_info->mask == NO_ATTRIBUTE_MASK)
dest_info->mask = NO_ATTRIBUTE_MASK;
else
dest_info->mask = g_file_attribute_matcher_ref (src_info->mask);
}
/**
* g_file_info_dup:
* @other: a #GFileInfo.
*
* Duplicates a file info structure.
*
* Returns: (transfer full): a duplicate #GFileInfo of @other.
**/
GFileInfo *
g_file_info_dup (GFileInfo *other)
{
GFileInfo *new;
g_return_val_if_fail (G_IS_FILE_INFO (other), NULL);
new = g_file_info_new ();
g_file_info_copy_into (other, new);
return new;
}
/**
* g_file_info_set_attribute_mask:
* @info: a #GFileInfo.
* @mask: a #GFileAttributeMatcher.
*
* Sets @mask on @info to match specific attribute types.
**/
void
g_file_info_set_attribute_mask (GFileInfo *info,
GFileAttributeMatcher *mask)
{
GFileAttribute *attr;
guint i;
g_return_if_fail (G_IS_FILE_INFO (info));
if (mask != info->mask)
{
if (info->mask != NO_ATTRIBUTE_MASK)
g_file_attribute_matcher_unref (info->mask);
info->mask = g_file_attribute_matcher_ref (mask);
/* Remove non-matching attributes */
for (i = 0; i < info->attributes->len; i++)
{
attr = &g_array_index (info->attributes, GFileAttribute, i);
if (!_g_file_attribute_matcher_matches_id (mask,
attr->attribute))
{
_g_file_attribute_value_clear (&attr->value);
g_array_remove_index (info->attributes, i);
i--;
}
}
}
}
/**
* g_file_info_unset_attribute_mask:
* @info: #GFileInfo.
*
* Unsets a mask set by g_file_info_set_attribute_mask(), if one
* is set.
**/
void
g_file_info_unset_attribute_mask (GFileInfo *info)
{
g_return_if_fail (G_IS_FILE_INFO (info));
if (info->mask != NO_ATTRIBUTE_MASK)
g_file_attribute_matcher_unref (info->mask);
info->mask = NO_ATTRIBUTE_MASK;
}
/**
* g_file_info_clear_status:
* @info: a #GFileInfo.
*
* Clears the status information from @info.
**/
void
g_file_info_clear_status (GFileInfo *info)
{
GFileAttribute *attrs;
guint i;
g_return_if_fail (G_IS_FILE_INFO (info));
attrs = (GFileAttribute *)info->attributes->data;
for (i = 0; i < info->attributes->len; i++)
attrs[i].value.status = G_FILE_ATTRIBUTE_STATUS_UNSET;
}
static int
g_file_info_find_place (GFileInfo *info,
guint32 attribute)
{
int min, max, med;
GFileAttribute *attrs;
/* Binary search for the place where attribute would be, if it's
in the array */
min = 0;
max = info->attributes->len;
attrs = (GFileAttribute *)info->attributes->data;
while (min < max)
{
med = min + (max - min) / 2;
if (attrs[med].attribute == attribute)
{
min = med;
break;
}
else if (attrs[med].attribute < attribute)
min = med + 1;
else /* attrs[med].attribute > attribute */
max = med;
}
return min;
}
static GFileAttributeValue *
g_file_info_find_value (GFileInfo *info,
guint32 attr_id)
{
GFileAttribute *attrs;
guint i;
i = g_file_info_find_place (info, attr_id);
attrs = (GFileAttribute *)info->attributes->data;
if (i < info->attributes->len &&
attrs[i].attribute == attr_id)
return &attrs[i].value;
return NULL;
}
static GFileAttributeValue *
g_file_info_find_value_by_name (GFileInfo *info,
const char *attribute)
{
guint32 attr_id;
attr_id = lookup_attribute (attribute);
return g_file_info_find_value (info, attr_id);
}
/**
* g_file_info_has_attribute:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Checks if a file info structure has an attribute named @attribute.
*
* Returns: %TRUE if @info has an attribute named @attribute,
* %FALSE otherwise.
**/
gboolean
g_file_info_has_attribute (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
value = g_file_info_find_value_by_name (info, attribute);
return value != NULL;
}
/**
* g_file_info_has_namespace:
* @info: a #GFileInfo.
* @name_space: a file attribute namespace.
*
* Checks if a file info structure has an attribute in the
* specified @name_space.
*
* Returns: %TRUE if @info has an attribute in @name_space,
* %FALSE otherwise.
*
* Since: 2.22
**/
gboolean
g_file_info_has_namespace (GFileInfo *info,
const char *name_space)
{
GFileAttribute *attrs;
guint32 ns_id;
guint i;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
g_return_val_if_fail (name_space != NULL, FALSE);
ns_id = lookup_namespace (name_space);
attrs = (GFileAttribute *)info->attributes->data;
for (i = 0; i < info->attributes->len; i++)
{
if (GET_NS (attrs[i].attribute) == ns_id)
return TRUE;
}
return FALSE;
}
/**
* g_file_info_list_attributes:
* @info: a #GFileInfo.
* @name_space: (nullable): a file attribute key's namespace, or %NULL to list
* all attributes.
*
* Lists the file info structure's attributes.
*
* Returns: (nullable) (array zero-terminated=1) (transfer full): a
* null-terminated array of strings of all of the possible attribute
* types for the given @name_space, or %NULL on error.
**/
char **
g_file_info_list_attributes (GFileInfo *info,
const char *name_space)
{
GPtrArray *names;
GFileAttribute *attrs;
guint32 attribute;
guint32 ns_id = (name_space) ? lookup_namespace (name_space) : 0;
guint i;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
names = g_ptr_array_new ();
attrs = (GFileAttribute *)info->attributes->data;
for (i = 0; i < info->attributes->len; i++)
{
attribute = attrs[i].attribute;
if (ns_id == 0 || GET_NS (attribute) == ns_id)
g_ptr_array_add (names, g_strdup (get_attribute_for_id (attribute)));
}
/* NULL terminate */
g_ptr_array_add (names, NULL);
return (char **)g_ptr_array_free (names, FALSE);
}
/**
* g_file_info_get_attribute_type:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets the attribute type for an attribute key.
*
* Returns: a #GFileAttributeType for the given @attribute, or
* %G_FILE_ATTRIBUTE_TYPE_INVALID if the key is not set.
**/
GFileAttributeType
g_file_info_get_attribute_type (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), G_FILE_ATTRIBUTE_TYPE_INVALID);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', G_FILE_ATTRIBUTE_TYPE_INVALID);
value = g_file_info_find_value_by_name (info, attribute);
if (value)
return value->type;
else
return G_FILE_ATTRIBUTE_TYPE_INVALID;
}
static void
g_file_info_remove_value (GFileInfo *info,
guint32 attr_id)
{
GFileAttribute *attrs;
guint i;
if (info->mask != NO_ATTRIBUTE_MASK &&
!_g_file_attribute_matcher_matches_id (info->mask, attr_id))
return;
i = g_file_info_find_place (info, attr_id);
attrs = (GFileAttribute *)info->attributes->data;
if (i < info->attributes->len &&
attrs[i].attribute == attr_id)
{
_g_file_attribute_value_clear (&attrs[i].value);
g_array_remove_index (info->attributes, i);
}
}
/**
* g_file_info_remove_attribute:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Removes all cases of @attribute from @info if it exists.
**/
void
g_file_info_remove_attribute (GFileInfo *info,
const char *attribute)
{
guint32 attr_id;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
attr_id = lookup_attribute (attribute);
g_file_info_remove_value (info, attr_id);
}
/**
* g_file_info_get_attribute_data:
* @info: a #GFileInfo
* @attribute: a file attribute key
* @type: (out) (optional): return location for the attribute type, or %NULL
* @value_pp: (out) (optional) (not nullable): return location for the
* attribute value, or %NULL; the attribute value will not be %NULL
* @status: (out) (optional): return location for the attribute status, or %NULL
*
* Gets the attribute type, value and status for an attribute key.
*
* Returns: (transfer none): %TRUE if @info has an attribute named @attribute,
* %FALSE otherwise.
*/
gboolean
g_file_info_get_attribute_data (GFileInfo *info,
const char *attribute,
GFileAttributeType *type,
gpointer *value_pp,
GFileAttributeStatus *status)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
value = g_file_info_find_value_by_name (info, attribute);
if (value == NULL)
return FALSE;
if (status)
*status = value->status;
if (type)
*type = value->type;
if (value_pp)
*value_pp = _g_file_attribute_value_peek_as_pointer (value);
return TRUE;
}
/**
* g_file_info_get_attribute_status:
* @info: a #GFileInfo
* @attribute: a file attribute key
*
* Gets the attribute status for an attribute key.
*
* Returns: a #GFileAttributeStatus for the given @attribute, or
* %G_FILE_ATTRIBUTE_STATUS_UNSET if the key is invalid.
*
*/
GFileAttributeStatus
g_file_info_get_attribute_status (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *val;
g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
val = g_file_info_find_value_by_name (info, attribute);
if (val)
return val->status;
return G_FILE_ATTRIBUTE_STATUS_UNSET;
}
/**
* g_file_info_set_attribute_status:
* @info: a #GFileInfo
* @attribute: a file attribute key
* @status: a #GFileAttributeStatus
*
* Sets the attribute status for an attribute key. This is only
* needed by external code that implement g_file_set_attributes_from_info()
* or similar functions.
*
* The attribute must exist in @info for this to work. Otherwise %FALSE
* is returned and @info is unchanged.
*
* Returns: %TRUE if the status was changed, %FALSE if the key was not set.
*
* Since: 2.22
*/
gboolean
g_file_info_set_attribute_status (GFileInfo *info,
const char *attribute,
GFileAttributeStatus status)
{
GFileAttributeValue *val;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
val = g_file_info_find_value_by_name (info, attribute);
if (val)
{
val->status = status;
return TRUE;
}
return FALSE;
}
GFileAttributeValue *
_g_file_info_get_attribute_value (GFileInfo *info,
const char *attribute)
{
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
return g_file_info_find_value_by_name (info, attribute);
}
/**
* g_file_info_get_attribute_as_string:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets the value of an attribute, formatted as a string.
* This escapes things as needed to make the string valid
* UTF-8.
*
* Returns: (nullable): a UTF-8 string associated with the given @attribute, or
* %NULL if the attribute wasnt set.
* When you're done with the string it must be freed with g_free().
**/
char *
g_file_info_get_attribute_as_string (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *val;
val = _g_file_info_get_attribute_value (info, attribute);
if (val)
return _g_file_attribute_value_as_string (val);
return NULL;
}
/**
* g_file_info_get_attribute_object:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets the value of a #GObject attribute. If the attribute does
* not contain a #GObject, %NULL will be returned.
*
* Returns: (transfer none) (nullable): a #GObject associated with the given @attribute,
* or %NULL otherwise.
**/
GObject *
g_file_info_get_attribute_object (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_object (value);
}
/**
* g_file_info_get_attribute_string:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets the value of a string attribute. If the attribute does
* not contain a string, %NULL will be returned.
*
* Returns: (nullable): the contents of the @attribute value as a UTF-8 string,
* or %NULL otherwise.
**/
const char *
g_file_info_get_attribute_string (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_string (value);
}
/**
* g_file_info_get_attribute_byte_string:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets the value of a byte string attribute. If the attribute does
* not contain a byte string, %NULL will be returned.
*
* Returns: (nullable): the contents of the @attribute value as a byte string, or
* %NULL otherwise.
**/
const char *
g_file_info_get_attribute_byte_string (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_byte_string (value);
}
/**
* g_file_info_get_attribute_stringv:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets the value of a stringv attribute. If the attribute does
* not contain a stringv, %NULL will be returned.
*
* Returns: (transfer none) (nullable): the contents of the @attribute value as a stringv,
* or %NULL otherwise. Do not free. These returned strings are UTF-8.
*
* Since: 2.22
**/
char **
g_file_info_get_attribute_stringv (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', NULL);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_stringv (value);
}
/**
* g_file_info_get_attribute_boolean:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets the value of a boolean attribute. If the attribute does not
* contain a boolean value, %FALSE will be returned.
*
* Returns: the boolean value contained within the attribute.
**/
gboolean
g_file_info_get_attribute_boolean (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_boolean (value);
}
/**
* g_file_info_get_attribute_uint32:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets an unsigned 32-bit integer contained within the attribute. If the
* attribute does not contain an unsigned 32-bit integer, or is invalid,
* 0 will be returned.
*
* Returns: an unsigned 32-bit integer from the attribute.
**/
guint32
g_file_info_get_attribute_uint32 (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_uint32 (value);
}
/**
* g_file_info_get_attribute_int32:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets a signed 32-bit integer contained within the attribute. If the
* attribute does not contain a signed 32-bit integer, or is invalid,
* 0 will be returned.
*
* Returns: a signed 32-bit integer from the attribute.
**/
gint32
g_file_info_get_attribute_int32 (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_int32 (value);
}
/**
* g_file_info_get_attribute_uint64:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets a unsigned 64-bit integer contained within the attribute. If the
* attribute does not contain an unsigned 64-bit integer, or is invalid,
* 0 will be returned.
*
* Returns: a unsigned 64-bit integer from the attribute.
**/
guint64
g_file_info_get_attribute_uint64 (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_uint64 (value);
}
/**
* g_file_info_get_attribute_int64:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
*
* Gets a signed 64-bit integer contained within the attribute. If the
* attribute does not contain a signed 64-bit integer, or is invalid,
* 0 will be returned.
*
* Returns: a signed 64-bit integer from the attribute.
**/
gint64
g_file_info_get_attribute_int64 (GFileInfo *info,
const char *attribute)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
g_return_val_if_fail (attribute != NULL && *attribute != '\0', 0);
value = g_file_info_find_value_by_name (info, attribute);
return _g_file_attribute_value_get_int64 (value);
}
static GFileAttributeValue *
g_file_info_create_value (GFileInfo *info,
guint32 attr_id)
{
GFileAttribute *attrs;
guint i;
if (info->mask != NO_ATTRIBUTE_MASK &&
!_g_file_attribute_matcher_matches_id (info->mask, attr_id))
return NULL;
i = g_file_info_find_place (info, attr_id);
attrs = (GFileAttribute *)info->attributes->data;
if (i < info->attributes->len &&
attrs[i].attribute == attr_id)
return &attrs[i].value;
else
{
GFileAttribute attr = { 0 };
attr.attribute = attr_id;
g_array_insert_val (info->attributes, i, attr);
attrs = (GFileAttribute *)info->attributes->data;
return &attrs[i].value;
}
}
void
_g_file_info_set_attribute_by_id (GFileInfo *info,
guint32 attribute,
GFileAttributeType type,
gpointer value_p)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_from_pointer (value, type, value_p, TRUE);
}
/**
* g_file_info_set_attribute:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @type: a #GFileAttributeType
* @value_p: (not nullable): pointer to the value
*
* Sets the @attribute to contain the given value, if possible. To unset the
* attribute, use %G_FILE_ATTRIBUTE_TYPE_INVALID for @type.
**/
void
g_file_info_set_attribute (GFileInfo *info,
const char *attribute,
GFileAttributeType type,
gpointer value_p)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
_g_file_info_set_attribute_by_id (info, lookup_attribute (attribute), type, value_p);
}
void
_g_file_info_set_attribute_object_by_id (GFileInfo *info,
guint32 attribute,
GObject *attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_object (value, attr_value);
}
/**
* g_file_info_set_attribute_object:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @attr_value: a #GObject.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
**/
void
g_file_info_set_attribute_object (GFileInfo *info,
const char *attribute,
GObject *attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
g_return_if_fail (G_IS_OBJECT (attr_value));
_g_file_info_set_attribute_object_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_stringv_by_id (GFileInfo *info,
guint32 attribute,
char **attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_stringv (value, attr_value);
}
/**
* g_file_info_set_attribute_stringv:
* @info: a #GFileInfo.
* @attribute: a file attribute key
* @attr_value: (array zero-terminated=1) (element-type utf8): a %NULL
* terminated array of UTF-8 strings.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
*
* Sinze: 2.22
**/
void
g_file_info_set_attribute_stringv (GFileInfo *info,
const char *attribute,
char **attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
g_return_if_fail (attr_value != NULL);
_g_file_info_set_attribute_stringv_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_string_by_id (GFileInfo *info,
guint32 attribute,
const char *attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_string (value, attr_value);
}
/**
* g_file_info_set_attribute_string:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @attr_value: a UTF-8 string.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
**/
void
g_file_info_set_attribute_string (GFileInfo *info,
const char *attribute,
const char *attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
g_return_if_fail (attr_value != NULL);
_g_file_info_set_attribute_string_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_byte_string_by_id (GFileInfo *info,
guint32 attribute,
const char *attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_byte_string (value, attr_value);
}
/**
* g_file_info_set_attribute_byte_string:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @attr_value: a byte string.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
**/
void
g_file_info_set_attribute_byte_string (GFileInfo *info,
const char *attribute,
const char *attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
g_return_if_fail (attr_value != NULL);
_g_file_info_set_attribute_byte_string_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_boolean_by_id (GFileInfo *info,
guint32 attribute,
gboolean attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_boolean (value, attr_value);
}
/**
* g_file_info_set_attribute_boolean:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @attr_value: a boolean value.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
**/
void
g_file_info_set_attribute_boolean (GFileInfo *info,
const char *attribute,
gboolean attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
_g_file_info_set_attribute_boolean_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_uint32_by_id (GFileInfo *info,
guint32 attribute,
guint32 attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_uint32 (value, attr_value);
}
/**
* g_file_info_set_attribute_uint32:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @attr_value: an unsigned 32-bit integer.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
**/
void
g_file_info_set_attribute_uint32 (GFileInfo *info,
const char *attribute,
guint32 attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
_g_file_info_set_attribute_uint32_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_int32_by_id (GFileInfo *info,
guint32 attribute,
gint32 attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_int32 (value, attr_value);
}
/**
* g_file_info_set_attribute_int32:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @attr_value: a signed 32-bit integer
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
**/
void
g_file_info_set_attribute_int32 (GFileInfo *info,
const char *attribute,
gint32 attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
_g_file_info_set_attribute_int32_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_uint64_by_id (GFileInfo *info,
guint32 attribute,
guint64 attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_uint64 (value, attr_value);
}
/**
* g_file_info_set_attribute_uint64:
* @info: a #GFileInfo.
* @attribute: a file attribute key.
* @attr_value: an unsigned 64-bit integer.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
**/
void
g_file_info_set_attribute_uint64 (GFileInfo *info,
const char *attribute,
guint64 attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
_g_file_info_set_attribute_uint64_by_id (info,
lookup_attribute (attribute),
attr_value);
}
void
_g_file_info_set_attribute_int64_by_id (GFileInfo *info,
guint32 attribute,
gint64 attr_value)
{
GFileAttributeValue *value;
value = g_file_info_create_value (info, attribute);
if (value)
_g_file_attribute_value_set_int64 (value, attr_value);
}
/**
* g_file_info_set_attribute_int64:
* @info: a #GFileInfo.
* @attribute: attribute name to set.
* @attr_value: int64 value to set attribute to.
*
* Sets the @attribute to contain the given @attr_value,
* if possible.
*
**/
void
g_file_info_set_attribute_int64 (GFileInfo *info,
const char *attribute,
gint64 attr_value)
{
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (attribute != NULL && *attribute != '\0');
_g_file_info_set_attribute_int64_by_id (info,
lookup_attribute (attribute),
attr_value);
}
/* Helper getters */
#define get_required_attribute(value_ptr, info, attribute_name, error_value) \
G_STMT_START { \
static guint32 attr = 0; \
\
if (attr == 0) \
attr = lookup_attribute (attribute_name); \
\
*value_ptr = g_file_info_find_value (info, attr); \
if (G_UNLIKELY (*value_ptr == NULL)) \
{ \
g_critical ("GFileInfo created without " attribute_name); \
g_return_val_if_reached (error_value); \
} \
} G_STMT_END
/**
* g_file_info_get_deletion_date:
* @info: a #GFileInfo.
*
* Returns the #GDateTime representing the deletion date of the file, as
* available in %G_FILE_ATTRIBUTE_TRASH_DELETION_DATE. If the
* %G_FILE_ATTRIBUTE_TRASH_DELETION_DATE attribute is unset, %NULL is returned.
*
* Returns: (nullable): a #GDateTime, or %NULL.
*
* Since: 2.36
**/
GDateTime *
g_file_info_get_deletion_date (GFileInfo *info)
{
static guint32 attr = 0;
GFileAttributeValue *value;
const char *date_str;
GTimeZone *local_tz = NULL;
GDateTime *dt = NULL;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_TRASH_DELETION_DATE);
value = g_file_info_find_value (info, attr);
date_str = _g_file_attribute_value_get_string (value);
if (!date_str)
return NULL;
local_tz = g_time_zone_new_local ();
dt = g_date_time_new_from_iso8601 (date_str, local_tz);
g_time_zone_unref (local_tz);
return g_steal_pointer (&dt);
}
/**
* g_file_info_get_file_type:
* @info: a #GFileInfo.
*
* Gets a file's type (whether it is a regular file, symlink, etc).
* This is different from the file's content type, see g_file_info_get_content_type().
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_TYPE.
*
* Returns: a #GFileType for the given file.
**/
GFileType
g_file_info_get_file_type (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), G_FILE_TYPE_UNKNOWN);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_TYPE_UNKNOWN);
return (GFileType)_g_file_attribute_value_get_uint32 (value);
}
/**
* g_file_info_get_is_hidden:
* @info: a #GFileInfo.
*
* Checks if a file is hidden.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN.
*
* Returns: %TRUE if the file is a hidden file, %FALSE otherwise.
**/
gboolean
g_file_info_get_is_hidden (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN, FALSE);
return _g_file_attribute_value_get_boolean (value);
}
/**
* g_file_info_get_is_backup:
* @info: a #GFileInfo.
*
* Checks if a file is a backup file.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP.
*
* Returns: %TRUE if file is a backup file, %FALSE otherwise.
**/
gboolean
g_file_info_get_is_backup (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP, FALSE);
return _g_file_attribute_value_get_boolean (value);
}
/**
* g_file_info_get_is_symlink:
* @info: a #GFileInfo.
*
* Checks if a file is a symlink.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK.
*
* Returns: %TRUE if the given @info is a symlink.
**/
gboolean
g_file_info_get_is_symlink (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK, FALSE);
return _g_file_attribute_value_get_boolean (value);
}
/**
* g_file_info_get_name:
* @info: a #GFileInfo.
*
* Gets the name for a file. This is guaranteed to always be set.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_NAME.
*
* Returns: (type filename) (not nullable): a string containing the file name.
**/
const char *
g_file_info_get_name (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_NAME, NULL);
return _g_file_attribute_value_get_byte_string (value);
}
/**
* g_file_info_get_display_name:
* @info: a #GFileInfo.
*
* Gets a display name for a file. This is guaranteed to always be set.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.
*
* Returns: (not nullable): a string containing the display name.
**/
const char *
g_file_info_get_display_name (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, NULL);
return _g_file_attribute_value_get_string (value);
}
/**
* g_file_info_get_edit_name:
* @info: a #GFileInfo.
*
* Gets the edit name for a file.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME.
*
* Returns: a string containing the edit name.
**/
const char *
g_file_info_get_edit_name (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME, NULL);
return _g_file_attribute_value_get_string (value);
}
/**
* g_file_info_get_icon:
* @info: a #GFileInfo.
*
* Gets the icon for a file.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_ICON.
*
* Returns: (nullable) (transfer none): #GIcon for the given @info.
**/
GIcon *
g_file_info_get_icon (GFileInfo *info)
{
GFileAttributeValue *value;
GObject *obj;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_ICON, NULL);
obj = _g_file_attribute_value_get_object (value);
if (G_IS_ICON (obj))
return G_ICON (obj);
return NULL;
}
/**
* g_file_info_get_symbolic_icon:
* @info: a #GFileInfo.
*
* Gets the symbolic icon for a file.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON.
*
* Returns: (nullable) (transfer none): #GIcon for the given @info.
*
* Since: 2.34
**/
GIcon *
g_file_info_get_symbolic_icon (GFileInfo *info)
{
GFileAttributeValue *value;
GObject *obj;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON, NULL);
obj = _g_file_attribute_value_get_object (value);
if (G_IS_ICON (obj))
return G_ICON (obj);
return NULL;
}
/**
* g_file_info_get_content_type:
* @info: a #GFileInfo.
*
* Gets the file's content type.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE.
*
* Returns: (nullable): a string containing the file's content type,
* or %NULL if unknown.
**/
const char *
g_file_info_get_content_type (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, NULL);
return _g_file_attribute_value_get_string (value);
}
/**
* g_file_info_get_size:
* @info: a #GFileInfo.
*
* Gets the file's size (in bytes). The size is retrieved through the value of
* the %G_FILE_ATTRIBUTE_STANDARD_SIZE attribute and is converted
* from #guint64 to #goffset before returning the result.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_SIZE.
*
* Returns: a #goffset containing the file's size (in bytes).
**/
goffset
g_file_info_get_size (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), (goffset) 0);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_SIZE, (goffset) 0);
return (goffset) _g_file_attribute_value_get_uint64 (value);
}
/**
* g_file_info_get_modification_time:
* @info: a #GFileInfo.
* @result: (out caller-allocates): a #GTimeVal.
*
* Gets the modification time of the current @info and sets it
* in @result.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_TIME_MODIFIED. If %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC is
* provided it will be used too.
*
* Deprecated: 2.62: Use g_file_info_get_modification_date_time() instead, as
* #GTimeVal is deprecated due to the year 2038 problem.
**/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
void
g_file_info_get_modification_time (GFileInfo *info,
GTimeVal *result)
{
static guint32 attr_mtime = 0, attr_mtime_usec;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (result != NULL);
if (attr_mtime == 0)
{
attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
}
value = g_file_info_find_value (info, attr_mtime);
if (G_UNLIKELY (value == NULL))
{
g_critical ("GFileInfo created without " G_FILE_ATTRIBUTE_TIME_MODIFIED);
result->tv_sec = result->tv_usec = 0;
g_return_if_reached ();
}
result->tv_sec = _g_file_attribute_value_get_uint64 (value);
value = g_file_info_find_value (info, attr_mtime_usec);
result->tv_usec = _g_file_attribute_value_get_uint32 (value);
}
G_GNUC_END_IGNORE_DEPRECATIONS
/**
* g_file_info_get_modification_date_time:
* @info: a #GFileInfo.
*
* Gets the modification time of the current @info and returns it as a
* #GDateTime.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_TIME_MODIFIED. If %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC is
* provided, the resulting #GDateTime will additionally have microsecond
* precision.
*
* If nanosecond precision is needed, %G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC must
* be queried separately using g_file_info_get_attribute_uint32().
*
* Returns: (transfer full) (nullable): modification time, or %NULL if unknown
* Since: 2.62
*/
GDateTime *
g_file_info_get_modification_date_time (GFileInfo *info)
{
static guint32 attr_mtime = 0, attr_mtime_usec;
GFileAttributeValue *value, *value_usec;
GDateTime *dt = NULL, *dt2 = NULL;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
if (attr_mtime == 0)
{
attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
}
value = g_file_info_find_value (info, attr_mtime);
if (value == NULL)
return NULL;
dt = g_date_time_new_from_unix_utc (_g_file_attribute_value_get_uint64 (value));
value_usec = g_file_info_find_value (info, attr_mtime_usec);
if (value_usec == NULL)
return g_steal_pointer (&dt);
dt2 = g_date_time_add (dt, _g_file_attribute_value_get_uint32 (value_usec));
g_date_time_unref (dt);
return g_steal_pointer (&dt2);
}
/**
* g_file_info_get_access_date_time:
* @info: a #GFileInfo.
*
* Gets the access time of the current @info and returns it as a
* #GDateTime.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_TIME_ACCESS. If %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC is
* provided, the resulting #GDateTime will additionally have microsecond
* precision.
*
* If nanosecond precision is needed, %G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC must
* be queried separately using g_file_info_get_attribute_uint32().
*
* Returns: (transfer full) (nullable): access time, or %NULL if unknown
* Since: 2.70
*/
GDateTime *
g_file_info_get_access_date_time (GFileInfo *info)
{
static guint32 attr_atime = 0, attr_atime_usec;
GFileAttributeValue *value, *value_usec;
GDateTime *dt = NULL, *dt2 = NULL;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
if (attr_atime == 0)
{
attr_atime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS);
attr_atime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
}
value = g_file_info_find_value (info, attr_atime);
if (value == NULL)
return NULL;
dt = g_date_time_new_from_unix_utc (_g_file_attribute_value_get_uint64 (value));
value_usec = g_file_info_find_value (info, attr_atime_usec);
if (value_usec == NULL)
return g_steal_pointer (&dt);
dt2 = g_date_time_add (dt, _g_file_attribute_value_get_uint32 (value_usec));
g_date_time_unref (dt);
return g_steal_pointer (&dt2);
}
/**
* g_file_info_get_creation_date_time:
* @info: a #GFileInfo.
*
* Gets the creation time of the current @info and returns it as a
* #GDateTime.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_TIME_CREATED. If %G_FILE_ATTRIBUTE_TIME_CREATED_USEC is
* provided, the resulting #GDateTime will additionally have microsecond
* precision.
*
* If nanosecond precision is needed, %G_FILE_ATTRIBUTE_TIME_CREATED_NSEC must
* be queried separately using g_file_info_get_attribute_uint32().
*
* Returns: (transfer full) (nullable): creation time, or %NULL if unknown
* Since: 2.70
*/
GDateTime *
g_file_info_get_creation_date_time (GFileInfo *info)
{
static guint32 attr_ctime = 0, attr_ctime_usec;
GFileAttributeValue *value, *value_usec;
GDateTime *dt = NULL, *dt2 = NULL;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
if (attr_ctime == 0)
{
attr_ctime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED);
attr_ctime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_USEC);
}
value = g_file_info_find_value (info, attr_ctime);
if (value == NULL)
return NULL;
dt = g_date_time_new_from_unix_utc (_g_file_attribute_value_get_uint64 (value));
value_usec = g_file_info_find_value (info, attr_ctime_usec);
if (value_usec == NULL)
return g_steal_pointer (&dt);
dt2 = g_date_time_add (dt, _g_file_attribute_value_get_uint32 (value_usec));
g_date_time_unref (dt);
return g_steal_pointer (&dt2);
}
/**
* g_file_info_get_symlink_target:
* @info: a #GFileInfo.
*
* Gets the symlink target for a given #GFileInfo.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET.
*
* Returns: (type filename) (nullable): a string containing the symlink target.
**/
const char *
g_file_info_get_symlink_target (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, NULL);
return _g_file_attribute_value_get_byte_string (value);
}
/**
* g_file_info_get_etag:
* @info: a #GFileInfo.
*
* Gets the [entity tag][gfile-etag] for a given
* #GFileInfo. See %G_FILE_ATTRIBUTE_ETAG_VALUE.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_ETAG_VALUE.
*
* Returns: (nullable): a string containing the value of the "etag:value" attribute.
**/
const char *
g_file_info_get_etag (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), NULL);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_ETAG_VALUE, NULL);
return _g_file_attribute_value_get_string (value);
}
/**
* g_file_info_get_sort_order:
* @info: a #GFileInfo.
*
* Gets the value of the sort_order attribute from the #GFileInfo.
* See %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
*
* It is an error to call this if the #GFileInfo does not contain
* %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
*
* Returns: a #gint32 containing the value of the "standard::sort_order" attribute.
**/
gint32
g_file_info_get_sort_order (GFileInfo *info)
{
GFileAttributeValue *value;
g_return_val_if_fail (G_IS_FILE_INFO (info), 0);
get_required_attribute (&value, info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER, 0);
return _g_file_attribute_value_get_int32 (value);
}
/* Helper setters: */
/**
* g_file_info_set_file_type:
* @info: a #GFileInfo.
* @type: a #GFileType.
*
* Sets the file type in a #GFileInfo to @type.
* See %G_FILE_ATTRIBUTE_STANDARD_TYPE.
**/
void
g_file_info_set_file_type (GFileInfo *info,
GFileType type)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_TYPE);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_uint32 (value, type);
}
/**
* g_file_info_set_is_hidden:
* @info: a #GFileInfo.
* @is_hidden: a #gboolean.
*
* Sets the "is_hidden" attribute in a #GFileInfo according to @is_hidden.
* See %G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN.
**/
void
g_file_info_set_is_hidden (GFileInfo *info,
gboolean is_hidden)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_boolean (value, is_hidden);
}
/**
* g_file_info_set_is_symlink:
* @info: a #GFileInfo.
* @is_symlink: a #gboolean.
*
* Sets the "is_symlink" attribute in a #GFileInfo according to @is_symlink.
* See %G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK.
**/
void
g_file_info_set_is_symlink (GFileInfo *info,
gboolean is_symlink)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_boolean (value, is_symlink);
}
/**
* g_file_info_set_name:
* @info: a #GFileInfo.
* @name: (type filename): a string containing a name.
*
* Sets the name attribute for the current #GFileInfo.
* See %G_FILE_ATTRIBUTE_STANDARD_NAME.
**/
void
g_file_info_set_name (GFileInfo *info,
const char *name)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (name != NULL);
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_NAME);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_byte_string (value, name);
}
/**
* g_file_info_set_display_name:
* @info: a #GFileInfo.
* @display_name: a string containing a display name.
*
* Sets the display name for the current #GFileInfo.
* See %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.
**/
void
g_file_info_set_display_name (GFileInfo *info,
const char *display_name)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (display_name != NULL);
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_string (value, display_name);
}
/**
* g_file_info_set_edit_name:
* @info: a #GFileInfo.
* @edit_name: a string containing an edit name.
*
* Sets the edit name for the current file.
* See %G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME.
**/
void
g_file_info_set_edit_name (GFileInfo *info,
const char *edit_name)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (edit_name != NULL);
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_string (value, edit_name);
}
/**
* g_file_info_set_icon:
* @info: a #GFileInfo.
* @icon: a #GIcon.
*
* Sets the icon for a given #GFileInfo.
* See %G_FILE_ATTRIBUTE_STANDARD_ICON.
**/
void
g_file_info_set_icon (GFileInfo *info,
GIcon *icon)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (G_IS_ICON (icon));
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_ICON);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_object (value, G_OBJECT (icon));
}
/**
* g_file_info_set_symbolic_icon:
* @info: a #GFileInfo.
* @icon: a #GIcon.
*
* Sets the symbolic icon for a given #GFileInfo.
* See %G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON.
*
* Since: 2.34
**/
void
g_file_info_set_symbolic_icon (GFileInfo *info,
GIcon *icon)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (G_IS_ICON (icon));
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_object (value, G_OBJECT (icon));
}
/**
* g_file_info_set_content_type:
* @info: a #GFileInfo.
* @content_type: a content type. See [GContentType][gio-GContentType]
*
* Sets the content type attribute for a given #GFileInfo.
* See %G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE.
**/
void
g_file_info_set_content_type (GFileInfo *info,
const char *content_type)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (content_type != NULL);
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_string (value, content_type);
}
/**
* g_file_info_set_size:
* @info: a #GFileInfo.
* @size: a #goffset containing the file's size.
*
* Sets the %G_FILE_ATTRIBUTE_STANDARD_SIZE attribute in the file info
* to the given size.
**/
void
g_file_info_set_size (GFileInfo *info,
goffset size)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SIZE);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_uint64 (value, size);
}
/**
* g_file_info_set_modification_time:
* @info: a #GFileInfo.
* @mtime: a #GTimeVal.
*
* Sets the %G_FILE_ATTRIBUTE_TIME_MODIFIED and
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC attributes in the file info to the
* given time value.
*
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC will be cleared.
*
* Deprecated: 2.62: Use g_file_info_set_modification_date_time() instead, as
* #GTimeVal is deprecated due to the year 2038 problem.
**/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
void
g_file_info_set_modification_time (GFileInfo *info,
GTimeVal *mtime)
{
static guint32 attr_mtime = 0, attr_mtime_usec = 0, attr_mtime_nsec = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (mtime != NULL);
if (attr_mtime == 0)
{
attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
attr_mtime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC);
}
value = g_file_info_create_value (info, attr_mtime);
if (value)
_g_file_attribute_value_set_uint64 (value, mtime->tv_sec);
value = g_file_info_create_value (info, attr_mtime_usec);
if (value)
_g_file_attribute_value_set_uint32 (value, mtime->tv_usec);
/* nsecs cant be known from a #GTimeVal, so remove them */
g_file_info_remove_value (info, attr_mtime_nsec);
}
G_GNUC_END_IGNORE_DEPRECATIONS
/**
* g_file_info_set_modification_date_time:
* @info: a #GFileInfo.
* @mtime: (not nullable): a #GDateTime.
*
* Sets the %G_FILE_ATTRIBUTE_TIME_MODIFIED and
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC attributes in the file info to the
* given date/time value.
*
* %G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC will be cleared.
*
* Since: 2.62
*/
void
g_file_info_set_modification_date_time (GFileInfo *info,
GDateTime *mtime)
{
static guint32 attr_mtime = 0, attr_mtime_usec = 0, attr_mtime_nsec = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (mtime != NULL);
if (attr_mtime == 0)
{
attr_mtime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED);
attr_mtime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
attr_mtime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC);
}
value = g_file_info_create_value (info, attr_mtime);
if (value)
_g_file_attribute_value_set_uint64 (value, g_date_time_to_unix (mtime));
value = g_file_info_create_value (info, attr_mtime_usec);
if (value)
_g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (mtime));
/* nsecs cant be known from a #GDateTime, so remove them */
g_file_info_remove_value (info, attr_mtime_nsec);
}
/**
* g_file_info_set_access_date_time:
* @info: a #GFileInfo.
* @atime: (not nullable): a #GDateTime.
*
* Sets the %G_FILE_ATTRIBUTE_TIME_ACCESS and
* %G_FILE_ATTRIBUTE_TIME_ACCESS_USEC attributes in the file info to the
* given date/time value.
*
* %G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC will be cleared.
*
* Since: 2.70
*/
void
g_file_info_set_access_date_time (GFileInfo *info,
GDateTime *atime)
{
static guint32 attr_atime = 0, attr_atime_usec = 0, attr_atime_nsec = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (atime != NULL);
if (attr_atime == 0)
{
attr_atime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS);
attr_atime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
attr_atime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC);
}
value = g_file_info_create_value (info, attr_atime);
if (value)
_g_file_attribute_value_set_uint64 (value, g_date_time_to_unix (atime));
value = g_file_info_create_value (info, attr_atime_usec);
if (value)
_g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (atime));
/* nsecs cant be known from a #GDateTime, so remove them */
g_file_info_remove_value (info, attr_atime_nsec);
}
/**
* g_file_info_set_creation_date_time:
* @info: a #GFileInfo.
* @creation_time: (not nullable): a #GDateTime.
*
* Sets the %G_FILE_ATTRIBUTE_TIME_CREATED and
* %G_FILE_ATTRIBUTE_TIME_CREATED_USEC attributes in the file info to the
* given date/time value.
*
* %G_FILE_ATTRIBUTE_TIME_CREATED_NSEC will be cleared.
*
* Since: 2.70
*/
void
g_file_info_set_creation_date_time (GFileInfo *info,
GDateTime *creation_time)
{
static guint32 attr_ctime = 0, attr_ctime_usec = 0, attr_ctime_nsec = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (creation_time != NULL);
if (attr_ctime == 0)
{
attr_ctime = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED);
attr_ctime_usec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_USEC);
attr_ctime_nsec = lookup_attribute (G_FILE_ATTRIBUTE_TIME_CREATED_NSEC);
}
value = g_file_info_create_value (info, attr_ctime);
if (value)
_g_file_attribute_value_set_uint64 (value, g_date_time_to_unix (creation_time));
value = g_file_info_create_value (info, attr_ctime_usec);
if (value)
_g_file_attribute_value_set_uint32 (value, g_date_time_get_microsecond (creation_time));
/* nsecs cant be known from a #GDateTime, so remove them */
g_file_info_remove_value (info, attr_ctime_nsec);
}
/**
* g_file_info_set_symlink_target:
* @info: a #GFileInfo.
* @symlink_target: (type filename): a static string containing a path to a symlink target.
*
* Sets the %G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET attribute in the file info
* to the given symlink target.
**/
void
g_file_info_set_symlink_target (GFileInfo *info,
const char *symlink_target)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
g_return_if_fail (symlink_target != NULL);
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_byte_string (value, symlink_target);
}
/**
* g_file_info_set_sort_order:
* @info: a #GFileInfo.
* @sort_order: a sort order integer.
*
* Sets the sort order attribute in the file info structure. See
* %G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER.
**/
void
g_file_info_set_sort_order (GFileInfo *info,
gint32 sort_order)
{
static guint32 attr = 0;
GFileAttributeValue *value;
g_return_if_fail (G_IS_FILE_INFO (info));
if (attr == 0)
attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
value = g_file_info_create_value (info, attr);
if (value)
_g_file_attribute_value_set_int32 (value, sort_order);
}
typedef struct {
guint32 id;
guint32 mask;
} SubMatcher;
struct _GFileAttributeMatcher {
gboolean all;
gint ref;
GArray *sub_matchers;
/* Iterator */
guint32 iterator_ns;
gint iterator_pos;
};
G_DEFINE_BOXED_TYPE (GFileAttributeMatcher, g_file_attribute_matcher,
g_file_attribute_matcher_ref,
g_file_attribute_matcher_unref)
static gint
compare_sub_matchers (gconstpointer a,
gconstpointer b)
{
const SubMatcher *suba = a;
const SubMatcher *subb = b;
int diff;
diff = suba->id - subb->id;
if (diff)
return diff;
return suba->mask - subb->mask;
}
static gboolean
sub_matcher_matches (SubMatcher *matcher,
SubMatcher *submatcher)
{
if ((matcher->mask & submatcher->mask) != matcher->mask)
return FALSE;
return matcher->id == (submatcher->id & matcher->mask);
}
/* Call this function after modifying a matcher.
* It will ensure all the invariants other functions rely on.
*/
static GFileAttributeMatcher *
matcher_optimize (GFileAttributeMatcher *matcher)
{
SubMatcher *submatcher, *compare;
guint i, j;
/* remove sub_matchers if we match everything anyway */
if (matcher->all)
{
if (matcher->sub_matchers)
{
g_array_free (matcher->sub_matchers, TRUE);
matcher->sub_matchers = NULL;
}
return matcher;
}
if (matcher->sub_matchers->len == 0)
{
g_file_attribute_matcher_unref (matcher);
return NULL;
}
/* sort sub_matchers by id (and then mask), so we can bsearch
* and compare matchers in O(N) instead of O(N²) */
g_array_sort (matcher->sub_matchers, compare_sub_matchers);
/* remove duplicates and specific matches when we match the whole namespace */
j = 0;
compare = &g_array_index (matcher->sub_matchers, SubMatcher, j);
for (i = 1; i < matcher->sub_matchers->len; i++)
{
submatcher = &g_array_index (matcher->sub_matchers, SubMatcher, i);
if (sub_matcher_matches (compare, submatcher))
continue;
j++;
compare++;
if (j < i)
*compare = *submatcher;
}
g_array_set_size (matcher->sub_matchers, j + 1);
return matcher;
}
/**
* g_file_attribute_matcher_new:
* @attributes: an attribute string to match.
*
* Creates a new file attribute matcher, which matches attributes
* against a given string. #GFileAttributeMatchers are reference
* counted structures, and are created with a reference count of 1. If
* the number of references falls to 0, the #GFileAttributeMatcher is
* automatically destroyed.
*
* The @attributes string should be formatted with specific keys separated
* from namespaces with a double colon. Several "namespace::key" strings may be
* concatenated with a single comma (e.g. "standard::type,standard::is-hidden").
* The wildcard "*" may be used to match all keys and namespaces, or
* "namespace::*" will match all keys in a given namespace.
*
* ## Examples of file attribute matcher strings and results
*
* - `"*"`: matches all attributes.
* - `"standard::is-hidden"`: matches only the key is-hidden in the
* standard namespace.
* - `"standard::type,unix::*"`: matches the type key in the standard
* namespace and all keys in the unix namespace.
*
* Returns: a #GFileAttributeMatcher
*/
GFileAttributeMatcher *
g_file_attribute_matcher_new (const char *attributes)
{
char **split;
char *colon;
int i;
GFileAttributeMatcher *matcher;
if (attributes == NULL || *attributes == '\0')
return NULL;
matcher = g_malloc0 (sizeof (GFileAttributeMatcher));
matcher->ref = 1;
matcher->sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
split = g_strsplit (attributes, ",", -1);
for (i = 0; split[i] != NULL; i++)
{
if (strcmp (split[i], "*") == 0)
matcher->all = TRUE;
else
{
SubMatcher s;
colon = strstr (split[i], "::");
if (colon != NULL &&
!(colon[2] == 0 ||
(colon[2] == '*' &&
colon[3] == 0)))
{
s.id = lookup_attribute (split[i]);
s.mask = 0xffffffff;
}
else
{
if (colon)
*colon = 0;
s.id = lookup_namespace (split[i]) << NS_POS;
s.mask = NS_MASK << NS_POS;
}
g_array_append_val (matcher->sub_matchers, s);
}
}
g_strfreev (split);
matcher = matcher_optimize (matcher);
return matcher;
}
/**
* g_file_attribute_matcher_subtract:
* @matcher: (nullable): Matcher to subtract from
* @subtract: (nullable): The matcher to subtract
*
* Subtracts all attributes of @subtract from @matcher and returns
* a matcher that supports those attributes.
*
* Note that currently it is not possible to remove a single
* attribute when the @matcher matches the whole namespace - or remove
* a namespace or attribute when the matcher matches everything. This
* is a limitation of the current implementation, but may be fixed
* in the future.
*
* Returns: (nullable): A file attribute matcher matching all attributes of
* @matcher that are not matched by @subtract
**/
GFileAttributeMatcher *
g_file_attribute_matcher_subtract (GFileAttributeMatcher *matcher,
GFileAttributeMatcher *subtract)
{
GFileAttributeMatcher *result;
guint mi, si;
SubMatcher *msub, *ssub;
if (matcher == NULL)
return NULL;
if (subtract == NULL)
return g_file_attribute_matcher_ref (matcher);
if (subtract->all)
return NULL;
if (matcher->all)
return g_file_attribute_matcher_ref (matcher);
result = g_malloc0 (sizeof (GFileAttributeMatcher));
result->ref = 1;
result->sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher));
si = 0;
g_assert (subtract->sub_matchers->len > 0);
ssub = &g_array_index (subtract->sub_matchers, SubMatcher, si);
for (mi = 0; mi < matcher->sub_matchers->len; mi++)
{
msub = &g_array_index (matcher->sub_matchers, SubMatcher, mi);
retry:
if (sub_matcher_matches (ssub, msub))
continue;
si++;
if (si >= subtract->sub_matchers->len)
break;
ssub = &g_array_index (subtract->sub_matchers, SubMatcher, si);
if (ssub->id <= msub->id)
goto retry;
g_array_append_val (result->sub_matchers, *msub);
}
if (mi < matcher->sub_matchers->len)
g_array_append_vals (result->sub_matchers,
&g_array_index (matcher->sub_matchers, SubMatcher, mi),
matcher->sub_matchers->len - mi);
result = matcher_optimize (result);
return result;
}
/**
* g_file_attribute_matcher_ref:
* @matcher: a #GFileAttributeMatcher.
*
* References a file attribute matcher.
*
* Returns: a #GFileAttributeMatcher.
**/
GFileAttributeMatcher *
g_file_attribute_matcher_ref (GFileAttributeMatcher *matcher)
{
if (matcher)
{
g_return_val_if_fail (matcher->ref > 0, NULL);
g_atomic_int_inc (&matcher->ref);
}
return matcher;
}
/**
* g_file_attribute_matcher_unref:
* @matcher: a #GFileAttributeMatcher.
*
* Unreferences @matcher. If the reference count falls below 1,
* the @matcher is automatically freed.
*
**/
void
g_file_attribute_matcher_unref (GFileAttributeMatcher *matcher)
{
if (matcher)
{
g_return_if_fail (matcher->ref > 0);
if (g_atomic_int_dec_and_test (&matcher->ref))
{
if (matcher->sub_matchers)
g_array_free (matcher->sub_matchers, TRUE);
g_free (matcher);
}
}
}
/**
* g_file_attribute_matcher_matches_only:
* @matcher: a #GFileAttributeMatcher.
* @attribute: a file attribute key.
*
* Checks if an attribute matcher only matches a given attribute. Always
* returns %FALSE if "*" was used when creating the matcher.
*
* Returns: %TRUE if the matcher only matches @attribute. %FALSE otherwise.
**/
gboolean
g_file_attribute_matcher_matches_only (GFileAttributeMatcher *matcher,
const char *attribute)
{
SubMatcher *sub_matcher;
guint32 id;
g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
if (matcher == NULL ||
matcher->all)
return FALSE;
if (matcher->sub_matchers->len != 1)
return FALSE;
id = lookup_attribute (attribute);
sub_matcher = &g_array_index (matcher->sub_matchers, SubMatcher, 0);
return sub_matcher->id == id &&
sub_matcher->mask == 0xffffffff;
}
static gboolean
matcher_matches_id (GFileAttributeMatcher *matcher,
guint32 id)
{
SubMatcher *sub_matchers;
guint i;
if (matcher->sub_matchers)
{
sub_matchers = (SubMatcher *)matcher->sub_matchers->data;
for (i = 0; i < matcher->sub_matchers->len; i++)
{
if (sub_matchers[i].id == (id & sub_matchers[i].mask))
return TRUE;
}
}
return FALSE;
}
gboolean
_g_file_attribute_matcher_matches_id (GFileAttributeMatcher *matcher,
guint32 id)
{
/* We return a NULL matcher for an empty match string, so handle this */
if (matcher == NULL)
return FALSE;
if (matcher->all)
return TRUE;
return matcher_matches_id (matcher, id);
}
/**
* g_file_attribute_matcher_matches:
* @matcher: a #GFileAttributeMatcher.
* @attribute: a file attribute key.
*
* Checks if an attribute will be matched by an attribute matcher. If
* the matcher was created with the "*" matching string, this function
* will always return %TRUE.
*
* Returns: %TRUE if @attribute matches @matcher. %FALSE otherwise.
**/
gboolean
g_file_attribute_matcher_matches (GFileAttributeMatcher *matcher,
const char *attribute)
{
g_return_val_if_fail (attribute != NULL && *attribute != '\0', FALSE);
/* We return a NULL matcher for an empty match string, so handle this */
if (matcher == NULL)
return FALSE;
if (matcher->all)
return TRUE;
return matcher_matches_id (matcher, lookup_attribute (attribute));
}
/* return TRUE -> all */
/**
* g_file_attribute_matcher_enumerate_namespace:
* @matcher: a #GFileAttributeMatcher.
* @ns: a string containing a file attribute namespace.
*
* Checks if the matcher will match all of the keys in a given namespace.
* This will always return %TRUE if a wildcard character is in use (e.g. if
* matcher was created with "standard::*" and @ns is "standard", or if matcher was created
* using "*" and namespace is anything.)
*
* TODO: this is awkwardly worded.
*
* Returns: %TRUE if the matcher matches all of the entries
* in the given @ns, %FALSE otherwise.
**/
gboolean
g_file_attribute_matcher_enumerate_namespace (GFileAttributeMatcher *matcher,
const char *ns)
{
SubMatcher *sub_matchers;
guint ns_id;
guint i;
g_return_val_if_fail (ns != NULL && *ns != '\0', FALSE);
/* We return a NULL matcher for an empty match string, so handle this */
if (matcher == NULL)
return FALSE;
if (matcher->all)
return TRUE;
ns_id = lookup_namespace (ns) << NS_POS;
if (matcher->sub_matchers)
{
sub_matchers = (SubMatcher *)matcher->sub_matchers->data;
for (i = 0; i < matcher->sub_matchers->len; i++)
{
if (sub_matchers[i].id == ns_id)
return TRUE;
}
}
matcher->iterator_ns = ns_id;
matcher->iterator_pos = 0;
return FALSE;
}
/**
* g_file_attribute_matcher_enumerate_next:
* @matcher: a #GFileAttributeMatcher.
*
* Gets the next matched attribute from a #GFileAttributeMatcher.
*
* Returns: (nullable): a string containing the next attribute or, %NULL if
* no more attribute exist.
**/
const char *
g_file_attribute_matcher_enumerate_next (GFileAttributeMatcher *matcher)
{
guint i;
SubMatcher *sub_matcher;
/* We return a NULL matcher for an empty match string, so handle this */
if (matcher == NULL)
return NULL;
while (1)
{
i = matcher->iterator_pos++;
if (matcher->sub_matchers == NULL)
return NULL;
if (i < matcher->sub_matchers->len)
sub_matcher = &g_array_index (matcher->sub_matchers, SubMatcher, i);
else
return NULL;
if (sub_matcher->mask == 0xffffffff &&
(sub_matcher->id & (NS_MASK << NS_POS)) == matcher->iterator_ns)
return get_attribute_for_id (sub_matcher->id);
}
}
/**
* g_file_attribute_matcher_to_string:
* @matcher: (nullable): a #GFileAttributeMatcher.
*
* Prints what the matcher is matching against. The format will be
* equal to the format passed to g_file_attribute_matcher_new().
* The output however, might not be identical, as the matcher may
* decide to use a different order or omit needless parts.
*
* Returns: a string describing the attributes the matcher matches
* against or %NULL if @matcher was %NULL.
*
* Since: 2.32
**/
char *
g_file_attribute_matcher_to_string (GFileAttributeMatcher *matcher)
{
GString *string;
guint i;
if (matcher == NULL)
return NULL;
if (matcher->all)
return g_strdup ("*");
string = g_string_new ("");
for (i = 0; i < matcher->sub_matchers->len; i++)
{
SubMatcher *submatcher = &g_array_index (matcher->sub_matchers, SubMatcher, i);
if (i > 0)
g_string_append_c (string, ',');
g_string_append (string, get_attribute_for_id (submatcher->id));
}
return g_string_free (string, FALSE);
}