1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-*/
3 /* nautilus-metafile.c - server side of Nautilus::Metafile
5 * Copyright (C) 2001 Eazel, Inc.
6 * Copyright (C) 2001-2005 Free Software Foundation, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 #include "nautilus-metafile.h"
27 #include "nautilus-directory.h"
28 #include "nautilus-directory.h"
29 #include "nautilus-file-private.h"
30 #include "nautilus-file-utilities.h"
31 #include "nautilus-global-preferences.h"
32 #include "nautilus-metadata.h"
33 #include "nautilus-thumbnails.h"
34 #include <eel/eel-glib-extensions.h>
35 #include <eel/eel-gtk-macros.h>
36 #include <eel/eel-string.h>
37 #include <eel/eel-vfs-extensions.h>
38 #include <eel/eel-xml-extensions.h>
39 #include <glib/gurifuncs.h>
40 #include <libxml/parser.h>
41 #include <gtk/gtkmain.h>
46 #define METAFILE_XML_VERSION "1.0"
47 #define METAFILE_PERMISSIONS 0600
48 #define METAFILES_DIRECTORY_NAME "metafiles"
56 static guint signals
[LAST_SIGNAL
] = { 0 };
58 /* TODO asynchronous copying/moving of metadata
60 * - potential metadata loss when a deletion is scheduled, and new metadata is copied to
61 * this location before the old deletion is consumed
63 * - if metafile read fails, and a file from that metafile is scheduled for a copy/move operation,
64 * its associated operations are not removed from pending_copies
68 static char *get_file_metadata (NautilusMetafile
*metafile
,
69 const char *file_name
,
71 const char *default_metadata
);
72 static GList
*get_file_metadata_list (NautilusMetafile
*metafile
,
73 const char *file_name
,
75 const char *list_subkey
);
76 static gboolean
set_file_metadata (NautilusMetafile
*metafile
,
77 const char *file_name
,
79 const char *default_metadata
,
80 const char *metadata
);
81 static gboolean
set_file_metadata_list (NautilusMetafile
*metafile
,
82 const char *file_name
,
84 const char *list_subkey
,
86 static void rename_file_metadata (NautilusMetafile
*metafile
,
87 const char *old_file_name
,
88 const char *new_file_name
);
89 static void copy_file_metadata (NautilusMetafile
*source_metafile
,
90 const char *source_file_name
,
91 NautilusMetafile
*destination_metafile
,
92 const char *destination_file_name
);
93 static void real_copy_file_metadata (NautilusMetafile
*source_metafile
,
94 const char *source_file_name
,
95 NautilusMetafile
*destination_metafile
,
96 const char *destination_file_name
);
97 static void remove_file_metadata (NautilusMetafile
*metafile
,
98 const char *file_name
);
99 static void real_remove_file_metadata (NautilusMetafile
*metafile
,
100 const char *file_name
);
101 static void call_metafile_changed_for_one_file (NautilusMetafile
*metafile
,
102 const char *file_name
);
103 static void metafile_read_restart (NautilusMetafile
*metafile
);
104 static void metafile_read_start (NautilusMetafile
*metafile
);
105 static void metafile_write_start (NautilusMetafile
*metafile
);
106 static void directory_request_write_metafile (NautilusMetafile
*metafile
);
107 static void metafile_free_metadata (NautilusMetafile
*metafile
);
108 static void metafile_read_cancel (NautilusMetafile
*metafile
);
109 static void async_read_cancel (NautilusMetafile
*metafile
);
110 static void set_metafile_contents (NautilusMetafile
*metafile
,
111 xmlDocPtr metafile_contents
);
113 typedef struct MetafileReadState
{
114 NautilusMetafile
*metafile
;
115 GCancellable
*cancellable
;
118 typedef struct MetafileWriteState
{
121 gboolean write_again
;
122 } MetafileWriteState
;
124 struct _NautilusMetafile
{
130 GHashTable
*node_hash
;
133 /* State for reading and writing metadata. */
134 MetafileReadState
*read_state
;
136 MetafileWriteState
*write_state
;
144 static GHashTable
*metafiles
;
146 G_DEFINE_TYPE (NautilusMetafile
, nautilus_metafile
, G_TYPE_OBJECT
);
149 nautilus_metafile_init (NautilusMetafile
*metafile
)
151 metafile
->node_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
156 finalize (GObject
*object
)
158 NautilusMetafile
*metafile
;
160 metafile
= NAUTILUS_METAFILE (object
);
162 g_assert (metafile
->write_state
== NULL
);
163 async_read_cancel (metafile
);
164 g_assert (metafile
->read_state
== NULL
);
166 g_hash_table_remove (metafiles
, metafile
->directory_uri
);
168 metafile_free_metadata (metafile
);
169 g_hash_table_destroy (metafile
->node_hash
);
171 g_assert (metafile
->write_idle_id
== 0);
173 g_free (metafile
->private_uri
);
174 g_free (metafile
->directory_uri
);
176 G_OBJECT_CLASS (nautilus_metafile_parent_class
)->finalize (object
);
180 escape_slashes (const char *str
)
187 for (p
= str
; *p
!= 0; p
++) {
188 if (*p
== '%' || *p
== '/') {
193 escaped
= g_malloc (strlen (str
) + 2*n_reserved
+ 1);
197 for (p
= str
; *p
!= 0; p
++) {
202 } else if (*p
== '/') {
217 construct_private_metafile_uri (const char *uri
)
219 char *user_directory
, *metafiles_directory
;
220 char *escaped_uri
, *file_name
;
221 char *alternate_path
, *alternate_uri
;
223 /* Ensure that the metafiles directory exists. */
224 user_directory
= nautilus_get_user_directory ();
225 metafiles_directory
= g_build_filename (user_directory
, METAFILES_DIRECTORY_NAME
, NULL
);
226 g_free (user_directory
);
227 mkdir (metafiles_directory
, 0700);
229 /* Construct a file name from the URI. */
230 escaped_uri
= escape_slashes (uri
);
231 file_name
= g_strconcat (escaped_uri
, ".xml", NULL
);
232 g_free (escaped_uri
);
234 /* Construct a URI for something in the "metafiles" directory. */
235 alternate_path
= g_build_filename (metafiles_directory
, file_name
, NULL
);
236 g_free (metafiles_directory
);
238 alternate_uri
= g_filename_to_uri (alternate_path
, NULL
, NULL
);
239 g_free (alternate_path
);
241 return alternate_uri
;
245 nautilus_metafile_set_directory_uri (NautilusMetafile
*metafile
,
246 const char *directory_uri
)
248 if (eel_strcmp (metafile
->directory_uri
, directory_uri
) == 0) {
252 g_free (metafile
->directory_uri
);
253 metafile
->directory_uri
= g_strdup (directory_uri
);
255 g_free (metafile
->private_uri
);
256 metafile
->private_uri
257 = construct_private_metafile_uri (directory_uri
);
260 static NautilusMetafile
*
261 nautilus_metafile_new (const char *directory_uri
)
263 NautilusMetafile
*metafile
;
265 metafile
= NAUTILUS_METAFILE (g_object_new (NAUTILUS_TYPE_METAFILE
, NULL
));
267 nautilus_metafile_set_directory_uri (metafile
, directory_uri
);
273 nautilus_metafile_get_for_uri (const char *directory_uri
)
275 NautilusMetafile
*metafile
;
279 g_return_val_if_fail (directory_uri
!= NULL
, NULL
);
281 if (metafiles
== NULL
) {
282 metafiles
= eel_g_hash_table_new_free_at_exit
283 (g_str_hash
, g_str_equal
, __FILE__
": metafiles");
287 file
= g_file_new_for_uri (directory_uri
);
288 canonical_uri
= g_file_get_uri (file
);
289 g_object_unref (file
);
291 metafile
= g_hash_table_lookup (metafiles
, canonical_uri
);
293 if (metafile
!= NULL
) {
294 g_object_ref (metafile
);
296 metafile
= nautilus_metafile_new (canonical_uri
);
298 g_assert (strcmp (metafile
->directory_uri
, canonical_uri
) == 0);
300 g_hash_table_insert (metafiles
,
301 metafile
->directory_uri
,
305 g_free (canonical_uri
);
310 static GList
*pending_copies
;
313 NautilusMetafile
*source_metafile
;
314 char *source_file_name
;
315 NautilusMetafile
*destination_metafile
;
316 char *destination_file_name
;
317 } NautilusMetadataCopy
;
320 nautilus_metadata_copy_equal (const NautilusMetadataCopy
*a
,
321 const NautilusMetadataCopy
*b
)
323 return (b
->source_metafile
== a
->source_metafile
)
324 && (b
->destination_metafile
== a
->destination_metafile
)
325 && (strcmp (a
->source_file_name
, b
->source_file_name
) == 0)
326 && (strcmp (a
->destination_file_name
, b
->destination_file_name
) == 0);
329 static NautilusMetadataCopy
*
330 nautilus_metadata_get_scheduled_copy (NautilusMetafile
*source_metafile
,
331 const char *source_file_name
,
332 NautilusMetafile
*destination_metafile
,
333 const char *destination_file_name
)
335 NautilusMetadataCopy key
, *copy
;
338 key
.source_metafile
= source_metafile
;
339 key
.source_file_name
= (char *) source_file_name
;
340 key
.destination_metafile
= destination_metafile
;
341 key
.destination_file_name
= (char *) destination_file_name
;
343 for (l
= pending_copies
; l
!= NULL
; l
= l
->next
) {
346 if (nautilus_metadata_copy_equal (l
->data
, &key
)) {
355 nautilus_metadata_has_scheduled_copy (NautilusMetafile
*source_metafile
,
356 const char *source_file_name
)
358 NautilusMetadataCopy
*copy
;
361 for (l
= pending_copies
; l
!= NULL
; l
= l
->next
) {
364 if ((copy
->source_metafile
== source_metafile
) &&
365 (strcmp (copy
->source_file_name
, source_file_name
) == 0)) {
374 nautilus_metadata_schedule_copy (NautilusMetafile
*source_metafile
,
375 const char *source_file_name
,
376 NautilusMetafile
*destination_metafile
,
377 const char *destination_file_name
)
379 NautilusMetadataCopy
*copy
;
381 g_assert (!source_metafile
->is_read
|| !destination_metafile
->is_read
);
383 copy
= nautilus_metadata_get_scheduled_copy (source_metafile
,
385 destination_metafile
,
386 destination_file_name
);
388 copy
= g_malloc (sizeof (NautilusMetadataCopy
));
389 copy
->source_metafile
= g_object_ref (source_metafile
);
390 copy
->source_file_name
= g_strdup (source_file_name
);
391 copy
->destination_metafile
= g_object_ref (destination_metafile
);
392 copy
->destination_file_name
= g_strdup (destination_file_name
);
394 pending_copies
= g_list_prepend (pending_copies
, copy
);
396 metafile_read_start (source_metafile
);
397 metafile_read_start (destination_metafile
);
402 nautilus_metadata_process_ready_copies (void)
404 NautilusMetadataCopy
*copy
;
413 if (copy
->source_metafile
->is_read
&&
414 copy
->destination_metafile
->is_read
) {
415 real_copy_file_metadata (copy
->source_metafile
, copy
->source_file_name
,
416 copy
->destination_metafile
, copy
->destination_file_name
);
418 g_object_unref (copy
->source_metafile
);
419 g_free (copy
->source_file_name
);
420 g_object_unref (copy
->destination_metafile
);
421 g_free (copy
->destination_file_name
);
424 pending_copies
= g_list_delete_link (pending_copies
, l
);
431 static GList
*pending_removals
;
434 NautilusMetafile
*metafile
;
436 } NautilusMetadataRemoval
;
439 nautilus_metadata_removal_equal (const NautilusMetadataRemoval
*a
,
440 const NautilusMetadataRemoval
*b
)
442 return ((b
->metafile
== a
->metafile
) &&
443 (strcmp (a
->file_name
, b
->file_name
) == 0));
446 static NautilusMetadataRemoval
*
447 nautilus_metadata_get_scheduled_removal (NautilusMetafile
*metafile
,
448 const char *file_name
)
450 NautilusMetadataRemoval key
, *removal
;
453 key
.metafile
= metafile
;
454 key
.file_name
= (char *) file_name
;
456 for (l
= pending_removals
; l
!= NULL
; l
= l
->next
) {
459 if (nautilus_metadata_removal_equal (l
->data
, &key
)) {
468 nautilus_metadata_schedule_removal (NautilusMetafile
*metafile
,
469 const char *file_name
)
471 NautilusMetadataRemoval
*removal
;
473 g_assert (nautilus_metadata_has_scheduled_copy (metafile
, file_name
));
475 removal
= nautilus_metadata_get_scheduled_removal (metafile
, file_name
);
476 if (removal
== NULL
) {
477 removal
= g_malloc (sizeof (NautilusMetadataRemoval
));
478 removal
->metafile
= g_object_ref (metafile
);
479 removal
->file_name
= g_strdup (file_name
);
481 pending_removals
= g_list_prepend (pending_removals
, removal
);
486 nautilus_metadata_process_ready_removals (void)
488 NautilusMetadataRemoval
*removal
;
491 l
= pending_removals
;
497 if (!nautilus_metadata_has_scheduled_copy (removal
->metafile
, removal
->file_name
)) {
498 real_remove_file_metadata (removal
->metafile
, removal
->file_name
);
500 pending_removals
= g_list_delete_link (pending_removals
, l
);
502 g_object_unref (removal
->metafile
);
503 g_free (removal
->file_name
);
511 * Right now we only limit the number of conccurrent reads.
512 * We may want to consider limiting writes as well.
515 static int num_reads_in_progress
;
516 static GList
*pending_reads
;
519 #define DEBUG_METADATA_IO
523 schedule_next_read (void)
525 const int kMaxAsyncReads
= 10;
529 #ifdef DEBUG_METADATA_IO
530 g_message ("schedule_next_read: %d pending reads, %d reads in progress",
531 g_list_length (pending_reads
), num_reads_in_progress
);
534 if (pending_reads
!= NULL
&& num_reads_in_progress
<= kMaxAsyncReads
) {
535 node
= pending_reads
;
536 pending_reads
= g_list_remove_link (pending_reads
, node
);
537 #ifdef DEBUG_METADATA_IO
538 g_message ("schedule_next_read: %s", NAUTILUS_METAFILE (node
->data
)->details
->directory_uri
);
540 metafile_read_start (node
->data
);
541 g_list_free_1 (node
);
542 ++num_reads_in_progress
;
547 async_read_start (NautilusMetafile
*metafile
)
549 if (metafile
->is_read
||
550 metafile
->read_state
!= NULL
) {
553 #ifdef DEBUG_METADATA_IO
554 g_message ("async_read_start: %s", metafile
->directory_uri
);
556 pending_reads
= g_list_prepend (pending_reads
, metafile
);
557 schedule_next_read ();
561 async_read_done (NautilusMetafile
*metafile
)
563 #ifdef DEBUG_METADATA_IO
564 g_message ("async_read_done: %s", metafile
->directory_uri
);
566 --num_reads_in_progress
;
567 schedule_next_read ();
571 async_read_cancel (NautilusMetafile
*metafile
)
575 #ifdef DEBUG_METADATA_IO
576 g_message ("async_read_cancel: %s", metafile
->directory_uri
);
578 node
= g_list_find (pending_reads
, metafile
);
581 pending_reads
= g_list_remove_link (pending_reads
, node
);
582 g_list_free_1 (node
);
585 if (metafile
->read_state
!= NULL
) {
586 metafile_read_cancel (metafile
);
587 async_read_done (metafile
);
593 nautilus_metafile_is_read (NautilusMetafile
*metafile
)
595 return metafile
->is_read
;
599 nautilus_metafile_get (NautilusMetafile
*metafile
,
600 const char *file_name
,
602 const char *default_value
)
604 return get_file_metadata (metafile
, file_name
, key
, default_value
);
608 nautilus_metafile_get_list (NautilusMetafile
*metafile
,
609 const char *file_name
,
610 const char *list_key
,
611 const char *list_subkey
)
613 return get_file_metadata_list (metafile
, file_name
, list_key
, list_subkey
);
618 nautilus_metafile_set (NautilusMetafile
*metafile
,
619 const char *file_name
,
621 const char *default_value
,
622 const char *metadata
)
624 if (set_file_metadata (metafile
, file_name
, key
, default_value
, metadata
)) {
625 call_metafile_changed_for_one_file (metafile
, file_name
);
630 nautilus_metafile_set_list (NautilusMetafile
*metafile
,
631 const char *file_name
,
632 const char *list_key
,
633 const char *list_subkey
,
636 if (set_file_metadata_list (metafile
, file_name
, list_key
, list_subkey
, list
)) {
637 call_metafile_changed_for_one_file (metafile
, file_name
);
642 nautilus_metafile_copy (NautilusMetafile
*source_metafile
,
643 const char *source_file_name
,
644 const char *destination_directory_uri
,
645 const char *destination_file_name
)
647 NautilusMetafile
*destination_metafile
;
649 destination_metafile
= nautilus_metafile_get_for_uri (destination_directory_uri
);
651 copy_file_metadata (source_metafile
, source_file_name
,
652 destination_metafile
, destination_file_name
);
654 g_object_unref (destination_metafile
);
659 nautilus_metafile_remove (NautilusMetafile
*metafile
,
660 const char *file_name
)
662 remove_file_metadata (metafile
, file_name
);
666 nautilus_metafile_rename (NautilusMetafile
*metafile
,
667 const char *old_file_name
,
668 const char *new_file_name
)
670 rename_file_metadata (metafile
, old_file_name
, new_file_name
);
674 nautilus_metafile_rename_directory (NautilusMetafile
*metafile
,
675 const char *new_directory_uri
)
677 nautilus_metafile_set_directory_uri (metafile
, new_directory_uri
);
681 nautilus_metafile_load (NautilusMetafile
*metafile
)
683 async_read_start (metafile
);
687 notify_metafile_ready_idle (gpointer user_data
)
689 NautilusMetafile
*metafile
;
690 metafile
= user_data
;
692 g_signal_emit (metafile
, signals
[READY
], 0);
693 g_object_unref (metafile
);
698 nautilus_metafile_notify_metafile_ready (NautilusMetafile
*metafile
, gboolean in_idle
)
701 g_idle_add (notify_metafile_ready_idle
, g_object_ref (metafile
));
703 g_signal_emit (metafile
, signals
[READY
], 0);
708 NautilusMetafile
*metafile
;
713 metafile_changed_idle (gpointer user_data
)
719 g_signal_emit (data
->metafile
, signals
[CHANGED
], 0, data
->file_names
);
721 g_object_unref (data
->metafile
);
722 eel_g_list_free_deep (data
->file_names
);
729 call_metafile_changed (NautilusMetafile
*metafile
,
734 data
= g_new (ChangedData
, 1);
735 data
->metafile
= g_object_ref (metafile
);
736 data
->file_names
= eel_g_str_list_copy (file_names
);
738 g_idle_add (metafile_changed_idle
, data
);
743 file_list_filler_ghfunc (gpointer key
,
747 Nautilus_FileNameList
*file_names
;
749 file_names
= user_data
;
751 file_names
->_buffer
[file_names
->_length
] = key
;
753 ++file_names
->_length
;
757 call_metafile_changed_for_all_files_mentioned_in_metafile (NautilusMetafile
*metafile
)
759 CORBA_unsigned_long len
;
760 Nautilus_FileNameList file_names
;
762 len
= g_hash_table_size (metafile
->node_hash
);
765 file_names
._maximum
= len
;
766 file_names
._length
= 0;
767 file_names
._buffer
= g_new (CORBA_char
*, len
);
769 g_hash_table_foreach (metafile
->node_hash
,
770 file_list_filler_ghfunc
,
773 call_metafile_changed (metafile
, &file_names
);
775 g_free (file_names
._buffer
);
781 call_metafile_changed_for_one_file (NautilusMetafile
*metafile
,
782 const char *file_name
)
788 l
.data
= (void *)file_name
;
790 call_metafile_changed (metafile
, &l
);
803 get_metadata_from_node (xmlNode
*node
,
805 const char *default_metadata
)
810 g_return_val_if_fail (key
!= NULL
, NULL
);
811 g_return_val_if_fail (key
[0] != '\0', NULL
);
813 property
= xmlGetProp (node
, key
);
814 if (property
== NULL
) {
815 result
= g_strdup (default_metadata
);
817 result
= g_strdup (property
);
825 get_metadata_list_from_node (xmlNode
*node
,
826 const char *list_key
,
827 const char *list_subkey
)
829 return eel_xml_get_property_for_children
830 (node
, list_key
, list_subkey
);
834 create_metafile_root (NautilusMetafile
*metafile
)
838 if (metafile
->xml
== NULL
) {
839 set_metafile_contents (metafile
, xmlNewDoc (METAFILE_XML_VERSION
));
841 root
= xmlDocGetRootElement (metafile
->xml
);
843 root
= xmlNewDocNode (metafile
->xml
, NULL
, "directory", NULL
);
844 xmlDocSetRootElement (metafile
->xml
, root
);
851 get_file_node (NautilusMetafile
*metafile
,
852 const char *file_name
,
856 xmlNode
*root
, *node
;
857 char *escaped_file_name
;
859 g_assert (NAUTILUS_IS_METAFILE (metafile
));
861 hash
= metafile
->node_hash
;
862 node
= g_hash_table_lookup (hash
, file_name
);
868 root
= create_metafile_root (metafile
);
869 node
= xmlNewChild (root
, NULL
, "file", NULL
);
870 escaped_file_name
= g_uri_escape_string (file_name
, NULL
, 0);
871 xmlSetProp (node
, "name", escaped_file_name
);
872 g_free (escaped_file_name
);
873 g_hash_table_insert (hash
, xmlMemStrdup (file_name
), node
);
881 set_file_node_timestamp (xmlNode
*node
)
885 /* 2^64 turns out to be 20 characters */
886 snprintf (time_str
, 20, "%ld", time (NULL
));
887 time_str
[20] = '\0';
888 xmlSetProp (node
, "timestamp", time_str
);
892 get_metadata_string_from_metafile (NautilusMetafile
*metafile
,
893 const char *file_name
,
895 const char *default_metadata
)
899 node
= get_file_node (metafile
, file_name
, FALSE
);
900 return get_metadata_from_node (node
, key
, default_metadata
);
904 get_metadata_list_from_metafile (NautilusMetafile
*metafile
,
905 const char *file_name
,
906 const char *list_key
,
907 const char *list_subkey
)
911 node
= get_file_node (metafile
, file_name
, FALSE
);
912 return get_metadata_list_from_node (node
, list_key
, list_subkey
);
916 set_metadata_string_in_metafile (NautilusMetafile
*metafile
,
917 const char *file_name
,
919 const char *default_metadata
,
920 const char *metadata
)
923 gboolean old_metadata_matches
;
926 xmlAttr
*property_node
;
928 /* If the data in the metafile is already correct, do nothing. */
929 old_metadata
= get_file_metadata
930 (metafile
, file_name
, key
, default_metadata
);
932 old_metadata_matches
= eel_strcmp (old_metadata
, metadata
) == 0;
933 g_free (old_metadata
);
934 if (old_metadata_matches
) {
938 /* Data that matches the default is represented in the tree by
939 * the lack of an attribute.
941 if (eel_strcmp (default_metadata
, metadata
) == 0) {
947 /* Get or create the node. */
948 node
= get_file_node (metafile
, file_name
, value
!= NULL
);
951 /* Set the timestamp */
952 set_file_node_timestamp (node
);
954 /* Add or remove a property node. */
955 property_node
= xmlSetProp (node
, key
, value
);
957 xmlRemoveProp (property_node
);
961 /* Since we changed the tree, arrange for it to be written. */
962 directory_request_write_metafile (metafile
);
967 set_metadata_list_in_metafile (NautilusMetafile
*metafile
,
968 const char *file_name
,
969 const char *list_key
,
970 const char *list_subkey
,
973 xmlNode
*node
, *child
, *next
;
978 /* Get or create the node. */
979 node
= get_file_node (metafile
, file_name
, list
!= NULL
);
981 /* Work with the list. */
984 g_assert (list
== NULL
);
988 /* Remove any nodes except the ones we expect. */
989 for (child
= eel_xml_get_children (node
);
994 if (strcmp (child
->name
, list_key
) == 0) {
995 property
= xmlGetProp (child
, list_subkey
);
996 if (property
!= NULL
&& p
!= NULL
997 && strcmp (property
, (char *) p
->data
) == 0) {
1000 xmlUnlinkNode (child
);
1001 xmlFreeNode (child
);
1008 /* Add any additional nodes needed. */
1009 for (; p
!= NULL
; p
= p
->next
) {
1010 child
= xmlNewChild (node
, NULL
, list_key
, NULL
);
1011 xmlSetProp (child
, list_subkey
, p
->data
);
1015 /* Set the timestamp */
1016 set_file_node_timestamp (node
);
1023 directory_request_write_metafile (metafile
);
1027 static MetadataValue
*
1028 metadata_value_new (const char *default_metadata
, const char *metadata
)
1030 MetadataValue
*value
;
1032 value
= g_new0 (MetadataValue
, 1);
1034 value
->default_value
= g_strdup (default_metadata
);
1035 value
->value
.string
= g_strdup (metadata
);
1040 static MetadataValue
*
1041 metadata_value_new_list (GList
*metadata
)
1043 MetadataValue
*value
;
1045 value
= g_new0 (MetadataValue
, 1);
1047 value
->is_list
= TRUE
;
1048 value
->value
.string_list
= eel_g_str_list_copy (metadata
);
1054 metadata_value_destroy (MetadataValue
*value
)
1056 if (value
== NULL
) {
1060 if (!value
->is_list
) {
1061 g_free (value
->value
.string
);
1063 eel_g_list_free_deep (value
->value
.string_list
);
1065 g_free (value
->default_value
);
1070 metadata_value_equal (const MetadataValue
*value_a
,
1071 const MetadataValue
*value_b
)
1073 if (value_a
->is_list
!= value_b
->is_list
) {
1077 if (!value_a
->is_list
) {
1078 return eel_strcmp (value_a
->value
.string
,
1079 value_b
->value
.string
) == 0
1080 && eel_strcmp (value_a
->default_value
,
1081 value_b
->default_value
) == 0;
1083 g_assert (value_a
->default_value
== NULL
);
1084 g_assert (value_b
->default_value
== NULL
);
1086 return eel_g_str_list_equal
1087 (value_a
->value
.string_list
,
1088 value_b
->value
.string_list
);
1093 set_metadata_in_metafile (NautilusMetafile
*metafile
,
1094 const char *file_name
,
1097 const MetadataValue
*value
)
1101 if (!value
->is_list
) {
1102 g_assert (subkey
== NULL
);
1103 changed
= set_metadata_string_in_metafile
1104 (metafile
, file_name
, key
,
1105 value
->default_value
,
1106 value
->value
.string
);
1108 g_assert (value
->default_value
== NULL
);
1109 changed
= set_metadata_list_in_metafile
1110 (metafile
, file_name
, key
, subkey
,
1111 value
->value
.string_list
);
1118 get_metadata_string_from_table (NautilusMetafile
*metafile
,
1119 const char *file_name
,
1121 const char *default_metadata
)
1123 GHashTable
*directory_table
, *file_table
;
1124 MetadataValue
*value
;
1126 /* Get the value from the hash table. */
1127 directory_table
= metafile
->changes
;
1128 file_table
= directory_table
== NULL
? NULL
1129 : g_hash_table_lookup (directory_table
, file_name
);
1130 value
= file_table
== NULL
? NULL
1131 : g_hash_table_lookup (file_table
, key
);
1132 if (value
== NULL
) {
1133 return g_strdup (default_metadata
);
1136 /* Convert it to a string. */
1137 g_assert (!value
->is_list
);
1138 if (eel_strcmp (value
->value
.string
, value
->default_value
) == 0) {
1139 return g_strdup (default_metadata
);
1141 return g_strdup (value
->value
.string
);
1145 get_metadata_list_from_table (NautilusMetafile
*metafile
,
1146 const char *file_name
,
1150 GHashTable
*directory_table
, *file_table
;
1152 MetadataValue
*value
;
1154 /* Get the value from the hash table. */
1155 directory_table
= metafile
->changes
;
1156 file_table
= directory_table
== NULL
? NULL
1157 : g_hash_table_lookup (directory_table
, file_name
);
1158 if (file_table
== NULL
) {
1161 combined_key
= g_strconcat (key
, "/", subkey
, NULL
);
1162 value
= g_hash_table_lookup (file_table
, combined_key
);
1163 g_free (combined_key
);
1164 if (value
== NULL
) {
1168 /* Copy the list and return it. */
1169 g_assert (value
->is_list
);
1170 return eel_g_str_list_copy (value
->value
.string_list
);
1174 str_or_null_hash (gconstpointer str
)
1176 return str
== NULL
? 0 : g_str_hash (str
);
1180 str_or_null_equal (gconstpointer str_a
, gconstpointer str_b
)
1182 if (str_a
== NULL
) {
1183 return str_b
== NULL
;
1185 if (str_b
== NULL
) {
1188 return g_str_equal (str_a
, str_b
);
1192 set_metadata_eat_value (NautilusMetafile
*metafile
,
1193 const char *file_name
,
1196 MetadataValue
*value
)
1198 GHashTable
*directory_table
, *file_table
;
1201 MetadataValue
*old_value
;
1203 if (metafile
->is_read
) {
1204 changed
= set_metadata_in_metafile
1205 (metafile
, file_name
, key
, subkey
, value
);
1206 metadata_value_destroy (value
);
1208 /* Create hash table only when we need it.
1209 * We'll destroy it when we finish reading the metafile.
1211 directory_table
= metafile
->changes
;
1212 if (directory_table
== NULL
) {
1213 directory_table
= g_hash_table_new
1214 (str_or_null_hash
, str_or_null_equal
);
1215 metafile
->changes
= directory_table
;
1217 file_table
= g_hash_table_lookup (directory_table
, file_name
);
1218 if (file_table
== NULL
) {
1219 file_table
= g_hash_table_new (g_str_hash
, g_str_equal
);
1220 g_hash_table_insert (directory_table
,
1221 g_strdup (file_name
), file_table
);
1224 /* Find the entry in the hash table. */
1225 if (subkey
== NULL
) {
1226 combined_key
= g_strdup (key
);
1228 combined_key
= g_strconcat (key
, "/", subkey
, NULL
);
1230 old_value
= g_hash_table_lookup (file_table
, combined_key
);
1232 /* Put the change into the hash. Delete the old change. */
1233 changed
= old_value
== NULL
|| !metadata_value_equal (old_value
, value
);
1235 g_hash_table_insert (file_table
, combined_key
, value
);
1236 if (old_value
!= NULL
) {
1237 /* The hash table keeps the old key. */
1238 g_free (combined_key
);
1239 metadata_value_destroy (old_value
);
1242 g_free (combined_key
);
1243 metadata_value_destroy (value
);
1251 free_file_table_entry (gpointer key
, gpointer value
, gpointer user_data
)
1253 g_assert (user_data
== NULL
);
1256 metadata_value_destroy (value
);
1260 free_directory_table_entry (gpointer key
, gpointer value
, gpointer user_data
)
1262 g_assert (user_data
== NULL
);
1263 g_assert (value
!= NULL
);
1266 g_hash_table_foreach (value
, free_file_table_entry
, NULL
);
1267 g_hash_table_destroy (value
);
1271 destroy_metadata_changes_hash_table (GHashTable
*directory_table
)
1273 if (directory_table
== NULL
) {
1276 g_hash_table_foreach (directory_table
, free_directory_table_entry
, NULL
);
1277 g_hash_table_destroy (directory_table
);
1281 destroy_xml_string_key (gpointer key
, gpointer value
, gpointer user_data
)
1283 g_assert (key
!= NULL
);
1284 g_assert (user_data
== NULL
);
1285 g_assert (value
!= NULL
);
1291 metafile_free_metadata (NautilusMetafile
*metafile
)
1293 g_return_if_fail (NAUTILUS_IS_METAFILE (metafile
));
1295 g_hash_table_foreach (metafile
->node_hash
,
1296 destroy_xml_string_key
, NULL
);
1297 xmlFreeDoc (metafile
->xml
);
1298 destroy_metadata_changes_hash_table (metafile
->changes
);
1302 get_file_metadata (NautilusMetafile
*metafile
,
1303 const char *file_name
,
1305 const char *default_metadata
)
1307 g_return_val_if_fail (NAUTILUS_IS_METAFILE (metafile
), NULL
);
1308 g_return_val_if_fail (!eel_str_is_empty (file_name
), NULL
);
1309 g_return_val_if_fail (!eel_str_is_empty (key
), NULL
);
1311 if (metafile
->is_read
) {
1312 return get_metadata_string_from_metafile
1313 (metafile
, file_name
, key
, default_metadata
);
1315 return get_metadata_string_from_table
1316 (metafile
, file_name
, key
, default_metadata
);
1321 get_file_metadata_list (NautilusMetafile
*metafile
,
1322 const char *file_name
,
1323 const char *list_key
,
1324 const char *list_subkey
)
1326 g_return_val_if_fail (NAUTILUS_IS_METAFILE (metafile
), NULL
);
1327 g_return_val_if_fail (!eel_str_is_empty (file_name
), NULL
);
1328 g_return_val_if_fail (!eel_str_is_empty (list_key
), NULL
);
1329 g_return_val_if_fail (!eel_str_is_empty (list_subkey
), NULL
);
1331 if (metafile
->is_read
) {
1332 return get_metadata_list_from_metafile
1333 (metafile
, file_name
, list_key
, list_subkey
);
1335 return get_metadata_list_from_table
1336 (metafile
, file_name
, list_key
, list_subkey
);
1341 set_file_metadata (NautilusMetafile
*metafile
,
1342 const char *file_name
,
1344 const char *default_metadata
,
1345 const char *metadata
)
1347 MetadataValue
*value
;
1349 g_return_val_if_fail (NAUTILUS_IS_METAFILE (metafile
), FALSE
);
1350 g_return_val_if_fail (!eel_str_is_empty (file_name
), FALSE
);
1351 g_return_val_if_fail (!eel_str_is_empty (key
), FALSE
);
1353 if (metafile
->is_read
) {
1354 return set_metadata_string_in_metafile (metafile
, file_name
, key
,
1355 default_metadata
, metadata
);
1357 value
= metadata_value_new (default_metadata
, metadata
);
1358 return set_metadata_eat_value (metafile
, file_name
,
1364 set_file_metadata_list (NautilusMetafile
*metafile
,
1365 const char *file_name
,
1366 const char *list_key
,
1367 const char *list_subkey
,
1370 MetadataValue
*value
;
1372 g_return_val_if_fail (NAUTILUS_IS_METAFILE (metafile
), FALSE
);
1373 g_return_val_if_fail (!eel_str_is_empty (file_name
), FALSE
);
1374 g_return_val_if_fail (!eel_str_is_empty (list_key
), FALSE
);
1375 g_return_val_if_fail (!eel_str_is_empty (list_subkey
), FALSE
);
1377 if (metafile
->is_read
) {
1378 return set_metadata_list_in_metafile (metafile
, file_name
,
1379 list_key
, list_subkey
, list
);
1381 value
= metadata_value_new_list (list
);
1382 return set_metadata_eat_value (metafile
, file_name
,
1383 list_key
, list_subkey
, value
);
1388 metafile_get_file_uri (NautilusMetafile
*metafile
,
1389 const char *file_name
)
1391 char *escaped_file_name
, *uri
;
1393 g_return_val_if_fail (NAUTILUS_IS_METAFILE (metafile
), NULL
);
1394 g_return_val_if_fail (file_name
!= NULL
, NULL
);
1396 escaped_file_name
= g_uri_escape_string (file_name
, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH
, FALSE
);
1398 uri
= g_build_filename (metafile
->directory_uri
, escaped_file_name
, NULL
);
1399 g_free (escaped_file_name
);
1404 rename_file_metadata (NautilusMetafile
*metafile
,
1405 const char *old_file_name
,
1406 const char *new_file_name
)
1409 gpointer key
, value
;
1412 char *old_file_uri
, *new_file_uri
;
1415 g_return_if_fail (NAUTILUS_IS_METAFILE (metafile
));
1416 g_return_if_fail (old_file_name
!= NULL
);
1417 g_return_if_fail (new_file_name
!= NULL
);
1419 remove_file_metadata (metafile
, new_file_name
);
1421 if (metafile
->is_read
) {
1422 /* Move data in XML document if present. */
1423 hash
= metafile
->node_hash
;
1424 found
= g_hash_table_lookup_extended
1425 (hash
, old_file_name
, &key
, &value
);
1427 g_assert (strcmp ((const char *) key
, old_file_name
) == 0);
1429 g_hash_table_remove (hash
,
1432 g_hash_table_insert (hash
,
1433 xmlMemStrdup (new_file_name
), value
);
1434 escaped
= g_uri_escape_string (new_file_name
, NULL
, FALSE
);
1435 xmlSetProp (file_node
, "name", escaped
);
1437 directory_request_write_metafile (metafile
);
1440 /* Move data in hash table. */
1441 /* FIXME: If there's data for this file in the
1442 * metafile on disk, this doesn't arrange for that
1443 * data to be moved to the new name.
1445 hash
= metafile
->changes
;
1446 found
= g_hash_table_lookup_extended
1447 (hash
, old_file_name
, &key
, &value
);
1449 g_hash_table_remove (hash
, old_file_name
);
1451 g_hash_table_insert (hash
, g_strdup (new_file_name
), value
);
1455 /* Rename the thumbnails for the file, if any. */
1456 old_file_uri
= metafile_get_file_uri (metafile
, old_file_name
);
1457 new_file_uri
= metafile_get_file_uri (metafile
, new_file_name
);
1458 nautilus_update_thumbnail_file_renamed (old_file_uri
, new_file_uri
);
1459 g_free (old_file_uri
);
1460 g_free (new_file_uri
);
1464 NautilusMetafile
*metafile
;
1465 const char *file_name
;
1469 apply_one_change (gpointer key
, gpointer value
, gpointer callback_data
)
1471 ChangeContext
*context
;
1472 const char *hash_table_key
, *separator
, *metadata_key
, *subkey
;
1475 g_assert (key
!= NULL
);
1476 g_assert (value
!= NULL
);
1477 g_assert (callback_data
!= NULL
);
1479 context
= callback_data
;
1481 /* Break the key in half. */
1482 hash_table_key
= key
;
1483 separator
= strchr (hash_table_key
, '/');
1484 if (separator
== NULL
) {
1486 metadata_key
= hash_table_key
;
1489 key_prefix
= g_strndup (hash_table_key
, separator
- hash_table_key
);
1490 metadata_key
= key_prefix
;
1491 subkey
= separator
+ 1;
1494 /* Set the metadata. */
1495 set_metadata_in_metafile (context
->metafile
, context
->file_name
,
1496 metadata_key
, subkey
, value
);
1497 g_free (key_prefix
);
1501 apply_file_changes (NautilusMetafile
*metafile
,
1502 const char *file_name
,
1503 GHashTable
*changes
)
1505 ChangeContext context
;
1507 g_assert (NAUTILUS_IS_METAFILE (metafile
));
1508 g_assert (file_name
!= NULL
);
1509 g_assert (changes
!= NULL
);
1511 context
.metafile
= metafile
;
1512 context
.file_name
= file_name
;
1514 g_hash_table_foreach (changes
, apply_one_change
, &context
);
1518 apply_one_file_changes (gpointer key
, gpointer value
, gpointer callback_data
)
1520 apply_file_changes (callback_data
, key
, value
);
1521 g_hash_table_destroy (value
);
1525 nautilus_metafile_apply_pending_changes (NautilusMetafile
*metafile
)
1527 if (metafile
->changes
== NULL
) {
1530 g_hash_table_foreach (metafile
->changes
,
1531 apply_one_file_changes
, metafile
);
1532 g_hash_table_destroy (metafile
->changes
);
1533 metafile
->changes
= NULL
;
1537 real_copy_file_metadata (NautilusMetafile
*source_metafile
,
1538 const char *source_file_name
,
1539 NautilusMetafile
*destination_metafile
,
1540 const char *destination_file_name
)
1542 xmlNodePtr source_node
, node
, root
;
1543 GHashTable
*hash
, *changes
;
1546 real_remove_file_metadata (destination_metafile
, destination_file_name
);
1547 g_assert (get_file_node (destination_metafile
, destination_file_name
, FALSE
) == NULL
);
1549 source_node
= get_file_node (source_metafile
, source_file_name
, FALSE
);
1550 if (source_node
!= NULL
) {
1551 node
= xmlCopyNode (source_node
, TRUE
);
1552 root
= create_metafile_root (destination_metafile
);
1553 xmlAddChild (root
, node
);
1554 escaped
= g_uri_escape_string (destination_file_name
, NULL
, FALSE
);
1555 xmlSetProp (node
, "name", escaped
);
1557 set_file_node_timestamp (node
);
1558 g_hash_table_insert (destination_metafile
->node_hash
,
1559 xmlMemStrdup (destination_file_name
), node
);
1560 directory_request_write_metafile (destination_metafile
);
1563 hash
= source_metafile
->changes
;
1565 changes
= g_hash_table_lookup (hash
, source_file_name
);
1566 if (changes
!= NULL
) {
1567 apply_file_changes (destination_metafile
,
1568 destination_file_name
,
1575 copy_file_metadata (NautilusMetafile
*source_metafile
,
1576 const char *source_file_name
,
1577 NautilusMetafile
*destination_metafile
,
1578 const char *destination_file_name
)
1580 char *source_file_uri
;
1581 char *destination_file_uri
;
1583 g_return_if_fail (NAUTILUS_IS_METAFILE (source_metafile
));
1584 g_return_if_fail (source_file_name
!= NULL
);
1585 g_return_if_fail (NAUTILUS_IS_METAFILE (destination_metafile
));
1586 g_return_if_fail (destination_file_name
!= NULL
);
1588 if (source_metafile
->is_read
1589 && destination_metafile
->is_read
) {
1590 real_copy_file_metadata (source_metafile
,
1592 destination_metafile
,
1593 destination_file_name
);
1595 nautilus_metadata_schedule_copy (source_metafile
,
1597 destination_metafile
,
1598 destination_file_name
);
1601 /* Copy the thumbnail for the file, if any. */
1602 source_file_uri
= metafile_get_file_uri (source_metafile
, source_file_name
);
1603 destination_file_uri
= metafile_get_file_uri (destination_metafile
, destination_file_name
);
1604 nautilus_update_thumbnail_file_copied (source_file_uri
, destination_file_uri
);
1605 g_free (source_file_uri
);
1606 g_free (destination_file_uri
);
1610 real_remove_file_metadata (NautilusMetafile
*metafile
,
1611 const char *file_name
)
1614 gpointer key
, value
;
1618 g_return_if_fail (NAUTILUS_IS_METAFILE (metafile
));
1619 g_return_if_fail (file_name
!= NULL
);
1621 if (metafile
->is_read
) {
1622 /* Remove data in XML document if present. */
1623 hash
= metafile
->node_hash
;
1624 found
= g_hash_table_lookup_extended
1625 (hash
, file_name
, &key
, &value
);
1627 g_assert (strcmp ((const char *) key
, file_name
) == 0);
1629 g_hash_table_remove (hash
,
1632 xmlUnlinkNode (file_node
);
1633 xmlFreeNode (file_node
);
1634 directory_request_write_metafile (metafile
);
1637 /* Remove data from hash table. */
1638 /* FIXME: If there's data for this file on the
1639 * metafile on disk, this does not arrange for it to
1640 * be removed when the metafile is later read.
1642 hash
= metafile
->changes
;
1644 found
= g_hash_table_lookup_extended
1645 (hash
, file_name
, &key
, &value
);
1647 g_hash_table_remove (hash
, file_name
);
1649 destroy_metadata_changes_hash_table (value
);
1656 remove_file_metadata (NautilusMetafile
*metafile
,
1657 const char *file_name
)
1661 g_return_if_fail (NAUTILUS_IS_METAFILE (metafile
));
1662 g_return_if_fail (file_name
!= NULL
);
1664 if (nautilus_metadata_has_scheduled_copy (metafile
, file_name
)) {
1665 nautilus_metadata_schedule_removal (metafile
, file_name
);
1667 real_remove_file_metadata (metafile
, file_name
);
1670 /* Delete the thumbnails for the file, if any. */
1671 file_uri
= metafile_get_file_uri (metafile
, file_name
);
1672 nautilus_remove_thumbnail_for_file (file_uri
);
1677 set_metafile_contents (NautilusMetafile
*metafile
,
1678 xmlDocPtr metafile_contents
)
1683 char *unescaped_name
;
1685 g_return_if_fail (NAUTILUS_IS_METAFILE (metafile
));
1686 g_return_if_fail (metafile
->xml
== NULL
);
1688 if (metafile_contents
== NULL
) {
1692 metafile
->xml
= metafile_contents
;
1694 /* Populate the node hash table. */
1695 hash
= metafile
->node_hash
;
1696 for (node
= eel_xml_get_root_children (metafile_contents
);
1697 node
!= NULL
; node
= node
->next
) {
1698 if (strcmp (node
->name
, "file") == 0) {
1699 name
= xmlGetProp (node
, "name");
1700 unescaped_name
= g_uri_unescape_string (name
, "/");
1701 if (unescaped_name
== NULL
||
1702 g_hash_table_lookup (hash
, unescaped_name
) != NULL
) {
1704 /* FIXME: Should we delete duplicate nodes as we discover them? */
1706 g_hash_table_insert (hash
, unescaped_name
, node
);
1713 metafile_read_cancel (NautilusMetafile
*metafile
)
1715 if (metafile
->read_state
!= NULL
) {
1716 g_cancellable_cancel (metafile
->read_state
->cancellable
);
1717 metafile
->read_state
->metafile
= NULL
;
1718 metafile
->read_state
= NULL
;
1723 metafile_read_state_free (MetafileReadState
*state
)
1725 g_object_unref (state
->cancellable
);
1730 metafile_read_mark_done (NautilusMetafile
*metafile
, gboolean callback_in_idle
)
1732 metafile_read_state_free (metafile
->read_state
);
1733 metafile
->read_state
= NULL
;
1735 metafile
->is_read
= TRUE
;
1737 /* Move over the changes to the metafile that were in the hash table. */
1738 nautilus_metafile_apply_pending_changes (metafile
);
1740 /* Tell change-watchers that we have update information. */
1741 nautilus_metafile_notify_metafile_ready (metafile
, callback_in_idle
);
1743 async_read_done (metafile
);
1747 metafile_read_done_callback (GObject
*source_object
,
1751 MetafileReadState
*state
;
1752 NautilusMetafile
*metafile
;
1754 char *file_contents
;
1758 if (state
->metafile
== NULL
) {
1759 /* Operation was cancelled. Bail out */
1760 metafile_read_state_free (state
);
1764 metafile
= state
->metafile
;
1765 g_assert (metafile
->xml
== NULL
);
1767 if (g_file_load_contents_finish (G_FILE (source_object
),
1769 &file_contents
, &file_size
,
1771 set_metafile_contents (metafile
, xmlParseMemory (file_contents
, file_size
));
1772 g_free (file_contents
);
1775 metafile_read_mark_done (metafile
, FALSE
);
1777 nautilus_metadata_process_ready_copies ();
1778 nautilus_metadata_process_ready_removals ();
1782 metafile_read_restart (NautilusMetafile
*metafile
)
1785 MetafileReadState
*state
;
1787 state
= g_new0 (MetafileReadState
, 1);
1788 state
->metafile
= metafile
;
1789 state
->cancellable
= g_cancellable_new ();
1791 metafile
->read_state
= state
;
1793 location
= g_file_new_for_uri (metafile
->private_uri
);
1795 g_file_load_contents_async (location
, state
->cancellable
,
1796 metafile_read_done_callback
, state
);
1798 g_object_unref (location
);
1802 allow_metafile (NautilusMetafile
*metafile
)
1806 g_assert (NAUTILUS_IS_METAFILE (metafile
));
1808 /* Note that this inhibits both reading and writing metadata
1809 * completely. In the future we may want to inhibit writing to
1810 * the real directory while allowing parallel-directory
1814 /* For now, hard-code these schemes. Perhaps we should
1815 * hardcode the schemes that are good for metadata instead of
1816 * the schemes that are bad for it.
1818 /* FIXME bugzilla.gnome.org 42434:
1819 * We need to handle this in a better way. Perhaps a
1820 * better way can wait until we have support for metadata
1821 * access inside gnome-vfs.
1823 uri
= metafile
->directory_uri
;
1824 if (eel_uri_is_search (uri
) ||
1825 eel_istr_has_prefix (uri
, "gnome-help:") ||
1826 eel_istr_has_prefix (uri
, "help:")
1835 metafile_read_start (NautilusMetafile
*metafile
)
1837 g_assert (NAUTILUS_IS_METAFILE (metafile
));
1839 if (metafile
->is_read
||
1840 metafile
->read_state
!= NULL
) {
1844 if (!allow_metafile (metafile
)) {
1845 metafile_read_mark_done (metafile
, TRUE
);
1847 metafile_read_restart (metafile
);
1852 metafile_write_done (NautilusMetafile
*metafile
)
1854 if (metafile
->write_state
->write_again
) {
1855 metafile_write_start (metafile
);
1859 xmlFree (metafile
->write_state
->buffer
);
1860 g_free (metafile
->write_state
);
1861 metafile
->write_state
= NULL
;
1862 g_object_unref (metafile
);
1866 metafile_write_failed (NautilusMetafile
*metafile
)
1868 metafile_write_done (metafile
);
1872 metafile_write_succeeded (NautilusMetafile
*metafile
)
1874 metafile_write_done (metafile
);
1878 write_all (int fd
, const char *buffer
, int size
)
1885 size_remaining
= size
;
1886 while (size_remaining
!= 0) {
1887 result
= write (fd
, p
, size_remaining
);
1888 if (result
<= 0 || result
> size_remaining
) {
1892 size_remaining
-= result
;
1899 metafile_write_local (NautilusMetafile
*metafile
,
1900 const char *metafile_path
)
1906 /* Do this synchronously, since it's likely to be local. Use
1907 * mkstemp to prevent security exploits by making symbolic
1908 * links named .nautilus-metafile.xml.
1911 temp_path
= g_strconcat (metafile_path
, "XXXXXX", NULL
);
1914 fd
= mkstemp (temp_path
);
1918 if (!failed
&& fchmod (fd
, METAFILE_PERMISSIONS
) == -1) {
1921 if (!failed
&& write_all (fd
,
1922 metafile
->write_state
->buffer
,
1923 metafile
->write_state
->size
) == -1) {
1926 if (fd
!= -1 && close (fd
) == -1) {
1929 if (failed
&& fd
!= -1) {
1932 if (!failed
&& rename (temp_path
, metafile_path
) == -1) {
1938 metafile_write_failed (metafile
);
1940 metafile_write_succeeded (metafile
);
1945 metafile_write_start (NautilusMetafile
*metafile
)
1947 const char *metafile_uri
;
1948 char *metafile_path
;
1950 g_assert (NAUTILUS_IS_METAFILE (metafile
));
1952 metafile
->write_state
->write_again
= FALSE
;
1954 metafile_uri
= metafile
->private_uri
;
1956 metafile_path
= g_filename_from_uri (metafile_uri
, NULL
, NULL
);
1957 g_assert (metafile_path
!= NULL
);
1959 metafile_write_local (metafile
, metafile_path
);
1960 g_free (metafile_path
);
1964 metafile_write (NautilusMetafile
*metafile
)
1968 g_assert (NAUTILUS_IS_METAFILE (metafile
));
1970 g_object_ref (metafile
);
1972 /* If we are already writing, then just remember to do it again. */
1973 if (metafile
->write_state
!= NULL
) {
1974 g_object_unref (metafile
);
1975 metafile
->write_state
->write_again
= TRUE
;
1979 /* Don't write anything if there's nothing to write.
1980 * At some point, we might want to change this to actually delete
1981 * the metafile in this case.
1983 if (metafile
->xml
== NULL
) {
1984 g_object_unref (metafile
);
1988 /* Create the write state. */
1989 metafile
->write_state
= g_new0 (MetafileWriteState
, 1);
1990 xmlDocDumpMemory (metafile
->xml
,
1991 &metafile
->write_state
->buffer
,
1993 metafile
->write_state
->size
= xml_doc_size
;
1994 metafile_write_start (metafile
);
1998 metafile_write_idle_callback (gpointer callback_data
)
2000 NautilusMetafile
*metafile
;
2002 metafile
= NAUTILUS_METAFILE (callback_data
);
2004 metafile
->write_idle_id
= 0;
2005 metafile_write (metafile
);
2007 g_object_unref (metafile
);
2013 directory_request_write_metafile (NautilusMetafile
*metafile
)
2015 g_assert (NAUTILUS_IS_METAFILE (metafile
));
2017 if (!allow_metafile (metafile
)) {
2021 /* Set up an idle task that will write the metafile. */
2022 if (metafile
->write_idle_id
== 0) {
2023 g_object_ref (metafile
);
2024 metafile
->write_idle_id
=
2025 g_idle_add (metafile_write_idle_callback
, metafile
);
2030 nautilus_metafile_class_init (NautilusMetafileClass
*klass
)
2032 G_OBJECT_CLASS (klass
)->finalize
= finalize
;
2034 signals
[CHANGED
] = g_signal_new ("changed",
2035 NAUTILUS_TYPE_METAFILE
,
2039 g_cclosure_marshal_VOID__POINTER
,
2040 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
2041 signals
[READY
] = g_signal_new ("ready",
2042 NAUTILUS_TYPE_METAFILE
,
2046 g_cclosure_marshal_VOID__VOID
,