gvfs/common/gvfsdaemonprotocol.c

396 lines
10 KiB
C
Raw Permalink Normal View History

2022-06-29 16:07:13 +08:00
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* 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 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, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
#include <config.h>
#include <glib-object.h>
#include <glib/gi18n-lib.h>
#include <gvfsdaemonprotocol.h>
#include <gio/gio.h>
static const char *
get_object_signature (GObject *obj)
{
if (G_IS_ICON (obj))
return "(us)";
return "(u)";
}
static GVariant *
append_object (GObject *obj)
{
GVariant *var;
/* version 1 and 2 are deprecated old themed-icon and file-icon values */
if (G_IS_ICON (obj))
{
char *data;
data = g_icon_to_string (G_ICON (obj));
var = g_variant_new ("(us)", 3, data);
g_free (data);
}
else
{
/* NULL or unknown type: */
if (obj != NULL)
g_warning ("Unknown attribute object type, ignoring");
var = g_variant_new ("(u)", 0);
}
return var;
}
void
_g_dbus_attribute_value_destroy (GFileAttributeType type,
GDBusAttributeValue *value)
{
switch (type) {
case G_FILE_ATTRIBUTE_TYPE_STRING:
case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
g_free (value->ptr);
break;
case G_FILE_ATTRIBUTE_TYPE_STRINGV:
g_strfreev (value->ptr);
break;
case G_FILE_ATTRIBUTE_TYPE_OBJECT:
if (value->ptr)
g_object_unref (value->ptr);
break;
default:
break;
}
}
gpointer
_g_dbus_attribute_as_pointer (GFileAttributeType type,
GDBusAttributeValue *value)
{
switch (type) {
case G_FILE_ATTRIBUTE_TYPE_STRING:
case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
case G_FILE_ATTRIBUTE_TYPE_OBJECT:
case G_FILE_ATTRIBUTE_TYPE_STRINGV:
return value->ptr;
default:
return (gpointer) value;
}
}
static const char *
_g_dbus_type_from_file_attribute_type (GFileAttributeType type)
{
const char *dbus_type;
switch (type)
{
case G_FILE_ATTRIBUTE_TYPE_STRING:
dbus_type = "s";
break;
case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
dbus_type = "ay";
break;
case G_FILE_ATTRIBUTE_TYPE_STRINGV:
dbus_type = "as";
break;
case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
dbus_type = "b";
break;
case G_FILE_ATTRIBUTE_TYPE_UINT32:
dbus_type = "u";
break;
case G_FILE_ATTRIBUTE_TYPE_INT32:
dbus_type = "i";
break;
case G_FILE_ATTRIBUTE_TYPE_UINT64:
dbus_type = "t";
break;
case G_FILE_ATTRIBUTE_TYPE_INT64:
dbus_type = "x";
break;
case G_FILE_ATTRIBUTE_TYPE_OBJECT:
dbus_type = "r";
break;
case G_FILE_ATTRIBUTE_TYPE_INVALID:
dbus_type = "ay";
break;
default:
dbus_type = NULL;
g_warning ("Invalid attribute type %u, ignoring\n", type);
break;
}
return dbus_type;
}
GVariant *
_g_dbus_append_file_attribute (const char *attribute,
GFileAttributeStatus status,
GFileAttributeType type,
gpointer value_p)
{
const char *dbus_type;
GVariant *v;
dbus_type = _g_dbus_type_from_file_attribute_type (type);
if (g_variant_type_equal (G_VARIANT_TYPE (dbus_type), G_VARIANT_TYPE_TUPLE))
dbus_type = get_object_signature ((GObject *)value_p);
if (g_variant_type_is_tuple (G_VARIANT_TYPE (dbus_type)))
v = append_object ((GObject *)value_p);
else if (g_variant_type_is_array (G_VARIANT_TYPE (dbus_type)))
{
char *s;
s = g_strdup_printf ("^%s", dbus_type);
v = g_variant_new (s, value_p);
g_free (s);
}
else if (g_variant_type_equal (G_VARIANT_TYPE (dbus_type), G_VARIANT_TYPE_UINT32))
v = g_variant_new (dbus_type, *(guint32 *)value_p);
else if (g_variant_type_equal (G_VARIANT_TYPE (dbus_type), G_VARIANT_TYPE_INT32))
v = g_variant_new (dbus_type, *(gint32 *)value_p);
else if (g_variant_type_equal (G_VARIANT_TYPE (dbus_type), G_VARIANT_TYPE_UINT64))
v = g_variant_new (dbus_type, *(guint64 *)value_p);
else if (g_variant_type_equal (G_VARIANT_TYPE (dbus_type), G_VARIANT_TYPE_INT64))
v = g_variant_new (dbus_type, *(gint64 *)value_p);
else if (g_variant_type_equal (G_VARIANT_TYPE (dbus_type), G_VARIANT_TYPE_BOOLEAN))
v = g_variant_new (dbus_type, *(gboolean *)value_p);
else
v = g_variant_new (dbus_type, value_p);
return g_variant_new ("(suv)",
attribute,
status,
v);
}
GVariant *
_g_dbus_append_file_info (GFileInfo *info)
{
GVariantBuilder builder;
char **attributes;
int i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(suv)"));
attributes = g_file_info_list_attributes (info, NULL);
for (i = 0; attributes[i] != NULL; i++)
{
GFileAttributeType type;
GFileAttributeStatus status;
gpointer value_p;
if (g_file_info_get_attribute_data (info, attributes[i], &type, &value_p, &status))
g_variant_builder_add_value (&builder,
_g_dbus_append_file_attribute (attributes[i], status, type, value_p));
}
g_strfreev (attributes);
return g_variant_builder_end (&builder);
}
gboolean
_g_dbus_get_file_attribute (GVariant *value,
gchar **attribute,
GFileAttributeStatus *status,
GFileAttributeType *type,
GDBusAttributeValue *attr_value)
{
gboolean res;
char *str;
guint32 obj_type;
GObject *obj;
GVariant *v;
g_variant_get (value, "(suv)",
attribute,
status,
&v);
res = TRUE;
if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
{
*type = G_FILE_ATTRIBUTE_TYPE_STRING;
g_variant_get (v, "s", &attr_value->ptr);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_BYTESTRING))
{
*type = G_FILE_ATTRIBUTE_TYPE_BYTE_STRING;
g_variant_get (v, "^ay", &attr_value->ptr);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING_ARRAY))
{
*type = G_FILE_ATTRIBUTE_TYPE_STRINGV;
g_variant_get (v, "^as", &attr_value->ptr);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_BYTE))
{
*type = G_FILE_ATTRIBUTE_TYPE_INVALID;
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN))
{
*type = G_FILE_ATTRIBUTE_TYPE_BOOLEAN;
g_variant_get (v, "b", &attr_value->boolean);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32))
{
*type = G_FILE_ATTRIBUTE_TYPE_UINT32;
g_variant_get (v, "u", &attr_value->uint32);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT32))
{
*type = G_FILE_ATTRIBUTE_TYPE_INT32;
g_variant_get (v, "i", &attr_value->ptr);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT64))
{
*type = G_FILE_ATTRIBUTE_TYPE_UINT64;
g_variant_get (v, "t", &attr_value->uint64);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE_INT64))
{
*type = G_FILE_ATTRIBUTE_TYPE_INT64;
g_variant_get (v, "x", &attr_value->ptr);
}
else if (g_variant_is_container (v))
{
*type = G_FILE_ATTRIBUTE_TYPE_OBJECT;
obj_type = G_MAXUINT32; /* treat it as an error if not set below */
str = NULL;
if (g_variant_is_of_type (v, G_VARIANT_TYPE ("(u)")))
{
g_variant_get (v, "(u)", &obj_type);
}
else if (g_variant_is_of_type (v, G_VARIANT_TYPE ("(us)")))
{
g_variant_get (v, "(u&s)", &obj_type, &str);
}
obj = NULL;
/* obj_type 1 and 2 are deprecated and treated as errors */
if (obj_type == 3)
{
if (str != NULL)
{
/* serialized G_ICON */
obj = (GObject *)g_icon_new_for_string (str, NULL);
}
else
{
g_warning ("Malformed object data in file attribute");
}
}
else
{
/* NULL (or unsupported) */
if (obj_type != 0)
g_warning ("Unsupported object type in file attribute");
}
attr_value->ptr = obj;
}
else
res = FALSE;
g_variant_unref (v);
return res;
}
GFileInfo *
_g_dbus_get_file_info (GVariant *value,
GError **error)
{
GFileInfo *info;
gchar *attribute;
GFileAttributeType type;
GFileAttributeStatus status;
GDBusAttributeValue attr_value;
GVariantIter iter;
GVariant *child;
info = g_file_info_new ();
g_variant_iter_init (&iter, value);
while ((child = g_variant_iter_next_value (&iter)))
{
if (!_g_dbus_get_file_attribute (child, &attribute, &status, &type, &attr_value))
goto error;
g_file_info_set_attribute (info, attribute, type, _g_dbus_attribute_as_pointer (type, &attr_value));
if (status)
g_file_info_set_attribute_status (info, attribute, status);
g_free (attribute);
_g_dbus_attribute_value_destroy (type, &attr_value);
g_variant_unref (child);
}
return info;
error:
g_object_unref (info);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Invalid file info format"));
return NULL;
}
GFileAttributeInfoList *
_g_dbus_get_attribute_info_list (GVariant *value,
GError **error)
{
GFileAttributeInfoList *list;
GVariantIter iter;
const char *name;
guint32 type, flags;
list = g_file_attribute_info_list_new ();
g_variant_iter_init (&iter, value);
while (g_variant_iter_next (&iter, "(&suu)", &name, &type, &flags))
g_file_attribute_info_list_add (list, name, type, flags);
return list;
}
GVariant *
_g_dbus_append_attribute_info_list (GFileAttributeInfoList *list)
{
GVariantBuilder builder;
int i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(suu)"));
for (i = 0; i < list->n_infos; i++)
g_variant_builder_add (&builder, "(suu)",
list->infos[i].name,
list->infos[i].type,
list->infos[i].flags);
return g_variant_builder_end (&builder);
}