X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgfileinfo.c;h=0cbf988a4fb99ad840f1dfbad214b329b9d45614;hb=fd643b87ab7bc232274c5cd6f9c175d5f6f9ecb9;hp=579148dccf21f8be404b5eacec4ab855a5d01982;hpb=3e4f3673d8a54b3e1924d00a4a3a6048426f0b10;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gfileinfo.c b/gio/gfileinfo.c index 579148d..0cbf988 100644 --- a/gio/gfileinfo.c +++ b/gio/gfileinfo.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: Alexander Larsson */ @@ -24,14 +22,14 @@ * SECTION:gfileinfo * @short_description: File Information and Attributes * @include: gio/gio.h - * @see_also: #GFile, GFileAttribute + * @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 for more - * information on how GIO handles file 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 @@ -132,7 +130,8 @@ _lookup_namespace (const char *namespace) ns_info->id = ++namespace_id_counter; g_hash_table_insert (ns_hash, g_strdup (namespace), ns_info); attributes = g_realloc (attributes, (ns_info->id + 1) * sizeof (char **)); - attributes[ns_info->id] = NULL; + attributes[ns_info->id] = g_new (char *, 1); + attributes[ns_info->id][0] = g_strconcat (namespace, "::*", NULL); } return ns_info; } @@ -203,6 +202,7 @@ ensure_attribute_hash (void) REGISTER_ATTRIBUTE (STANDARD_SYMLINK_TARGET); REGISTER_ATTRIBUTE (STANDARD_TARGET_URI); REGISTER_ATTRIBUTE (STANDARD_SORT_ORDER); + REGISTER_ATTRIBUTE (STANDARD_SYMBOLIC_ICON); REGISTER_ATTRIBUTE (ETAG_VALUE); REGISTER_ATTRIBUTE (ID_FILE); REGISTER_ATTRIBUTE (ID_FILESYSTEM); @@ -249,6 +249,7 @@ ensure_attribute_hash (void) REGISTER_ATTRIBUTE (OWNER_GROUP); REGISTER_ATTRIBUTE (THUMBNAIL_PATH); REGISTER_ATTRIBUTE (THUMBNAILING_FAILED); + REGISTER_ATTRIBUTE (THUMBNAIL_IS_VALID); REGISTER_ATTRIBUTE (PREVIEW_ICON); REGISTER_ATTRIBUTE (FILESYSTEM_SIZE); REGISTER_ATTRIBUTE (FILESYSTEM_FREE); @@ -363,7 +364,8 @@ g_file_info_new (void) * @src_info: source to copy attributes from. * @dest_info: destination to copy attributes to. * - * Copies all of the #GFileAttributes from @src_info to @dest_info. + * Copies all of the [GFileAttribute][gio-GFileAttribute] + * from @src_info to @dest_info. **/ void g_file_info_copy_into (GFileInfo *src_info, @@ -617,9 +619,9 @@ g_file_info_has_namespace (GFileInfo *info, * * Lists the file info structure's attributes. * - * Returns: (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. + * 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, @@ -1107,7 +1109,8 @@ _g_file_info_set_attribute_by_id (GFileInfo *info, * @type: a #GFileAttributeType * @value_p: pointer to the value * - * Sets the @attribute to contain the given value, if possible. + * Sets the @attribute to contain the given value, if possible. To unset the + * attribute, use %G_ATTRIBUTE_TYPE_INVALID for @type. **/ void g_file_info_set_attribute (GFileInfo *info, @@ -1172,7 +1175,7 @@ _g_file_info_set_attribute_stringv_by_id (GFileInfo *info, * g_file_info_set_attribute_stringv: * @info: a #GFileInfo. * @attribute: a file attribute key - * @attr_value: a %NULL terminated array of UTF-8 strings. + * @attr_value: (array) (element-type utf8): a %NULL terminated array of UTF-8 strings. * * Sets the @attribute to contain the given @attr_value, * if possible. @@ -1436,6 +1439,42 @@ g_file_info_set_attribute_int64 (GFileInfo *info, /* Helper getters */ /** + * 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: 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; + GTimeVal tv; + + 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; + + if (g_time_val_from_iso8601 (date_str, &tv) == FALSE) + return NULL; + + return g_date_time_new_from_timeval_local (&tv); +} + +/** * g_file_info_get_file_type: * @info: a #GFileInfo. * @@ -1625,6 +1664,35 @@ g_file_info_get_icon (GFileInfo *info) } /** + * g_file_info_get_symbolic_icon: + * @info: a #GFileInfo. + * + * Gets the symbolic icon for a file. + * + * Returns: (transfer none): #GIcon for the given @info. + * + * Since: 2.34 + **/ +GIcon * +g_file_info_get_symbolic_icon (GFileInfo *info) +{ + static guint32 attr = 0; + GFileAttributeValue *value; + GObject *obj; + + g_return_val_if_fail (G_IS_FILE_INFO (info), NULL); + + if (attr == 0) + attr = lookup_attribute (G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON); + + value = g_file_info_find_value (info, attr); + 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. * @@ -1673,7 +1741,7 @@ g_file_info_get_size (GFileInfo *info) /** * g_file_info_get_modification_time: * @info: a #GFileInfo. - * @result: a #GTimeVal. + * @result: (out caller-allocates): a #GTimeVal. * * Gets the modification time of the current @info and sets it * in @result. @@ -1727,7 +1795,7 @@ g_file_info_get_symlink_target (GFileInfo *info) * g_file_info_get_etag: * @info: a #GFileInfo. * - * Gets the entity tag for a given + * Gets the [entity tag][gfile-etag] for a given * #GFileInfo. See %G_FILE_ATTRIBUTE_ETAG_VALUE. * * Returns: a string containing the value of the "etag:value" attribute. @@ -1802,7 +1870,7 @@ g_file_info_set_file_type (GFileInfo *info, * @info: a #GFileInfo. * @is_hidden: a #gboolean. * - * Sets the "is_hidden" attribute in a #GFileInfo according to @is_symlink. + * Sets the "is_hidden" attribute in a #GFileInfo according to @is_hidden. * See %G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN. **/ void @@ -1952,9 +2020,37 @@ g_file_info_set_icon (GFileInfo *info, } /** + * 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. + * @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. @@ -2003,7 +2099,7 @@ g_file_info_set_size (GFileInfo *info, } /** - * g_file_info_set_modification_time + * g_file_info_set_modification_time: * @info: a #GFileInfo. * @mtime: a #GTimeVal. * @@ -2086,8 +2182,6 @@ g_file_info_set_sort_order (GFileInfo *info, } -#define ON_STACK_MATCHERS 5 - typedef struct { guint32 id; guint32 mask; @@ -2095,69 +2189,103 @@ typedef struct { struct _GFileAttributeMatcher { gboolean all; - SubMatcher sub_matchers[ON_STACK_MATCHERS]; gint ref; - GArray *more_sub_matchers; + GArray *sub_matchers; /* Interator */ guint32 iterator_ns; gint iterator_pos; }; -static void -matcher_add (GFileAttributeMatcher *matcher, - guint id, - guint mask) +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) { - SubMatcher *sub_matchers; - int i; - SubMatcher s; + 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; - for (i = 0; i < ON_STACK_MATCHERS; i++) + /* remove sub_matchers if we match everything anyway */ + if (matcher->all) { - /* First empty spot, not found, use this */ - if (matcher->sub_matchers[i].id == 0) - { - matcher->sub_matchers[i].id = id; - matcher->sub_matchers[i].mask = mask; - return; - } + if (matcher->sub_matchers) + { + g_array_free (matcher->sub_matchers, TRUE); + matcher->sub_matchers = NULL; + } + return matcher; + } - /* Already added */ - if (matcher->sub_matchers[i].id == id && - matcher->sub_matchers[i].mask == mask) - return; + if (matcher->sub_matchers->len == 0) + { + g_file_attribute_matcher_unref (matcher); + return NULL; } - if (matcher->more_sub_matchers == NULL) - matcher->more_sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher)); + /* 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); - sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data; - for (i = 0; i < matcher->more_sub_matchers->len; i++) + for (i = 1; i < matcher->sub_matchers->len; i++) { - /* Already added */ - if (sub_matchers[i].id == id && - sub_matchers[i].mask == mask) - return; + submatcher = &g_array_index (matcher->sub_matchers, SubMatcher, i); + if (sub_matcher_matches (compare, submatcher)) + continue; + + j++; + compare++; + + if (j < i) + *compare = *submatcher; } - s.id = id; - s.mask = mask; + g_array_set_size (matcher->sub_matchers, j + 1); - g_array_append_val (matcher->more_sub_matchers, s); + return matcher; } -G_DEFINE_BOXED_TYPE (GFileAttributeMatcher, g_file_attribute_matcher, - g_file_attribute_matcher_ref, - g_file_attribute_matcher_unref) - /** * 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 + * 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. @@ -2168,21 +2296,16 @@ G_DEFINE_BOXED_TYPE (GFileAttributeMatcher, g_file_attribute_matcher, * The wildcard "*" may be used to match all keys and namespaces, or * "namespace::*" will match all keys in a given namespace. * - * Examples of strings to use: - * - * File Attribute Matcher strings and results - * - * Matcher String Matches - * - * "*"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. - * - *
+ * ## Examples of file attribute matcher strings and results * - * Returns: a #GFileAttributeMatcher. - **/ + * - `"*"`: 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) { @@ -2196,6 +2319,7 @@ g_file_attribute_matcher_new (const char *attributes) matcher = g_malloc0 (sizeof (GFileAttributeMatcher)); matcher->ref = 1; + matcher->sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher)); split = g_strsplit (attributes, ",", -1); @@ -2205,7 +2329,7 @@ g_file_attribute_matcher_new (const char *attributes) matcher->all = TRUE; else { - guint32 id, mask; + SubMatcher s; colon = strstr (split[i], "::"); if (colon != NULL && @@ -2213,28 +2337,101 @@ g_file_attribute_matcher_new (const char *attributes) (colon[2] == '*' && colon[3] == 0))) { - id = lookup_attribute (split[i]); - mask = 0xffffffff; + s.id = lookup_attribute (split[i]); + s.mask = 0xffffffff; } else { if (colon) *colon = 0; - id = lookup_namespace (split[i]) << NS_POS; - mask = NS_MASK << NS_POS; + s.id = lookup_namespace (split[i]) << NS_POS; + s.mask = NS_MASK << NS_POS; } - matcher_add (matcher, id, mask); + g_array_append_val (matcher->sub_matchers, s); } } g_strfreev (split); + matcher = matcher_optimize (matcher); + return matcher; } /** + * g_file_attribute_matcher_subtract: + * @matcher: Matcher to subtract from + * @subtract: 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: 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. * @@ -2270,8 +2467,8 @@ g_file_attribute_matcher_unref (GFileAttributeMatcher *matcher) if (g_atomic_int_dec_and_test (&matcher->ref)) { - if (matcher->more_sub_matchers) - g_array_free (matcher->more_sub_matchers, TRUE); + if (matcher->sub_matchers) + g_array_free (matcher->sub_matchers, TRUE); g_free (matcher); } @@ -2292,6 +2489,7 @@ 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); @@ -2300,15 +2498,15 @@ g_file_attribute_matcher_matches_only (GFileAttributeMatcher *matcher, matcher->all) return FALSE; + if (matcher->sub_matchers->len != 1) + return FALSE; + id = lookup_attribute (attribute); - - if (matcher->sub_matchers[0].id != 0 && - matcher->sub_matchers[1].id == 0 && - matcher->sub_matchers[0].mask == 0xffffffff && - matcher->sub_matchers[0].id == id) - return TRUE; - - return FALSE; + + sub_matcher = &g_array_index (matcher->sub_matchers, SubMatcher, 0); + + return sub_matcher->id == id && + sub_matcher->mask == 0xffffffff; } static gboolean @@ -2318,19 +2516,10 @@ matcher_matches_id (GFileAttributeMatcher *matcher, SubMatcher *sub_matchers; int i; - for (i = 0; i < ON_STACK_MATCHERS; i++) + if (matcher->sub_matchers) { - if (matcher->sub_matchers[i].id == 0) - return FALSE; - - if (matcher->sub_matchers[i].id == (id & matcher->sub_matchers[i].mask)) - return TRUE; - } - - if (matcher->more_sub_matchers) - { - sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data; - for (i = 0; i < matcher->more_sub_matchers->len; i++) + 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; @@ -2416,16 +2605,10 @@ g_file_attribute_matcher_enumerate_namespace (GFileAttributeMatcher *matcher, ns_id = lookup_namespace (ns) << NS_POS; - for (i = 0; i < ON_STACK_MATCHERS; i++) - { - if (matcher->sub_matchers[i].id == ns_id) - return TRUE; - } - - if (matcher->more_sub_matchers) + if (matcher->sub_matchers) { - sub_matchers = (SubMatcher *)matcher->more_sub_matchers->data; - for (i = 0; i < matcher->more_sub_matchers->len; i++) + 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; @@ -2461,27 +2644,56 @@ g_file_attribute_matcher_enumerate_next (GFileAttributeMatcher *matcher) { i = matcher->iterator_pos++; - if (i < ON_STACK_MATCHERS) - { - if (matcher->sub_matchers[i].id == 0) - return NULL; + if (matcher->sub_matchers == NULL) + return NULL; - sub_matcher = &matcher->sub_matchers[i]; - } + if (i < matcher->sub_matchers->len) + sub_matcher = &g_array_index (matcher->sub_matchers, SubMatcher, i); else - { - if (matcher->more_sub_matchers == NULL) - return NULL; - - i -= ON_STACK_MATCHERS; - if (i < matcher->more_sub_matchers->len) - sub_matcher = &g_array_index (matcher->more_sub_matchers, SubMatcher, i); - else - return NULL; - } + 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: (allow-none): 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); +}