Blame src/nautilus-keyfile-metadata.c

Packit a189e0
/*
Packit a189e0
 * Nautilus
Packit a189e0
 *
Packit a189e0
 * Copyright (C) 2011 Red Hat, Inc.
Packit a189e0
 *
Packit a189e0
 * Nautilus is free software; you can redistribute it and/or
Packit a189e0
 * modify it under the terms of the GNU General Public License as
Packit a189e0
 * published by the Free Software Foundation; either version 2 of the
Packit a189e0
 * License, or (at your option) any later version.
Packit a189e0
 *
Packit a189e0
 * Nautilus is distributed in the hope that it will be useful,
Packit a189e0
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a189e0
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a189e0
 * General Public License for more details.
Packit a189e0
 *
Packit a189e0
 * You should have received a copy of the GNU General Public
Packit a189e0
 * License along with this program; see the file COPYING.  If not,
Packit a189e0
 * see <http://www.gnu.org/licenses/>.
Packit a189e0
 *
Packit a189e0
 * Authors: Cosimo Cecchi <cosimoc@redhat.com>
Packit a189e0
 */
Packit a189e0
Packit a189e0
#include <config.h>
Packit a189e0
Packit a189e0
#include "nautilus-keyfile-metadata.h"
Packit a189e0
Packit a189e0
#include "nautilus-directory-notify.h"
Packit a189e0
#include "nautilus-file-private.h"
Packit a189e0
#include "nautilus-file-utilities.h"
Packit a189e0
Packit a189e0
#include <glib/gstdio.h>
Packit a189e0
Packit a189e0
#include <sys/types.h>
Packit a189e0
#include <sys/stat.h>
Packit a189e0
#include <fcntl.h>
Packit a189e0
Packit a189e0
typedef struct
Packit a189e0
{
Packit a189e0
    GKeyFile *keyfile;
Packit a189e0
    guint save_in_idle_id;
Packit a189e0
} KeyfileMetadataData;
Packit a189e0
Packit a189e0
static GHashTable *data_hash = NULL;
Packit a189e0
Packit a189e0
static KeyfileMetadataData *
Packit a189e0
keyfile_metadata_data_new (const char *keyfile_filename)
Packit a189e0
{
Packit a189e0
    KeyfileMetadataData *data;
Packit a189e0
    GKeyFile *retval;
Packit a189e0
    GError *error = NULL;
Packit a189e0
Packit a189e0
    retval = g_key_file_new ();
Packit a189e0
Packit a189e0
    g_key_file_load_from_file (retval,
Packit a189e0
                               keyfile_filename,
Packit a189e0
                               G_KEY_FILE_NONE,
Packit a189e0
                               &error);
Packit a189e0
Packit a189e0
    if (error != NULL)
Packit a189e0
    {
Packit a189e0
        if (!g_error_matches (error,
Packit a189e0
                              G_FILE_ERROR,
Packit a189e0
                              G_FILE_ERROR_NOENT))
Packit a189e0
        {
Packit a189e0
            g_print ("Unable to open the desktop metadata keyfile: %s\n",
Packit a189e0
                     error->message);
Packit a189e0
        }
Packit a189e0
Packit a189e0
        g_error_free (error);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    data = g_slice_new0 (KeyfileMetadataData);
Packit a189e0
    data->keyfile = retval;
Packit a189e0
Packit a189e0
    return data;
Packit a189e0
}
Packit a189e0
Packit a189e0
static void
Packit a189e0
keyfile_metadata_data_free (KeyfileMetadataData *data)
Packit a189e0
{
Packit a189e0
    g_key_file_unref (data->keyfile);
Packit a189e0
Packit a189e0
    if (data->save_in_idle_id != 0)
Packit a189e0
    {
Packit a189e0
        g_source_remove (data->save_in_idle_id);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    g_slice_free (KeyfileMetadataData, data);
Packit a189e0
}
Packit a189e0
Packit a189e0
static GKeyFile *
Packit a189e0
get_keyfile (const char *keyfile_filename)
Packit a189e0
{
Packit a189e0
    KeyfileMetadataData *data;
Packit a189e0
Packit a189e0
    if (data_hash == NULL)
Packit a189e0
    {
Packit a189e0
        data_hash = g_hash_table_new_full (g_str_hash,
Packit a189e0
                                           g_str_equal,
Packit a189e0
                                           g_free,
Packit a189e0
                                           (GDestroyNotify) keyfile_metadata_data_free);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    data = g_hash_table_lookup (data_hash, keyfile_filename);
Packit a189e0
Packit a189e0
    if (data == NULL)
Packit a189e0
    {
Packit a189e0
        data = keyfile_metadata_data_new (keyfile_filename);
Packit a189e0
Packit a189e0
        g_hash_table_insert (data_hash,
Packit a189e0
                             g_strdup (keyfile_filename),
Packit a189e0
                             data);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    return data->keyfile;
Packit a189e0
}
Packit a189e0
Packit a189e0
static gboolean
Packit a189e0
save_in_idle_cb (const gchar *keyfile_filename)
Packit a189e0
{
Packit a189e0
    KeyfileMetadataData *data;
Packit a189e0
    gchar *contents;
Packit a189e0
    gsize length;
Packit a189e0
    GError *error = NULL;
Packit a189e0
Packit a189e0
    data = g_hash_table_lookup (data_hash, keyfile_filename);
Packit a189e0
    data->save_in_idle_id = 0;
Packit a189e0
Packit a189e0
    contents = g_key_file_to_data (data->keyfile, &length, NULL);
Packit a189e0
Packit a189e0
    if (contents != NULL)
Packit a189e0
    {
Packit a189e0
        g_file_set_contents (keyfile_filename,
Packit a189e0
                             contents, length,
Packit a189e0
                             &error);
Packit a189e0
        g_free (contents);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    if (error != NULL)
Packit a189e0
    {
Packit a189e0
        g_warning ("Couldn't save the desktop metadata keyfile to disk: %s",
Packit a189e0
                   error->message);
Packit a189e0
        g_error_free (error);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    return FALSE;
Packit a189e0
}
Packit a189e0
Packit a189e0
static void
Packit a189e0
save_in_idle (const char *keyfile_filename)
Packit a189e0
{
Packit a189e0
    KeyfileMetadataData *data;
Packit a189e0
Packit a189e0
    g_return_if_fail (data_hash != NULL);
Packit a189e0
Packit a189e0
    data = g_hash_table_lookup (data_hash, keyfile_filename);
Packit a189e0
    g_return_if_fail (data != NULL);
Packit a189e0
Packit a189e0
    if (data->save_in_idle_id != 0)
Packit a189e0
    {
Packit a189e0
        return;
Packit a189e0
    }
Packit a189e0
Packit a189e0
    data->save_in_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
Packit a189e0
                                             (GSourceFunc) save_in_idle_cb,
Packit a189e0
                                             g_strdup (keyfile_filename),
Packit a189e0
                                             g_free);
Packit a189e0
}
Packit a189e0
Packit a189e0
void
Packit a189e0
nautilus_keyfile_metadata_set_string (NautilusFile *file,
Packit a189e0
                                      const char   *keyfile_filename,
Packit a189e0
                                      const gchar  *name,
Packit a189e0
                                      const gchar  *key,
Packit a189e0
                                      const gchar  *string)
Packit a189e0
{
Packit a189e0
    GKeyFile *keyfile;
Packit a189e0
Packit a189e0
    keyfile = get_keyfile (keyfile_filename);
Packit a189e0
Packit a189e0
    g_key_file_set_string (keyfile,
Packit a189e0
                           name,
Packit a189e0
                           key,
Packit a189e0
                           string);
Packit a189e0
Packit a189e0
    save_in_idle (keyfile_filename);
Packit a189e0
Packit a189e0
    if (nautilus_keyfile_metadata_update_from_keyfile (file, keyfile_filename, name))
Packit a189e0
    {
Packit a189e0
        nautilus_file_changed (file);
Packit a189e0
    }
Packit a189e0
}
Packit a189e0
Packit a189e0
#define STRV_TERMINATOR "@x-nautilus-desktop-metadata-term@"
Packit a189e0
Packit a189e0
void
Packit a189e0
nautilus_keyfile_metadata_set_stringv (NautilusFile       *file,
Packit a189e0
                                       const char         *keyfile_filename,
Packit a189e0
                                       const char         *name,
Packit a189e0
                                       const char         *key,
Packit a189e0
                                       const char * const *stringv)
Packit a189e0
{
Packit a189e0
    GKeyFile *keyfile;
Packit a189e0
    guint length;
Packit a189e0
    gchar **actual_stringv = NULL;
Packit a189e0
    gboolean free_strv = FALSE;
Packit a189e0
Packit a189e0
    keyfile = get_keyfile (keyfile_filename);
Packit a189e0
Packit a189e0
    /* if we would be setting a single-length strv, append a fake
Packit a189e0
     * terminator to the array, to be able to differentiate it later from
Packit a189e0
     * the single string case
Packit a189e0
     */
Packit a189e0
    length = g_strv_length ((gchar **) stringv);
Packit a189e0
Packit a189e0
    if (length == 1)
Packit a189e0
    {
Packit a189e0
        actual_stringv = g_malloc0 (3 * sizeof (gchar *));
Packit a189e0
        actual_stringv[0] = (gchar *) stringv[0];
Packit a189e0
        actual_stringv[1] = STRV_TERMINATOR;
Packit a189e0
        actual_stringv[2] = NULL;
Packit a189e0
Packit a189e0
        length = 2;
Packit a189e0
        free_strv = TRUE;
Packit a189e0
    }
Packit a189e0
    else
Packit a189e0
    {
Packit a189e0
        actual_stringv = (gchar **) stringv;
Packit a189e0
    }
Packit a189e0
Packit a189e0
    g_key_file_set_string_list (keyfile,
Packit a189e0
                                name,
Packit a189e0
                                key,
Packit a189e0
                                (const gchar **) actual_stringv,
Packit a189e0
                                length);
Packit a189e0
Packit a189e0
    save_in_idle (keyfile_filename);
Packit a189e0
Packit a189e0
    if (nautilus_keyfile_metadata_update_from_keyfile (file, keyfile_filename, name))
Packit a189e0
    {
Packit a189e0
        nautilus_file_changed (file);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    if (free_strv)
Packit a189e0
    {
Packit a189e0
        g_free (actual_stringv);
Packit a189e0
    }
Packit a189e0
}
Packit a189e0
Packit a189e0
gboolean
Packit a189e0
nautilus_keyfile_metadata_update_from_keyfile (NautilusFile *file,
Packit a189e0
                                               const char   *keyfile_filename,
Packit a189e0
                                               const gchar  *name)
Packit a189e0
{
Packit a189e0
    gchar **keys, **values;
Packit a189e0
    const gchar *actual_values[2];
Packit a189e0
    const gchar *key, *value;
Packit a189e0
    gchar *gio_key;
Packit a189e0
    gsize length, values_length;
Packit a189e0
    GKeyFile *keyfile;
Packit a189e0
    GFileInfo *info;
Packit a189e0
    gint idx;
Packit a189e0
    gboolean res;
Packit a189e0
Packit a189e0
    keyfile = get_keyfile (keyfile_filename);
Packit a189e0
Packit a189e0
    keys = g_key_file_get_keys (keyfile,
Packit a189e0
                                name,
Packit a189e0
                                &length,
Packit a189e0
                                NULL);
Packit a189e0
Packit a189e0
    if (keys == NULL)
Packit a189e0
    {
Packit a189e0
        return FALSE;
Packit a189e0
    }
Packit a189e0
Packit a189e0
    info = g_file_info_new ();
Packit a189e0
Packit a189e0
    for (idx = 0; idx < length; idx++)
Packit a189e0
    {
Packit a189e0
        key = keys[idx];
Packit a189e0
        values = g_key_file_get_string_list (keyfile,
Packit a189e0
                                             name,
Packit a189e0
                                             key,
Packit a189e0
                                             &values_length,
Packit a189e0
                                             NULL);
Packit a189e0
Packit a189e0
        gio_key = g_strconcat ("metadata::", key, NULL);
Packit a189e0
Packit a189e0
        if (values_length < 1)
Packit a189e0
        {
Packit a189e0
            continue;
Packit a189e0
        }
Packit a189e0
        else if (values_length == 1)
Packit a189e0
        {
Packit a189e0
            g_file_info_set_attribute_string (info,
Packit a189e0
                                              gio_key,
Packit a189e0
                                              values[0]);
Packit a189e0
        }
Packit a189e0
        else if (values_length == 2)
Packit a189e0
        {
Packit a189e0
            /* deal with the fact that single-length strv are stored
Packit a189e0
             * with an additional terminator in the keyfile string, to differentiate
Packit a189e0
             * them from the regular string case.
Packit a189e0
             */
Packit a189e0
            value = values[1];
Packit a189e0
Packit a189e0
            if (g_strcmp0 (value, STRV_TERMINATOR) == 0)
Packit a189e0
            {
Packit a189e0
                /* if the 2nd value is the terminator, remove it */
Packit a189e0
                actual_values[0] = values[0];
Packit a189e0
                actual_values[1] = NULL;
Packit a189e0
Packit a189e0
                g_file_info_set_attribute_stringv (info,
Packit a189e0
                                                   gio_key,
Packit a189e0
                                                   (gchar **) actual_values);
Packit a189e0
            }
Packit a189e0
            else
Packit a189e0
            {
Packit a189e0
                /* otherwise, set it as a regular strv */
Packit a189e0
                g_file_info_set_attribute_stringv (info,
Packit a189e0
                                                   gio_key,
Packit a189e0
                                                   values);
Packit a189e0
            }
Packit a189e0
        }
Packit a189e0
        else
Packit a189e0
        {
Packit a189e0
            g_file_info_set_attribute_stringv (info,
Packit a189e0
                                               gio_key,
Packit a189e0
                                               values);
Packit a189e0
        }
Packit a189e0
Packit a189e0
        g_free (gio_key);
Packit a189e0
        g_strfreev (values);
Packit a189e0
    }
Packit a189e0
Packit a189e0
    res = nautilus_file_update_metadata_from_info (file, info);
Packit a189e0
Packit a189e0
    g_strfreev (keys);
Packit a189e0
    g_object_unref (info);
Packit a189e0
Packit a189e0
    return res;
Packit a189e0
}