mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 07:26:15 +01:00
4cad66580b
This partially revertsed8e86a7d4
. The change to add the criticals (commited8e86a7d4
) is correct, but landed too late in the cycle. Let’s downgrade the criticals to debugs for now, to stop applications seeing a lot of new criticals in their output. Those criticals are particularly disruptive for command line applications and unit tests. Early in the next cycle, the debugs will be re-upgraded to criticals. This will give applications a whole additional cycle to fix their ambiguous use of API. It turned out that a lot of applications have latent bugs around calling `g_file_info_get_*()` without checking whether an attribute is set first, and were hence relying on the ‘unknown’ return value also being an appropriate default for them. This was compounded by the fact that several non-local GVFS backends were not setting `GFileInfo` attributes all the time, which caused the ‘missing attribute’ code path to be hit more frequently. For example, they would only call `g_file_info_set_is_hidden()` with a true value and never bother with a false one. It was further compounded by the fact that, while this change landed for the 2.75.4 release, there did not seem to be extensive integration testing of that release, and distributions and downstreams went straight to 2.76.0. That meant we missed the window between 2.75.4 and 2.76.0 to change, fix or revert this behaviour. GLib relies on distros and downstreams doing integration testing of unstable releases. We test with downstream GNOME as part of gnome-build-meta, but do not have the resources to do integration testing for everybody. Signed-off-by: Philip Withnall <pwithnall@endlessos.org> See: #2907 See: #2932 See: #2934 See: #2945 See: #2948
3059 lines
82 KiB
C
3059 lines
82 KiB
C
/* 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 wasn’t 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_debug ("GFileInfo created without " attribute_name); \
|
||
return 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_debug ("GFileInfo created without " G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||
result->tv_sec = result->tv_usec = 0;
|
||
return;
|
||
}
|
||
|
||
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: (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 can’t 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 can’t 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 can’t 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 can’t 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: 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);
|
||
}
|