1 --- caja-1.28.0/libcaja-private/caja-column-utilities.c.orig 2024-02-20 01:30:36.000000000 +0100
2 +++ caja-1.28.0/libcaja-private/caja-column-utilities.c 2024-02-26 08:42:41.074153382 +0100
5 caja_module_extension_list_free (providers);
7 + columns = g_list_append (columns,
8 + g_object_new (CAJA_TYPE_COLUMN,
9 + "name", "restore_info",
10 + "attribute", "restore_info",
11 + "label", _("Restore information"),
12 + "description", _("Restore information of the file."),
18 --- caja-1.28.0/libcaja-private/caja-directory-async.c.orig 2024-02-20 01:30:36.000000000 +0100
19 +++ caja-1.28.0/libcaja-private/caja-directory-async.c 2024-02-26 08:46:37.475055194 +0100
21 REQUEST_SET_TYPE (request, REQUEST_FILESYSTEM_INFO);
24 + if (file_attributes & CAJA_FILE_ATTRIBUTE_FILESYSTEM_INFO)
26 + REQUEST_SET_TYPE (request, REQUEST_RESTORE_INFO);
32 @@ -5161,6 +5166,19 @@
37 +caja_directory_cancel_restore_info (CajaDirectory *directory)
39 + if (CAJA_IS_DIRECTORY (directory))
41 + if (directory->details->restore_cancel)
43 + g_cancellable_cancel (directory->details->restore_cancel);
44 + directory->details->restore_cancel = NULL;
50 cancel_loading_attributes (CajaDirectory *directory,
51 CajaFileAttributes file_attributes)
52 @@ -5213,6 +5231,11 @@
53 mount_cancel (directory);
56 + if (REQUEST_WANTS_TYPE (request, REQUEST_RESTORE_INFO))
58 + caja_directory_cancel_restore_info (directory);
61 caja_directory_async_state_changed (directory);
64 @@ -5263,6 +5286,10 @@
66 cancel_mount_for_file (directory, file);
68 + if (REQUEST_WANTS_TYPE (request, REQUEST_RESTORE_INFO))
70 + caja_directory_cancel_restore_info (directory);
73 caja_directory_async_state_changed (directory);
75 --- caja-1.28.0/libcaja-private/caja-directory-private.h.orig 2024-02-20 01:30:36.000000000 +0100
76 +++ caja-1.28.0/libcaja-private/caja-directory-private.h 2024-02-26 08:42:41.075455631 +0100
80 REQUEST_FILESYSTEM_INFO,
81 + REQUEST_RESTORE_INFO,
87 guint64 free_space; /* (guint)-1 for unknown */
88 time_t free_space_read; /* The time free_space was updated, or 0 for never */
90 + GCancellable *restore_cancel;
91 + /* zfs snapshot info */
92 + GList *zfs_snapshots;
95 CajaDirectory *caja_directory_get_existing (GFile *location);
96 --- caja-1.28.0/libcaja-private/caja-directory.c.orig 2024-02-20 01:30:36.000000000 +0100
97 +++ caja-1.28.0/libcaja-private/caja-directory.c 2024-02-26 08:42:41.075943421 +0100
99 #include "caja-metadata.h"
100 #include "caja-desktop-directory.h"
101 #include "caja-vfs-directory.h"
102 +#include "caja-zfs.h"
107 directory->details->low_priority_queue = caja_file_queue_new ();
108 directory->details->extension_queue = caja_file_queue_new ();
109 directory->details->free_space = (guint64)-1;
110 + directory->details->zfs_snapshots = NULL;
111 + directory->details->restore_cancel = NULL;
116 g_assert (directory->details->file_list == NULL);
117 g_hash_table_destroy (directory->details->file_hash);
119 + if (directory->details->zfs_snapshots)
121 + ts_free_snapshots (directory->details->zfs_snapshots);
124 + if (directory->details->restore_cancel)
126 + g_cancellable_cancel (directory->details->restore_cancel);
129 caja_file_queue_destroy (directory->details->high_priority_queue);
130 caja_file_queue_destroy (directory->details->low_priority_queue);
131 caja_file_queue_destroy (directory->details->extension_queue);
133 caja_file_list_free (files);
137 +time_slider_enabled = TRUE;
140 +caja_is_time_slider_enabled ()
142 + return time_slider_enabled;
145 +static void time_slider_pref_changed_callback (gpointer callback_data)
147 + time_slider_enabled = g_settings_get_boolean (caja_preferences,
148 + CAJA_PREFERENCES_ENABLE_TIME_SLIDER);
152 collect_all_directories (gpointer key, gpointer value, gpointer callback_data)
156 CajaDirectory *directory;
160 uri = g_file_get_uri (location);
165 directory = CAJA_DIRECTORY (g_object_new (CAJA_TYPE_VFS_DIRECTORY, NULL));
166 + path = g_file_get_path (location);
170 set_directory_location (directory, location);
171 @@ -495,6 +526,206 @@
172 g_file_is_native (directory->details->location);
177 + CajaDirectory *dir;
178 + GCancellable *cancel;
179 + TsReadyCallback callback;
180 + gpointer callback_user_data;
181 +} QuerySnapshotsAsyncData;
185 +snapshot_list_ready_callback (GObject *source_object,
187 + gpointer user_data)
189 + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
190 + QuerySnapshotsAsyncData *data = (QuerySnapshotsAsyncData*) user_data;
192 + if (!g_cancellable_is_cancelled (data->cancel))
194 + data->dir->details->zfs_snapshots = g_simple_async_result_get_op_res_gpointer (simple);
197 + data->callback (data->dir, data->cancel, data->callback_user_data);
201 +caja_directory_get_snapshots_async (CajaDirectory *directory,
202 + TsReadyCallback ready_callback,
203 + GCancellable *cancel,
204 + gpointer callback_user_data)
206 + g_assert (CAJA_IS_DIRECTORY (directory));
208 + if (directory->details->location == NULL)
211 + if (directory->details->zfs_snapshots)
213 + ts_free_snapshots (directory->details->zfs_snapshots);
214 + directory->details->zfs_snapshots = NULL;
217 + if (caja_is_time_slider_enabled ())
219 + QuerySnapshotsAsyncData *data;
220 + data = g_new0 (QuerySnapshotsAsyncData,1);
221 + data->dir = directory;
222 + data->cancel = cancel;
223 + data->callback = ready_callback;
224 + data->callback_user_data = callback_user_data;
226 + ts_get_snapshots_for_dir_async (directory->details->location,
227 + snapshot_list_ready_callback,
234 +caja_directory_has_snapshots (CajaDirectory *directory)
236 + g_assert (CAJA_IS_DIRECTORY (directory));
238 + if (directory->details->zfs_snapshots)
245 +caja_directory_get_num_snapshots (CajaDirectory *directory)
247 + g_assert (CAJA_IS_DIRECTORY (directory));
249 + if (directory->details->zfs_snapshots)
253 + for (tmp = directory->details->zfs_snapshots;tmp;tmp = tmp->next)
261 +caja_directory_is_in_snapshot (CajaDirectory *directory)
263 + char *directory_uri;
264 + gboolean result = FALSE;
266 + g_return_val_if_fail (CAJA_IS_DIRECTORY (directory), FALSE);
268 + directory_uri = caja_directory_get_uri (directory);
270 + result = ts_is_in_snapshot (directory_uri);
272 + g_free (directory_uri);
278 +caja_directory_get_snapshots (CajaDirectory *directory)
280 + g_assert (CAJA_IS_DIRECTORY (directory));
282 + return directory->details->zfs_snapshots;
286 +caja_directory_remove_snapshot (CajaDirectory *directory,
289 + if (directory->details->zfs_snapshots)
291 + directory->details->zfs_snapshots = g_list_remove (directory->details->zfs_snapshots, snap);
292 + ts_free_zfs_dataset (snap);
296 +/* return true if snapdir dir path is a dir or subdir of refdir */
298 +caja_directory_is_a_snapshot_dir_of (CajaDirectory *snapdir,
299 + CajaDirectory *refdir)
302 + gboolean result = FALSE;
304 + if (caja_directory_is_in_snapshot (snapdir))
306 + char snapdir_root_real_path [PATH_MAX+1];
307 + char refdir_real_path [PATH_MAX+1];
308 + CajaDirectory *snapdir_root = caja_directory_get_snap_root (snapdir);
309 + GFile *snapdir_root_file = caja_directory_get_location (snapdir_root);
310 + GFile *refdir_file = caja_directory_get_location (refdir);
311 + char* snapdir_root_path = g_file_get_path (snapdir_root_file);
312 + char* refdir_path = g_file_get_path (refdir_file);
314 + if (ts_realpath (snapdir_root_path, snapdir_root_real_path) &&
315 + ts_realpath (refdir_path, refdir_real_path))
317 + if (g_strrstr (snapdir_root_real_path,refdir_real_path))
321 + g_free (snapdir_root_path);
322 + g_free (refdir_path);
323 + g_object_unref (snapdir_root_file);
324 + g_object_unref (refdir_file);
325 + g_object_unref (snapdir_root);
332 +caja_directory_get_snap_root (CajaDirectory *directory)
334 + char *directory_uri, *snap_root;
337 + CajaDirectory *new_dir;
339 + g_assert (CAJA_IS_DIRECTORY (directory));
341 + directory_uri = caja_directory_get_uri (directory);
344 + if (!caja_directory_is_in_snapshot (directory))
346 + g_free (directory_uri);
350 + /*remove .zfs/snapshot/blah/ */
351 + zfs = g_strrstr (directory_uri, ".zfs/snapshot/");
356 + iter += sizeof (".zfs/snapshot/");
357 + while (*iter != '/' && *iter != '\0')
364 + snap_root = g_strdup_printf ("%s%s", directory_uri, iter);
367 + g_free (directory_uri);
368 + new_dir = caja_directory_get_by_uri (snap_root);
369 + g_free (snap_root);
376 caja_directory_is_in_trash (CajaDirectory *directory)
378 --- caja-1.28.0/libcaja-private/caja-directory.h.orig 2024-02-20 01:30:36.000000000 +0100
379 +++ caja-1.28.0/libcaja-private/caja-directory.h 2024-02-26 08:42:41.076213417 +0100
383 #include "caja-file-attributes.h"
384 +#include "caja-zfs.h"
390 gboolean caja_directory_is_in_trash (CajaDirectory *directory);
392 +/* ZFS snasphots management. */
393 +typedef void (*TsReadyCallback) (CajaDirectory *directory, GCancellable *cancellable, gpointer callback_data);
395 +void caja_directory_get_snapshots_async (CajaDirectory *directory,
396 + TsReadyCallback ready_callback,
397 + GCancellable *cancel,
398 + gpointer callback_user_data);
399 +gboolean caja_directory_has_snapshots (CajaDirectory *directory);
400 +gboolean caja_directory_is_in_snapshot (CajaDirectory *directory);
401 +int caja_directory_get_num_snapshots (CajaDirectory *directory);
402 +GList * caja_directory_get_snapshots (CajaDirectory *directory);
403 +void caja_directory_remove_snapshot (CajaDirectory *directory,
405 +CajaDirectory * caja_directory_get_snap_root (CajaDirectory *directory);
406 +gboolean caja_directory_is_a_snapshot_dir_of (CajaDirectory *snapdir,
407 + CajaDirectory *refdir);
408 +void caja_directory_cancel_restore_info (CajaDirectory *directory);
410 /* Return false if directory contains anything besides a Caja metafile.
411 * Only valid if directory is monitored. Used by the Trash monitor.
415 gboolean caja_directory_is_editable (CajaDirectory *directory);
417 +gboolean caja_is_time_slider_enabled ();
421 #endif /* CAJA_DIRECTORY_H */
422 --- caja-1.28.0/libcaja-private/caja-file-attributes.h.orig 2024-02-20 01:30:36.000000000 +0100
423 +++ caja-1.28.0/libcaja-private/caja-file-attributes.h 2024-02-26 08:42:41.076404101 +0100
425 CAJA_FILE_ATTRIBUTE_THUMBNAIL = 1 << 8,
426 CAJA_FILE_ATTRIBUTE_MOUNT = 1 << 9,
427 CAJA_FILE_ATTRIBUTE_FILESYSTEM_INFO = 1 << 10,
428 + CAJA_FILE_ATTRIBUTE_RESTORE_INFO = 1 << 12,
429 } CajaFileAttributes;
431 #endif /* CAJA_FILE_ATTRIBUTES_H */
432 --- caja-1.28.0/libcaja-private/caja-file-private.h.orig 2024-02-20 01:30:36.000000000 +0100
433 +++ caja-1.28.0/libcaja-private/caja-file-private.h 2024-02-26 08:42:41.076641510 +0100
435 /* Mount for mountpoint or the references GMount for a "mountable" */
438 + /* Time slider file difference information */
439 + char *restore_info;
441 + /* Snapshot directory for versions */
442 + char *snapshot_directory;
443 + GCancellable *has_snapshot_cancel;
445 /* boolean fields: bitfield to save space, since there can be
446 many CajaFile objects. */
450 eel_boolean_bit is_thumbnailing : 1;
452 + eel_boolean_bit restore_info_is_up_to_date : 1;
453 + eel_boolean_bit restore_info_in_progress : 1;
455 + eel_boolean_bit has_snap_versions_is_up_to_date : 1;
456 + eel_boolean_bit has_snap_versions_in_progress : 1;
457 + eel_boolean_bit has_snap_versions : 1;
459 /* TRUE if the file is open in a spatial window */
460 eel_boolean_bit has_open_window : 1;
462 --- caja-1.28.0/libcaja-private/caja-file.c.orig 2024-02-20 01:30:36.000000000 +0100
463 +++ caja-1.28.0/libcaja-private/caja-file.c 2024-02-26 08:42:41.077938703 +0100
465 #include "caja-ui-utilities.h"
466 #include "caja-vfs-file.h"
467 #include "caja-saved-search-file.h"
468 +#include "caja-zfs.h"
471 #include <selinux/selinux.h>
474 attribute_link_target_q,
476 - attribute_free_space_q;
477 + attribute_free_space_q,
478 + attribute_restore_info_q;;
480 static void caja_file_info_iface_init (CajaFileInfoIface *iface);
481 static char * caja_file_get_owner_as_string (CajaFile *file,
484 static const char * caja_file_peek_display_name (CajaFile *file);
485 static const char * caja_file_peek_display_name_collation_key (CajaFile *file);
486 +static void invalidate_restore_info (CajaFile *file);
487 static void file_mount_unmounted (GMount *mount, gpointer data);
488 static void metadata_hash_free (GHashTable *hash);
491 g_clear_pointer (&file->details->filesystem_id, g_ref_string_release);
492 file->details->filesystem_id = NULL;
494 + g_free (file->details->restore_info);
495 + file->details->restore_info = NULL;
496 + invalidate_restore_info (file);
497 + g_free (file->details->snapshot_directory);
498 + file->details->snapshot_directory = NULL;
499 + file->details->has_snap_versions_in_progress = FALSE;
500 + file->details->has_snap_versions_is_up_to_date = FALSE;
501 + file->details->has_snap_versions = FALSE;
503 clear_metadata (file);
507 g_free (file->details->activation_uri);
508 g_free (file->details->compare_by_emblem_cache);
510 + g_free (file->details->restore_info);
511 + if (file->details->snapshot_directory) {
512 + g_free (file->details->snapshot_directory);
515 if (file->details->thumbnail) {
516 g_object_unref (file->details->thumbnail);
518 @@ -4835,6 +4852,242 @@
522 +/* Following code is copied from Rhythmbox rb-cut-and-paste-code.c */
524 +/* Legal conversion specifiers, as specified in the C standard. */
525 +#define C_STANDARD_STRFTIME_CHARACTERS "aAbBcdHIjmMpSUwWxXyYZ"
526 +#define C_STANDARD_NUMERIC_STRFTIME_CHARACTERS "dHIjmMSUwWyY"
527 +#define SUS_EXTENDED_STRFTIME_MODIFIERS "EO"
530 + * eel_strdup_strftime:
532 + * Cover for standard date-and-time-formatting routine strftime that returns
533 + * a newly-allocated string of the correct size. The caller is responsible
534 + * for g_free-ing the returned string.
536 + * Besides the buffer management, there are two differences between this
537 + * and the library strftime:
539 + * 1) The modifiers "-" and "_" between a "%" and a numeric directive
540 + * are defined as for the GNU version of strftime. "-" means "do not
541 + * pad the field" and "_" means "pad with spaces instead of zeroes".
542 + * 2) Non-ANSI extensions to strftime are flagged at runtime with a
543 + * warning, so it's easy to notice use of the extensions without
544 + * testing with multiple versions of the library.
546 + * @format: format string to pass to strftime. See strftime documentation
548 + * @time_pieces: date/time, in struct format.
550 + * Return value: Newly allocated string containing the formatted time.
554 +eel_strdup_strftime (const char *format, struct tm *time_pieces)
556 + g_autoptr(GString) string = NULL;
557 + const char *remainder, *percent;
558 + char code[4], buffer[512];
559 + char *piece, *result;
560 + g_autofree gchar *converted = NULL;
561 + size_t string_length;
562 + gboolean strip_leading_zeros, turn_leading_zeros_to_spaces;
566 + /* Format could be translated, and contain UTF-8 chars,
567 + * so convert to locale encoding which strftime uses */
568 + converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
570 + converted = g_strdup (format);
572 + string = g_string_new ("");
573 + remainder = converted;
575 + /* Walk from % character to % character. */
577 + percent = strchr (remainder, '%');
578 + if (percent == NULL) {
579 + g_string_append (string, remainder);
582 + g_string_append_len (string, remainder,
583 + percent - remainder);
585 + /* Handle the "%" character. */
586 + remainder = percent + 1;
587 + switch (*remainder) {
589 + strip_leading_zeros = TRUE;
590 + turn_leading_zeros_to_spaces = FALSE;
594 + strip_leading_zeros = FALSE;
595 + turn_leading_zeros_to_spaces = TRUE;
599 + g_string_append_c (string, '%');
603 + g_warning ("Trailing %% passed to eel_strdup_strftime");
604 + g_string_append_c (string, '%');
607 + strip_leading_zeros = FALSE;
608 + turn_leading_zeros_to_spaces = FALSE;
613 + if (strchr (SUS_EXTENDED_STRFTIME_MODIFIERS, *remainder) != NULL) {
614 + modifier = *remainder;
617 + if (*remainder == 0) {
618 + g_warning ("Unfinished %%%c modifier passed to eel_strdup_strftime", modifier);
623 + if (strchr (C_STANDARD_STRFTIME_CHARACTERS, *remainder) == NULL) {
624 + g_warning ("eel_strdup_strftime does not support "
625 + "non-standard escape code %%%c",
629 + /* Convert code to strftime format. We have a fixed
630 + * limit here that each code can expand to a maximum
631 + * of 512 bytes, which is probably OK. There's no
632 + * limit on the total size of the result string.
636 + if (modifier != 0) {
637 +#ifdef HAVE_STRFTIME_EXTENSION
638 + code[i++] = modifier;
641 + code[i++] = *remainder;
643 +#pragma GCC diagnostic push
644 +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
645 + /* Format string under control of caller, since this is a wrapper for strftime. */
646 + string_length = strftime (buffer, sizeof (buffer),
647 + code, time_pieces);
648 +#pragma GCC diagnostic pop
649 + if (string_length == 0) {
650 + /* We could put a warning here, but there's no
651 + * way to tell a successful conversion to
652 + * empty string from a failure.
657 + /* Strip leading zeros if requested. */
659 + if (strip_leading_zeros || turn_leading_zeros_to_spaces) {
660 + if (strchr (C_STANDARD_NUMERIC_STRFTIME_CHARACTERS, *remainder) == NULL) {
661 + g_warning ("eel_strdup_strftime does not support "
662 + "modifier for non-numeric escape code %%%c%c",
666 + if (*piece == '0') {
669 + } while (*piece == '0');
670 + if (!g_ascii_isdigit (*piece)) {
674 + if (turn_leading_zeros_to_spaces) {
675 + memset (buffer, ' ', piece - buffer);
681 + /* Add this piece. */
682 + g_string_append (string, piece);
685 + /* Convert the string back into utf-8. */
686 + result = g_locale_to_utf8 (string->str, -1, NULL, NULL, NULL);
692 +caja_date_as_string (time_t time_raw, gboolean use_smallest)
695 + const char **formats;
696 + const char *width_template;
697 + const char *format;
705 + ttime = localtime (&time_raw);
707 + if (!use_smallest) {
708 + if (date_format_pref == CAJA_DATE_FORMAT_LOCALE) {
709 + return eel_strdup_strftime ("%c", ttime);
710 + } else if (date_format_pref == CAJA_DATE_FORMAT_ISO) {
711 + return eel_strdup_strftime ("%Y-%m-%d %H:%M:%S",ttime);
715 + date = g_date_new ();
716 + g_date_set_time_t (date, time_raw);
718 + today = g_date_new ();
719 + g_date_set_time_t (today, time (NULL));
721 + /* Overflow results in a large number; fine for our purposes. */
722 + date_age = (g_date_get_julian (today) -
723 + g_date_get_julian (date));
725 + g_date_free (date);
726 + g_date_free (today);
728 + /* Format varies depending on how old the date is. This minimizes
729 + * the length (and thus clutter & complication) of typical dates
730 + * while providing sufficient detail for recent dates to make
731 + * them maximally understandable at a glance. Keep all format
732 + * strings separate rather than combining bits & pieces for
733 + * internationalization's sake.
736 + if (date_age == 0) {
737 + formats = TODAY_TIME_FORMATS;
738 + } else if (date_age == 1) {
739 + formats = YESTERDAY_TIME_FORMATS;
740 + } else if (date_age < 7) {
741 + formats = CURRENT_WEEK_TIME_FORMATS;
743 + formats = CURRENT_WEEK_TIME_FORMATS;
747 + format = _(formats[1]);
751 + while (formats[i] != NULL)
753 + format = _(formats[i-3]);
755 + return eel_strdup_strftime (format, ttime);
759 caja_file_fit_date_as_string (CajaFile *file,
760 CajaDateType date_type,
761 @@ -6608,6 +6861,9 @@
762 if (attribute_q == attribute_free_space_q) {
763 return caja_file_get_volume_free_space (file);
765 + if (attribute_q == attribute_restore_info_q) {
766 + return caja_file_get_restore_info_async (file);
769 extension_attribute = NULL;
771 @@ -7654,6 +7910,616 @@
777 +caja_file_is_in_snapshot (CajaFile *file)
779 + char *file_uri = caja_file_get_uri (file);
780 + gboolean result = ts_is_in_snapshot (file_uri);
785 +static gboolean caja_file_in_snap_exist_in_current (CajaFile *file, GCancellable *cancel)
787 + /* get path without /.zfs/snapshot/blah/ */
788 + /* test is file exist */
789 + char *file_uri = caja_file_get_uri (file);
790 + char *file_uri_without_snap = NULL;
791 + gboolean result = FALSE;
793 + if (g_cancellable_is_cancelled (cancel))
799 + file_uri_without_snap = ts_remove_snapshot_dir (file_uri);
801 + if (file_uri_without_snap)
803 + GFile* root_file = g_file_new_for_uri (file_uri_without_snap);
804 + char *path = g_file_get_path (root_file);
808 + result = g_file_test (path, G_FILE_TEST_EXISTS);
811 + g_object_unref (root_file);
812 + g_free (file_uri_without_snap);
822 +char * caja_file_in_snapshot_get_info (CajaFile *file, GCancellable *cancel)
825 + GFile *then_gfile = caja_file_get_location (file);
826 + char *then_path = g_file_get_path (then_gfile);
827 + g_object_unref (then_gfile);
829 + if (g_cancellable_is_cancelled (cancel))
831 + g_free (then_gfile);
832 + g_free (then_path);
833 + return g_strdup ("cancelled");
838 + struct stat64 then;
839 + char *now_path = ts_remove_snapshot_dir (then_path);
841 + if (lstat64 (now_path, &now) == 0)
843 + if (lstat64 (then_path, &then) == 0)
846 + if (now.st_mtime != then.st_mtime)
848 + if (now.st_size == then.st_size)
850 + info = g_strdup (_("different date, same size as latest version"));
851 + else if (now.st_size > then.st_size)
853 + info = g_strdup (_("different date, smaller than latest version"));
854 + else if ( now.st_size < then.st_size)
856 + info = g_strdup (_("different date, bigger than latest version"));
860 + info = g_strdup (_("identical to latest version"));
863 + info = g_strdup_printf ("FIXME no then %s", then_path);
867 + info = g_strdup (_("not present in latest version"));
870 + g_free (then_path);
876 +static char * restore_string (char *str, GCancellable *cancel)
878 + if (g_cancellable_is_cancelled (cancel))
881 + return g_strdup (_("unknown"));
887 +gint time_cmp (time_t *a,
900 +caja_file_get_num_snapshot_version (CajaFile *file,
901 + GCancellable *cancel,
902 + gboolean stop_at_first)
905 + GList *tmp2 = NULL;
906 + GList *time = NULL;
907 + time_t* now_time = NULL;
908 + char *result = NULL;
910 + CajaFile *parent = NULL;
911 + CajaDirectory *dir = NULL;
912 + char *snapdir = NULL;
914 + if (CAJA_IS_FILE (file))
916 + parent = caja_file_get_parent (file);
919 + dir = caja_directory_get_for_file (parent);
920 + g_object_unref (parent);
926 + struct stat64 then;
927 + char snap_name[PATH_MAX+1];
928 + char *name = caja_file_get_name (file);
930 + g_object_ref (dir);
931 + tmp = caja_directory_get_snapshots (dir);
933 + GFile *now_gfile = caja_file_get_location (file);
934 + char *now_path = g_file_get_path (now_gfile);
935 + g_object_unref (now_gfile);
939 + if (lstat64 (now_path, &now) != 0)
942 + g_object_unref (dir);
951 + /* get list of mtime for all files in snapshots */
953 + now_time = g_new0 (time_t, 1);
954 + *now_time = now.st_mtim.tv_sec;
955 + time = g_list_prepend (time, now_time);
958 + for (tmp; tmp; tmp = tmp->next)
960 + g_snprintf (snap_name, sizeof(snap_name), "%s/%s",
961 + ((ZfsDataSet *) tmp->data)->mountpoint,
963 + if (g_cancellable_is_cancelled (cancel))
965 + if (lstat64 (snap_name, &then) == 0)
967 + if (g_list_find_custom (time, &then.st_mtim.tv_sec, (GCompareFunc) time_cmp) == NULL)
968 + { /*insert in list only is unique */
969 + time_t* snap_time = g_new0 (time_t, 1);
970 + *snap_time = then.st_mtim.tv_sec;
971 + time = g_list_prepend (time, snap_time);
974 + snapdir = g_strdup (((ZfsDataSet *) tmp->data)->mountpoint);
983 + g_object_unref (dir);
987 + for (tmp = time; tmp; tmp = tmp->next)
989 + g_free ((time_t*) tmp->data);
993 + /* remove current version */
996 + g_list_free (time);
1000 + if (stop_at_first)
1002 + else /*SUN_BRANDING*/
1003 + return restore_string (g_strdup_printf (_("no other version")), cancel);
1006 + if (stop_at_first)
1009 + return restore_string (g_strdup_printf ("%d %s", version,
1010 + /* SUN_BRANDING */
1011 + version > 1 ? _("other versions") : /* SUN_BRANDING */ _("other version")),
1015 +static gboolean worker_thread_started = FALSE;
1017 +typedef void (*ReadyCallback) (gpointer data,
1018 + GCancellable *cancellable);
1019 +typedef void (*WorkerFunction) (gpointer data,
1020 + GCancellable *cancellable);
1023 + gpointer return_data;
1024 + ReadyCallback ready_callback;
1025 + WorkerFunction worker_func;
1026 + GCancellable *cancellable;
1030 +caja_file_get_restore_info (gpointer data,
1031 + GCancellable *cancellable)
1033 + QueryData *qdata = (QueryData*) data;
1034 + CajaFile *file = CAJA_FILE (qdata->data);
1035 + char *result = NULL;
1038 + struct timespec ts;
1041 + nanosleep (&ts, NULL);
1045 + GFile *f = caja_file_get_location (file);
1046 + char *path = g_file_get_uri (f);
1047 + printf ("start restore info for %s", path);
1049 + g_object_unref (f);
1051 + if (!g_cancellable_is_cancelled (cancellable))
1054 + if (caja_file_is_directory (file))
1056 + CajaDirectory *dir = caja_directory_get_for_file (file);
1057 + g_object_ref (dir);
1058 + if (caja_directory_is_in_snapshot (dir))
1060 + if (!caja_file_in_snap_exist_in_current (file, cancellable))
1061 + /* SUN_BRANDING */
1062 + result = g_strdup (_("not present in latest version"));
1064 + /* SUN_BRANDING */
1065 + result = g_strdup (_("present in latest version"));
1069 + int version = caja_directory_get_num_snapshots (dir);
1072 + /* SUN_BRANDING */
1073 + result = g_strdup (_("no version"));
1075 + result = g_strdup_printf ("%d %s",version,
1076 + /* SUN_BRANDING */
1077 + version > 1 ? _("versions") : /* SUN_BRANDING */ _("version"));
1079 + g_object_unref (dir);
1083 + if (caja_file_is_in_snapshot (file))
1084 + result = caja_file_in_snapshot_get_info (file, cancellable);
1086 + result = caja_file_get_num_snapshot_version (file, cancellable, FALSE);
1091 + printf ("is %s\n", result);
1095 + qdata->return_data = restore_string (result, cancellable);
1099 +static void restore_information_ready_callback (gpointer data,
1100 + GCancellable *cancellable)
1102 + QueryData *qdata = (QueryData*) data;
1103 + CajaFile *file = (CajaFile*) qdata->data;
1104 + char *return_data = qdata->return_data;
1106 + if (!CAJA_IS_FILE (file))
1109 + file->details->restore_info_in_progress = FALSE;
1111 + if (g_cancellable_is_cancelled (cancellable))
1113 + file->details->restore_info = g_strdup (_("unknown"));
1114 + invalidate_restore_info (file);
1116 + g_free (return_data);
1120 + file->details->restore_info_is_up_to_date = TRUE;
1121 + file->details->restore_info = return_data;
1124 + caja_file_changed (file);
1125 + caja_file_unref (file);
1130 +complete_in_idle_cb (gpointer data)
1132 + QueryData *qdata = (QueryData*)data;
1133 + qdata->ready_callback (data, qdata->cancellable);
1139 +worker_queue_finished_callback (GObject *source_object,
1140 + GAsyncResult *res,
1141 + gpointer user_data)
1143 + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
1144 + GCancellable *cancel = (GCancellable*) user_data;
1146 + worker_thread_started = FALSE;
1148 + if (g_cancellable_is_cancelled (cancel))
1153 + g_simple_async_result_get_op_res_gpointer (simple);
1158 +worker_queue_func (GSimpleAsyncResult *res,
1160 + GCancellable *cancellable)
1162 + QueryData *data = NULL;
1165 + GAsyncQueue *queue = (GAsyncQueue*) g_simple_async_result_get_op_res_gpointer (res);
1166 + g_async_queue_ref (queue);
1168 + g_get_current_time (&timeout);
1169 + g_time_val_add (&timeout, 3000000);
1171 + data = g_async_queue_timed_pop (queue, &timeout);
1177 + /* only call the worker fct if not cancel
1178 + * but execute ready function anyway */
1179 + if (!g_cancellable_is_cancelled (data->cancellable))
1180 + data->worker_func (data, data->cancellable);
1182 + /*call ready callback in main loop/thread */
1183 + source = g_idle_source_new ();
1184 + g_source_set_priority (source, G_PRIORITY_DEFAULT);
1185 + g_source_set_callback (source, complete_in_idle_cb, data, NULL);
1186 + g_source_attach (source, NULL);
1187 + g_source_unref (source);
1189 + /* pop next one */
1190 + g_get_current_time (&timeout);
1191 + g_time_val_add (&timeout, 3000000);
1192 + data = g_async_queue_timed_pop (queue, &timeout);
1195 + g_async_queue_unref (queue);
1198 +char * caja_file_get_restore_info_async (CajaFile *file)
1200 + if (!caja_is_time_slider_enabled ())
1203 + if (!ts_is_restore_column_enabled ())
1206 + if (file->details->restore_info_is_up_to_date)
1208 + /*if ( file->details->restore_info == NULL)
1209 + return g_strdup ("null cached info");*/
1210 + return g_strdup (file->details->restore_info);
1213 + if (file->details->restore_info_in_progress)
1214 + return g_strdup ("...");
1217 + static GAsyncQueue *queue = NULL;
1218 + QueryData *data = NULL;
1220 + if (!file->details->directory)
1221 + return g_strdup ("no directory element\n");
1223 + if (!caja_directory_has_snapshots (file->details->directory) && !caja_file_is_in_snapshot (file))
1224 + return g_strdup ("doesn't have snap nor is in snap\n");
1226 + if (!file->details->directory->details->restore_cancel)
1228 + file->details->directory->details->restore_cancel = g_cancellable_new ();
1232 + if (g_cancellable_is_cancelled (file->details->directory->details->restore_cancel))
1236 + g_free (file->details->restore_info);
1237 + file->details->restore_info = NULL;
1238 + file->details->restore_info_in_progress = TRUE;
1241 + queue = g_async_queue_new ();
1243 + data = g_new0 (QueryData, 1);
1244 + data->data = file;
1245 + caja_file_ref (file);
1246 + data->cancellable = file->details->directory->details->restore_cancel;
1247 + data->ready_callback = restore_information_ready_callback;
1248 + data->worker_func = caja_file_get_restore_info;
1250 + g_async_queue_push (queue, data);
1252 + if (!worker_thread_started)
1254 + GSimpleAsyncResult *res;
1255 + worker_thread_started = TRUE;
1257 + res = g_simple_async_result_new (G_OBJECT (file),
1258 + worker_queue_finished_callback,
1260 + (gpointer) worker_queue_func);
1262 + g_simple_async_result_set_op_res_gpointer (res, queue, NULL);
1263 + g_simple_async_result_run_in_thread (res,
1264 + worker_queue_func,
1265 + G_PRIORITY_DEFAULT,
1266 + data->cancellable);
1269 + return g_strdup ("...");
1274 +caja_file_has_snapshot_version (CajaFile *file)
1276 + if (file->details->has_snap_versions_is_up_to_date)
1277 + return (file->details->has_snap_versions);
1278 + return UNKNOWN_STATE;
1283 + GCancellable *cancel;
1284 + FileHasSnapshotCallback callback;
1285 + gpointer callback_user_data;
1287 +} HasSnapshotAsyncData;
1289 +typedef void (*HasSnapReadyCallback) (CajaDirectory *file,
1290 + GCancellable *cancel,
1291 + gpointer callback_data);
1294 +static void has_snapshot_ready_callback (GObject *source_object,
1295 + GAsyncResult *res,
1296 + gpointer user_data)
1298 + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
1299 + HasSnapshotAsyncData *data = (HasSnapshotAsyncData*) user_data;
1301 + if (g_cancellable_is_cancelled (data->cancel))
1303 + data->file->details->has_snap_versions_in_progress = FALSE;
1304 + data->file->details->has_snap_versions_is_up_to_date = FALSE;
1305 + if (data->file->details->snapshot_directory)
1306 + g_free (data->file->details->snapshot_directory);
1308 + data->file->details->has_snapshot_cancel = NULL;
1312 + data->file->details->has_snap_versions_in_progress = FALSE;
1313 + data->file->details->has_snap_versions_is_up_to_date = TRUE;
1314 + if (data->file->details->snapshot_directory)
1315 + g_free (data->file->details->snapshot_directory);
1316 + data->file->details->snapshot_directory = g_simple_async_result_get_op_res_gpointer (simple);
1317 + if (data->file->details->snapshot_directory)
1318 + data->file->details->has_snap_versions = TRUE;
1320 + data->file->details->has_snap_versions = FALSE;
1322 + data->callback (data->callback_user_data);
1325 +caja_file_get_snapshot_dir (CajaFile *file)
1327 + return file->details->snapshot_directory;
1329 +void caja_file_real_get_snapshot_version (GSimpleAsyncResult *res,
1331 + GCancellable *cancellable)
1333 + CajaFile *file = CAJA_FILE (object);
1334 + char *snap_info = caja_file_get_num_snapshot_version (file, cancellable, TRUE);
1336 + if (!snap_info) /* scan for .zfs directory*/
1337 + snap_info = ts_get_not_zfs_snapshot_dir (caja_file_get_location (file));
1340 + struct timespec ts;
1343 + nanosleep (&ts, NULL);
1347 + g_simple_async_result_set_op_res_gpointer (res, snap_info, (GDestroyNotify) NULL);
1349 + g_simple_async_result_set_op_res_gpointer (res, NULL, (GDestroyNotify) NULL);
1352 +void caja_file_get_snapshot_version (CajaFile *file,
1353 + FileHasSnapshotCallback callback,
1354 + GCancellable *cancel,
1355 + gpointer user_data)
1357 + HasSnapshotAsyncData *data;
1358 + GSimpleAsyncResult *res;
1360 + if (file->details->has_snap_versions_in_progress)
1362 + g_cancellable_cancel(file->details->has_snapshot_cancel);
1363 + file->details->has_snapshot_cancel = NULL;
1364 + file->details->has_snap_versions_in_progress = FALSE;
1367 + file->details->has_snapshot_cancel = cancel;
1368 + file->details->has_snap_versions_in_progress = TRUE;
1369 + file->details->has_snap_versions_is_up_to_date = FALSE;
1371 + data = g_new0 (HasSnapshotAsyncData, 1);
1372 + data->file = file;
1373 + data->cancel = cancel;
1374 + data->callback = callback;
1375 + data->callback_user_data = user_data;
1377 + res = g_simple_async_result_new (G_OBJECT (file),
1378 + has_snapshot_ready_callback,
1380 + (gpointer) caja_file_real_get_snapshot_version);
1381 + g_simple_async_result_run_in_thread (res, caja_file_real_get_snapshot_version,
1382 + G_PRIORITY_DEFAULT, cancel);
1386 caja_file_mark_gone (CajaFile *file)
1388 @@ -7920,6 +8786,12 @@
1389 file->details->mount_is_up_to_date = FALSE;
1393 +invalidate_restore_info (CajaFile *file)
1395 + file->details->restore_info_is_up_to_date = FALSE;
1399 caja_file_invalidate_extension_info_internal (CajaFile *file)
1401 @@ -7974,6 +8846,9 @@
1402 if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
1403 invalidate_thumbnail (file);
1405 + if (REQUEST_WANTS_TYPE (request, REQUEST_RESTORE_INFO)) {
1406 + invalidate_restore_info (file);
1408 if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
1409 invalidate_mount (file);
1411 @@ -8054,7 +8929,8 @@
1412 CAJA_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT |
1413 CAJA_FILE_ATTRIBUTE_EXTENSION_INFO |
1414 CAJA_FILE_ATTRIBUTE_THUMBNAIL |
1415 - CAJA_FILE_ATTRIBUTE_MOUNT;
1416 + CAJA_FILE_ATTRIBUTE_MOUNT |
1417 + CAJA_FILE_ATTRIBUTE_RESTORE_INFO ;
1421 @@ -8621,6 +9497,7 @@
1422 attribute_link_target_q = g_quark_from_static_string ("link_target");
1423 attribute_volume_q = g_quark_from_static_string ("volume");
1424 attribute_free_space_q = g_quark_from_static_string ("free_space");
1425 + attribute_restore_info_q = g_quark_from_static_string ("restore_info");
1427 G_OBJECT_CLASS (class)->finalize = finalize;
1428 G_OBJECT_CLASS (class)->constructor = caja_file_constructor;
1429 --- caja-1.28.0/libcaja-private/caja-file.h.orig 2024-02-20 01:30:36.000000000 +0100
1430 +++ caja-1.28.0/libcaja-private/caja-file.h 2024-02-26 08:42:41.078215891 +0100
1432 const char *mime_type);
1433 gboolean caja_file_is_launchable (CajaFile *file);
1434 gboolean caja_file_is_symbolic_link (CajaFile *file);
1435 +gboolean caja_file_is_in_snapshot (CajaFile *file);
1436 gboolean caja_file_is_mountpoint (CajaFile *file);
1437 GMount * caja_file_get_mount (CajaFile *file);
1438 char * caja_file_get_volume_free_space (CajaFile *file);
1439 @@ -250,6 +251,27 @@
1441 CajaFile * caja_file_get_trash_original_file (CajaFile *file);
1444 +char * caja_file_get_num_snapshot_version (CajaFile *file,
1445 + GCancellable *cancel,
1446 + gboolean stop_at_first);
1447 +char * caja_file_get_restore_info_async (CajaFile *file);
1453 +} HasSnapshotResult;
1455 +HasSnapshotResult caja_file_has_snapshot_version (CajaFile *file);
1456 +char * caja_file_get_snapshot_dir (CajaFile *file);
1457 +typedef void (*FileHasSnapshotCallback) (gpointer user_data);
1459 +void caja_file_get_snapshot_version (CajaFile *file,
1460 + FileHasSnapshotCallback callback,
1461 + GCancellable *cancel,
1462 + gpointer user_data);
1465 gboolean caja_file_can_get_permissions (CajaFile *file);
1466 gboolean caja_file_can_set_permissions (CajaFile *file);
1467 --- caja-1.28.0/libcaja-private/caja-global-preferences.h.orig 2024-02-20 01:30:36.000000000 +0100
1468 +++ caja-1.28.0/libcaja-private/caja-global-preferences.h 2024-02-26 08:42:41.078422380 +0100
1470 #define CAJA_PREFERENCES_USE_IEC_UNITS "use-iec-units"
1471 #define CAJA_PREFERENCES_SHOW_ICONS_IN_LIST_VIEW "show-icons-in-list-view"
1474 +#define CAJA_PREFERENCES_ENABLE_TIME_SLIDER "enable-time-slider"
1477 #define CAJA_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS "mouse-use-extra-buttons"
1478 #define CAJA_PREFERENCES_MOUSE_FORWARD_BUTTON "mouse-forward-button"
1479 --- caja-1.28.0/libcaja-private/caja-zfs.c.orig 2024-02-26 08:42:41.078919123 +0100
1480 +++ caja-1.28.0/libcaja-private/caja-zfs.c 2024-02-26 08:42:41.078857872 +0100
1483 + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
1489 +#include <strings.h>
1490 +#include <stdlib.h>
1491 +#include <unistd.h>
1492 +#include "caja-zfs.h"
1494 +#include <locale.h>
1495 +#include <langinfo.h>
1496 +#include <stdint.h>
1498 +#include <glib/gi18n.h>
1499 +#include <glib/gstdio.h>
1500 +#include <eel/eel-glib-extensions.h>
1501 +#include <sys/mnttab.h>
1502 +#include <sys/mkdev.h>
1503 +#include <libscf.h>
1504 +#include <dirent.h>
1505 +#include <sys/utsname.h>
1506 +#include "caja-global-preferences.h"
1507 +#define ZFS_SNAPSHOT_DIR ".zfs/snapshot/"
1508 +#define ZFS_BACKUP_DIR ".time-slider/rsync"
1510 +#ifndef ZFS_MAXNAMELEN
1511 +#ifdef ZFS_MAX_DATASET_NAME_LEN
1512 +#define ZFS_MAXNAMELEN ZFS_MAX_DATASET_NAME_LEN
1514 +#define ZFS_MAXNAMELEN 256
1519 +char* ts_realpath (char * dir, char *resolved_name)
1521 + char real_dir[PATH_MAX+1];
1522 + char real_path[PATH_MAX+1];
1523 + gboolean found = FALSE;
1524 + struct stat64 dir_stat64;
1527 + result = realpath(dir, real_dir);
1532 + if (stat64 (real_dir, &dir_stat64) == 0)
1534 + if (strcmp (dir_stat64.st_fstype, "lofs") == 0)
1537 + struct extmnttab mtab;
1539 + fp = fopen (MNTTAB,"r");
1542 + while ((status = getextmntent(fp, &mtab, sizeof (struct extmnttab))) == 0)
1544 + if (strcmp (mtab.mnt_fstype, "lofs") == 0)
1546 + dev_t dev = NODEV;
1547 + dev = makedev(mtab.mnt_major, mtab.mnt_minor);
1548 + if (dev == dir_stat64.st_dev)
1550 + if (strcmp (real_dir, mtab.mnt_mountp) == 0)
1551 + strcpy (real_path, mtab.mnt_special);
1555 + split = g_strsplit (real_dir, mtab.mnt_mountp, 2);
1556 + /*split 2nd part contains path without mount point */
1557 + g_snprintf (real_path,sizeof(real_path),"%s%s",mtab.mnt_special,split[1]);
1558 + g_strfreev (split);
1565 + (void) fclose(fp);
1569 + return strcpy (resolved_name, real_path);
1571 + return strcpy (resolved_name, real_dir);
1574 +static void ts_set_snapshot_used_space (zfs_handle_t *zhp, ZfsDataSet *snap)
1576 + gchar buf[ZFS_MAXNAMELEN];
1577 + if (zfs_prop_get(zhp, ZFS_PROP_USED, buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0)
1580 + char format_float[5] = "%f%s";
1581 + char format_int[5] = "%d%s";
1582 + char *format = format_int;
1583 + int used_space_int = 0;
1584 + gboolean success = FALSE;
1586 + snap->used_space_str = g_strdup (buf);
1588 + if (strchr (buf, '.'))
1590 + format = format_float;
1591 + if (sscanf(buf, format,&snap->used_space,unit) == 2)
1596 + if (sscanf(buf, format,&used_space_int,unit) == 2)
1599 + snap->used_space = (float) used_space_int;
1602 + if (strcmp (buf, "0") == 0)
1604 + g_free (snap->used_space_str);
1605 + snap->used_space_str = g_strdup ("0 K");
1611 + if (strcmp (unit, "M") == 0)
1612 + snap->used_space *= 1024;
1613 + if (strcmp (unit, "G") == 0)
1614 + snap->used_space *= 1024 * 1024;
1618 + g_free (snap->used_space_str);
1619 + /* SUN_BRANDING */
1620 + snap->used_space_str = g_strdup (_("Unknown"));
1625 + g_free (snap->used_space_str);
1626 + /* SUN_BRANDING */
1627 + snap->used_space_str = g_strdup (_("Unknown"));
1631 +static void ts_set_snapshot_mtime_and_time_diff (zfs_handle_t *zhp, ZfsDataSet *snap)
1637 + const gchar *format;
1638 + gchar *locale_format = NULL;
1639 + gchar buf[ZFS_MAXNAMELEN];
1640 + gchar *date_str = NULL;
1642 + if (zfs_prop_get(zhp, ZFS_PROP_CREATION, buf, sizeof (buf), NULL, NULL, 0, B_TRUE) == 0)
1646 + sscanf (buf, "%llu", &snap->mtime);
1647 + snap->mtime_str = caja_date_as_string (snap->mtime, FALSE);
1652 +void print_snap_list (char *dir, GList *snap_list)
1655 + printf ("list of snapshots for %s :\n", dir);
1656 + for (tmp = snap_list; tmp->next; tmp = tmp->next)
1658 + ZfsDataSet *snap = (ZfsDataSet*) tmp->data;
1659 + printf (" name: %s\n mountpoint: %s\n mtime_str :%s\n space used : %s\n size in kilobytes : %f\n",
1660 + snap->name, snap->mountpoint, snap->mtime_str, snap->used_space_str, snap->used_space);
1667 +dump_zds (ZfsDataSet *zds)
1675 + msg = g_string_new ("");
1676 + g_string_printf (msg,
1678 + "\tmountpoint: %s\n"
1680 + zds->name,zds->mountpoint, zfs_type_to_name(zds->type));
1681 + if (zds->snapshots)
1684 + g_string_append_printf(msg,"\tsnapshots :\n");
1685 + for (tmp=zds->snapshots;tmp;tmp = tmp->next)
1687 + ZfsDataSet *tmp_zds= (ZfsDataSet*) tmp->data;
1688 + g_string_append_printf (msg,"\t\tname: %s\n\t\tpath: %s\n",
1690 + tmp_zds->mountpoint);
1693 + g_string_append_printf (msg, "\n");
1699 +dump_sds (SearchDataSet *sds)
1707 + printf ("Search DataSet is empty\n");
1711 + msg = g_string_new ("");
1712 + g_string_printf (msg, "DDS Dump:\n"
1713 + "\tsearched_path: %s\n",
1714 + sds->searched_path);
1716 + g_string_append_printf (msg, "Zfs Data set :\n");
1717 + for (tmp=sds->datasets;tmp;tmp=tmp->next)
1719 + GString * zds_dump = dump_zds ((ZfsDataSet *)tmp->data);
1720 + g_string_append_printf (msg,"%s",zds_dump->str);
1721 + g_string_free (zds_dump, TRUE);
1723 + g_string_append_printf (msg, "\n");
1724 + printf ("%s", msg->str);
1725 + g_string_free (msg, TRUE);
1729 +ts_new_zfs_dataset (SearchDataSet* sds)
1732 + zds = g_new0 (ZfsDataSet, 1);
1733 + zds->search_dataset = sds;
1738 +ts_free_zfs_dataset (ZfsDataSet* zds)
1743 + g_free (zds->name);
1744 + if (zds->mountpoint)
1745 + g_free (zds->mountpoint);
1746 + if (zds->mtime_str)
1747 + g_free (zds->mtime_str);
1748 + if (zds->used_space_str)
1749 + g_free (zds->used_space_str);
1751 + if (zds->snapshots)
1754 + for (tmp = zds->snapshots;tmp;tmp = tmp->next)
1755 + ts_free_zfs_dataset ((ZfsDataSet*)tmp->data);
1760 +static SearchDataSet *
1761 +ts_new_search_dataset (GCancellable *cancel)
1763 + SearchDataSet *sds;
1764 + sds = g_new0 (SearchDataSet, 1);
1765 + sds->cancel = cancel;
1769 +ts_free_search_dataset (SearchDataSet *sds)
1773 + if (sds->searched_path)
1774 + g_free (sds->searched_path);
1775 + if (sds->mountpoint)
1776 + g_free (sds->mountpoint);
1777 + if (sds->datasets)
1780 + for (tmp = sds->datasets;tmp;tmp = tmp->next)
1781 + ts_free_zfs_dataset ((ZfsDataSet*)tmp->data);
1786 +static char* construct_check_snapshot_path (SearchDataSet *sds, char* mountpoint, const char *name, char *searched_path)
1788 + gchar *result = NULL;
1792 + gchar *snap_name = NULL;
1793 + gchar *remaining_path = NULL;
1795 + /* get the snapshot name part pool@snap-name we are only interested in snap-name split[1] */
1796 + split = g_strsplit (name,"@",2);
1797 + /* get the path after the mountpoint */
1798 + split2 = g_strsplit (searched_path, mountpoint, 2);
1800 + if (split && split[1])
1801 + snap_name = split[1];
1803 + if (split2 && split2[1])
1804 + remaining_path = split2[1];
1806 +/* printf ("mountpoint : %s \nname : %s \nsearched_path: %s\n", mountpoint, name, searched_path);
1807 + printf ("split %s at @ = [%s] [%s]\n", name, split[0],split[1]);
1808 + printf ("split %s at [%s] = [%s] [%s]\n", searched_path, mountpoint, split2[0],split2[1]);
1809 + printf ("%s/.zfs/snapshot/%s/%s\n\n", mountpoint, split[1], split2[1]);*/
1811 + if (snap_name && remaining_path)
1812 + if (strcmp(mountpoint, "/") == 0)
1813 + result = g_strdup_printf ("/.zfs/snapshot/%s/%s", snap_name, remaining_path);
1815 + result = g_strdup_printf ("%s/.zfs/snapshot/%s/%s", mountpoint, snap_name, remaining_path);
1817 + g_strfreev (split);
1818 + g_strfreev (split2);
1820 + /* don't test for file presence if searched path is the same as the mount point */
1821 + if (sds->searched_path_match_mp)
1824 + if (result && g_file_test (result, G_FILE_TEST_IS_DIR))
1826 + char real_dir[PATH_MAX+1];
1827 + if (!ts_realpath(result, real_dir))
1835 + result = g_strdup (real_dir);
1845 +snapshot_callback (zfs_handle_t *zhp, void *data)
1847 + ZfsDataSet *main_zds = (ZfsDataSet*) data;
1849 + /* only add snapshot dir that exist */
1851 + if (zfs_get_type (zhp) == ZFS_TYPE_SNAPSHOT && !g_cancellable_is_cancelled (main_zds->search_dataset->cancel))
1853 + const char* name = zfs_get_name (zhp);
1854 + char *snap_path = construct_check_snapshot_path (main_zds->search_dataset,
1855 + main_zds->mountpoint,
1857 + main_zds->search_dataset->searched_path);
1860 + ZfsDataSet *zds = ts_new_zfs_dataset (main_zds->search_dataset);
1861 + zds->name = g_strdup (name);
1862 + zds->type = ZFS_TYPE_SNAPSHOT;
1863 + zds->mountpoint = snap_path;
1864 + ts_set_snapshot_mtime_and_time_diff (zhp, zds);
1865 + ts_set_snapshot_used_space (zhp, zds);
1866 + main_zds->snapshots = g_list_append (main_zds->snapshots,zds);
1874 +static struct mnttab *
1875 +mygetmntent(FILE *f)
1877 + static struct mnttab mt;
1880 + if ((status = getmntent(f, &mt)) == 0)
1887 +is_fs_mounted (const char *fs_name)
1890 + struct mnttab *mntp;
1893 + mnttab = fopen (MNTTAB,"r");
1895 + while ((mntp = mygetmntent(mnttab)) != NULL)
1897 + if (mntp->mnt_fstype == (char *)0 || strcmp(mntp->mnt_fstype, "zfs") != 0)
1899 + if (strcmp (mntp->mnt_special, fs_name) == 0)
1902 + return g_strdup (mntp->mnt_mountp);
1909 +static char* rsync_get_smf_dir()
1911 + char data_store[MAXPATHLEN];
1915 + scf_handle_t *handle = NULL;
1916 + scf_scope_t *sc = NULL;
1917 + scf_service_t *svc = NULL;
1918 + scf_instance_t *inst = NULL;
1919 + scf_propertygroup_t *pg = NULL;
1920 + scf_property_t *prop = NULL;
1921 + scf_value_t *value = NULL;
1922 + scf_iter_t *value_iter = NULL;
1925 + /* connect to the current SMF global repository */
1926 + handle = scf_handle_create(SCF_VERSION);
1928 + /* allocate scf resources */
1929 + sc = scf_scope_create(handle);
1930 + svc = scf_service_create(handle);
1931 + inst = scf_instance_create (handle);
1932 + pg = scf_pg_create(handle);
1933 + prop = scf_property_create(handle);
1934 + value = scf_value_create(handle);
1935 + value_iter = scf_iter_create(handle);
1937 + char *result = NULL;
1939 + /* if failed to allocate resources, exit */
1940 + if (handle == NULL || sc == NULL || svc == NULL || pg == NULL ||
1941 + prop == NULL || value == NULL || value_iter == NULL) {
1942 + /* scf handles allocation failed. */
1946 + /* bind scf handle to the running svc.configd daemon */
1947 + if (scf_handle_bind(handle) == -1) {
1948 + /* scf binding failed. */
1952 + /* get the scope of the localhost in the current repository */
1953 + if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) == -1) {
1954 + /* Getting scf scope failed.*/
1958 + /* get the service within the scope */
1959 + if (scf_scope_get_service(sc, "application/time-slider/plugin", svc) == -1) {
1960 + /* failed getting service */
1964 + /* get the instance within the service */
1965 + if (scf_service_get_instance(svc, "rsync", inst) == -1)
1969 + /* get the property group within the instance */
1970 + if (scf_instance_get_pg(inst, "rsync", pg) == -1) {
1971 + /* Getting property group failed. */
1976 + * Now get the properties.
1978 + if (scf_pg_get_property(pg, "target_dir", prop) == -1) {
1982 + if (scf_property_get_value(prop, value) == -1) {
1986 + data_store[0] = 0;
1987 + if (scf_value_get_astring(value, data_store, MAXPATHLEN) == -1) {
1991 + result = strdup (data_store);
1995 + /* destroy scf pointers */
1996 + if (value != NULL)
1997 + scf_value_destroy(value);
1998 + if (value_iter != NULL)
1999 + scf_iter_destroy(value_iter);
2001 + scf_property_destroy(prop);
2003 + scf_pg_destroy(pg);
2005 + scf_instance_destroy (inst);
2007 + scf_service_destroy(svc);
2009 + scf_scope_destroy(sc);
2010 + if (handle != NULL)
2011 + scf_handle_destroy(handle);
2016 +static char *rsync_get_dir (zfs_handle_t *zhp)
2018 + nvlist_t *propval;
2020 + if (nvlist_lookup_nvlist(zfs_get_user_props(zhp),
2021 + "org.opensolaris:time-slider-rsync", &propval) == 0)
2023 + boolean_t ret_bool = FALSE;
2026 + nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
2028 + if (strcmp (strval, "true") == 0)
2030 + dir = rsync_get_smf_dir ();
2038 +void sync_backups_add (zfs_handle_t *zhp, ZfsDataSet *main_zds)
2040 + char *rsync_dir = rsync_get_dir (zhp);
2042 + struct dirent *dir;
2043 + char *fs_rsync_dir;
2044 + struct utsname machine;
2049 + /* format SMF backup dir , TIMESLIDER, nodename from uname, path, .time-slider/rsync */
2050 + if (uname (&machine) == -1)
2053 + fs_rsync_dir = g_strdup_printf ("%s/TIMESLIDER/%s/%s/%s/",
2059 + if (!g_file_test (fs_rsync_dir, G_FILE_TEST_IS_DIR))
2061 + g_free (rsync_dir);
2062 + g_free (fs_rsync_dir);
2066 + d = opendir (fs_rsync_dir);
2070 + g_free (rsync_dir);
2071 + g_free (fs_rsync_dir);
2075 + while ((dir = readdir (d)))
2077 + if (strstr (dir->d_name, "zfs-auto-snap_"))
2078 + { /* got a snap copy dir */
2079 + char **comma_split = NULL;
2080 + char **freq_split = NULL;
2082 + ZfsDataSet *zds = NULL;
2084 + /* extract creation time from dir name */
2085 + comma_split = g_strsplit (dir->d_name, "_", 2);
2086 + /* printf ("comma_split[1] = %s\n", comma_split[1]); */
2087 + freq_split = g_strsplit (comma_split[1], "-", 2);
2088 + /* printf ("freq_split[1] = %s\n", freq_split[1]); */
2090 + /* parse time string */
2091 + if (strptime (freq_split[1], "%Y-%m-%d-%Hh%M", &tms) != NULL)
2093 + zds = ts_new_zfs_dataset (main_zds->search_dataset);
2094 + zds->name = g_strdup (dir->d_name);
2096 + zds->mountpoint = g_strdup_printf ("%s%s/", fs_rsync_dir, dir->d_name);
2097 + zds->mtime = mktime (&tms);
2098 + zds->mtime_str = caja_date_as_string (zds->mtime, FALSE);
2099 + zds->used_space_str = g_strdup (_("Separate Backup"));
2100 + main_zds->snapshots = g_list_append (main_zds->snapshots,zds);
2101 + /* printf ("in sync_backups_add adding %s %s\n", zds->name, zds->mountpoint); */
2104 + g_strfreev (comma_split);
2106 + g_strfreev (freq_split);
2111 + g_free (rsync_dir);
2115 +zfs_callback (zfs_handle_t *zhp, void *data)
2117 + char buf[ZFS_MAXPROPLEN];
2118 + char mounted[ZFS_MAXPROPLEN];
2119 + SearchDataSet *sds = (SearchDataSet*) data;
2121 + if (sds->match_found)
2127 + if (zfs_get_type (zhp) & sds->type & !g_cancellable_is_cancelled (sds->cancel))
2129 +/* struct timespec ts;
2131 + ts.tv_nsec = 100000000;
2132 + nanosleep (&ts, NULL);*/
2134 + if (sds->prop >= ZFS_PROP_TYPE && sds->prop < ZFS_NUM_PROPS)
2136 + zfs_prop_get(zhp, sds->prop, buf, sizeof (buf), NULL, NULL, 0, TRUE);
2138 + zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mounted, sizeof (mounted), NULL, NULL, 0, TRUE);
2140 + if ((strcmp (sds->mountpoint, buf) == 0) && (strcmp (mounted, "yes") == 0))
2142 + ZfsDataSet *zds = ts_new_zfs_dataset (sds);
2143 + zds->type = zfs_get_type (zhp);
2144 + zds->name = g_strdup (zfs_get_name(zhp));
2145 + zds->mountpoint = g_strdup (buf);
2146 + zfs_iter_snapshots (zhp, B_FALSE, snapshot_callback, zds);
2147 + sync_backups_add (zhp, zds);
2148 + sds->datasets = g_list_append (sds->datasets, zds);
2149 + sds->match_found = TRUE;
2151 + else if (strcmp ("legacy", buf) == 0)
2152 + { /* parse /etc/mnttab to get the mount point */
2153 + char *mountp = is_fs_mounted (zfs_get_name(zhp));
2156 + if (strcmp (sds->mountpoint, mountp) == 0)
2158 + ZfsDataSet *zds = ts_new_zfs_dataset (sds);
2159 + zds->type = zfs_get_type (zhp);
2160 + zds->name = g_strdup (zfs_get_name(zhp));
2161 + zds->mountpoint = mountp;
2162 + zfs_iter_snapshots (zhp, B_FALSE, snapshot_callback, zds);
2163 + sync_backups_add (zhp, zds);
2164 + sds->datasets = g_list_append (sds->datasets, zds);
2165 + sds->match_found = TRUE;
2172 + if (!sds->match_found)
2173 + zfs_iter_filesystems (zhp, zfs_callback, sds);
2179 +static SearchDataSet *
2180 +ts_get_data_from_mountpoint (const char* searched_path, const char *mountpoint, GCancellable *cancel)
2182 + static libzfs_handle_t *zfs_handle = NULL;
2183 + SearchDataSet *sds;
2185 + sds = ts_new_search_dataset (cancel);
2187 + sds->prop = ZFS_PROP_MOUNTPOINT;
2188 + sds->type = ZFS_TYPE_FILESYSTEM;
2189 + sds->searched_path = g_strdup (searched_path);
2190 + sds->mountpoint = g_strdup (mountpoint);
2192 + if (strcmp (searched_path, mountpoint) == 0)
2193 + sds->searched_path_match_mp = TRUE;
2197 + if ((zfs_handle = libzfs_init()) == NULL) {
2198 + g_warning ("internal error: failed to initialize ZFS library\n");
2199 + ts_free_search_dataset (sds);
2203 + zfs_iter_root (zfs_handle, zfs_callback, sds);
2208 +snap_sort_by_age (gconstpointer a,
2211 + const ZfsDataSet *snap1 = a;
2212 + const ZfsDataSet *snap2 = b;
2214 + if (snap1->mtime == snap2->mtime)
2216 + if (snap1->mtime < snap2->mtime)
2218 + if (snap1->mtime > snap2->mtime)
2224 +ts_get_zfs_filesystem (char *dir)
2226 + char real_dir[PATH_MAX+1];
2227 + char filesystem[PATH_MAX+1];
2228 + gboolean found_fs= FALSE;
2229 + struct stat64 dir_stat64;
2231 + if (!ts_realpath(dir, real_dir))
2235 + if (stat64 (real_dir, &dir_stat64) == 0)
2236 + { /* check is fs is zfs */
2237 + if (strcmp (dir_stat64.st_fstype, "zfs") == 0)
2240 + struct extmnttab mtab;
2243 + /* get mount point */
2245 + fp = fopen (MNTTAB,"r");
2248 + while ((status = getextmntent(fp, &mtab, sizeof (struct extmnttab))) == 0)
2250 + dev_t dev = NODEV;
2251 + dev = makedev(mtab.mnt_major, mtab.mnt_minor);
2252 + if (dev == dir_stat64.st_dev)
2254 + strcpy (filesystem, mtab.mnt_special);
2259 + (void) fclose(fp);
2263 + return g_strdup(filesystem);
2268 +static char * get_zfs_mountpoint (char *dir)
2270 + char real_dir[PATH_MAX+1];
2271 + char mountpoint[PATH_MAX+1];
2272 + gboolean found_mount_point = FALSE;
2273 + struct stat64 dir_stat64;
2275 + if (!ts_realpath(dir, real_dir))
2279 + if (stat64 (real_dir, &dir_stat64) == 0)
2280 + { /* check is fs is zfs */
2281 + if (strcmp (dir_stat64.st_fstype, "zfs") == 0)
2284 + struct extmnttab mtab;
2287 + /* get mount point */
2289 + fp = fopen (MNTTAB,"r");
2292 + while ((status = getextmntent(fp, &mtab, sizeof (struct extmnttab))) == 0)
2294 + dev_t dev = NODEV;
2295 + dev = makedev(mtab.mnt_major, mtab.mnt_minor);
2296 + if (dev == dir_stat64.st_dev)
2298 + strcpy (mountpoint, mtab.mnt_mountp);
2299 + found_mount_point = TRUE;
2303 + (void) fclose(fp);
2306 + if (found_mount_point)
2307 + return g_strdup(mountpoint);
2313 +char *ts_get_snapshot_dir (char *dir)
2315 + char *zfs_dir = get_zfs_mountpoint (dir);
2318 + char *snapshot_dir = g_strdup_printf ("%s/.zfs/snapshot", zfs_dir);
2320 + return snapshot_dir;
2328 +static void ts_get_snapshots_for_dir (GSimpleAsyncResult *res,
2330 + GCancellable *cancellable)
2332 + char *mountpoint = NULL;
2333 + char real_dir[PATH_MAX+1];
2334 + SearchDataSet *sds;
2335 + GList* snap_result = NULL;
2336 + GFile *file = G_FILE (object);
2337 + char *dir = g_file_get_path (file);
2339 + mountpoint = get_zfs_mountpoint (dir);
2344 + g_simple_async_result_set_op_res_gpointer (res, snap_result, (GDestroyNotify) NULL);
2349 + ts_realpath(dir, real_dir);
2351 + sds = ts_get_data_from_mountpoint (real_dir, mountpoint, cancellable);
2353 + g_free (mountpoint);
2355 + if (g_cancellable_is_cancelled (cancellable))
2357 + /* printf ("ts_get_snapshots_for_dir %s cancelled\n", dir); */
2360 + ts_free_search_dataset (sds);
2368 + for (tmp=sds->datasets;tmp;tmp=tmp->next)
2370 + ZfsDataSet *zds = (ZfsDataSet*) tmp->data;
2371 + if (zds->snapshots)
2373 + snap_result = g_list_concat (snap_result, zds->snapshots);
2374 + zds->snapshots = NULL;
2377 + ts_free_search_dataset (sds);
2382 + snap_result = g_list_sort (snap_result, (GCompareFunc)snap_sort_by_age);
2383 + /* print_snap_list (dir, snap_result); */
2387 + g_simple_async_result_set_op_res_gpointer (res, snap_result, (GDestroyNotify) NULL);
2391 +GList *ts_get_snapshots_for_dir_async (GFile *file,
2392 + GAsyncReadyCallback result_ready,
2393 + GCancellable *cancel,
2394 + gpointer user_data)
2396 + GSimpleAsyncResult *res;
2398 + res = g_simple_async_result_new (G_OBJECT (file), result_ready, user_data, (gpointer) ts_get_snapshots_for_dir);
2399 + g_simple_async_result_run_in_thread (res, ts_get_snapshots_for_dir, G_PRIORITY_DEFAULT, cancel);
2404 +void ts_free_snapshots (GList *snaps)
2409 + for (tmp=snaps;tmp;tmp=tmp->next)
2410 + ts_free_zfs_dataset ((ZfsDataSet*) tmp->data);
2411 + g_list_free (snaps);
2415 +gboolean ts_is_in_remote_backup (char *str)
2419 + if (g_strrstr (str, ZFS_BACKUP_DIR))
2426 +gboolean ts_is_in_snapshot (char * str)
2430 + if (g_strrstr (str, ZFS_SNAPSHOT_DIR))
2432 + if (g_strrstr (str, ZFS_BACKUP_DIR))
2438 +char* ts_remove_snapshot_dir (char *str)
2440 + if (ts_is_in_snapshot (str))
2443 + char *zfs, *iter, point;
2446 + /*remove .zfs/snapshot/blah/ */
2447 + zfs = g_strrstr (str, ZFS_SNAPSHOT_DIR);
2452 + iter += sizeof (ZFS_SNAPSHOT_DIR);
2453 + while (*iter != '/' && *iter != '\0')
2461 + snap_root = g_strdup_printf ("%s%s", str, iter);
2471 +static gboolean restore_col_enabled = FALSE;
2474 +ts_is_restore_column_enabled ()
2476 + return restore_col_enabled;
2479 +void ts_is_restore_column_enabled_init ();
2482 +visible_columns_changed (gpointer callback_data)
2484 + ts_is_restore_column_enabled_init ();
2488 +void ts_is_restore_column_enabled_init ()
2490 + char **visible_columns;
2491 + static gboolean init = FALSE;
2496 + g_signal_connect_swapped ( caja_list_view_preferences,
2497 + g_strconcat ("changed::", CAJA_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS, NULL),
2498 + G_CALLBACK ( visible_columns_changed ),
2503 + restore_col_enabled = FALSE;
2505 + visible_columns = g_settings_get_strv (caja_list_view_preferences,
2506 + CAJA_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS);
2508 + while (visible_columns[i])
2510 + if (strcmp (visible_columns [i], "restore_info") == 0)
2512 + restore_col_enabled = TRUE;
2517 + g_strfreev (visible_columns);
2521 +static GList * get_dir_entries (char *dir_path)
2523 + const char *entry_name;
2525 + GList *dir_entries = NULL;
2526 + dir = g_dir_open (dir_path, 0, NULL);
2528 + while ((entry_name = g_dir_read_name (dir)) != NULL)
2529 + dir_entries = g_list_prepend (dir_entries, g_strdup (entry_name));
2531 + g_dir_close (dir);
2533 + return dir_entries;
2536 +static void free_dir_entries (GList *entries)
2538 + g_list_foreach (entries, (GFunc)g_free, NULL);
2539 + g_list_free (entries);
2542 +static gboolean are_entries_identical (GList *old, GList *new)
2544 + if (g_list_length (old) != g_list_length (new))
2547 + for (old; old; old = old->next)
2549 + gboolean found = FALSE;
2550 + for (new; new; new = new->next)
2552 + if (strcmp (old->data, new->data) == 0)
2564 +void monitor_zfs_snap_directory_cancel (ZfsSnapDirMonitor *monitor_data)
2568 + /* printf ("in monitor_zfs_snap_directory_cancel %s\n", monitor_data->path); */
2569 + g_source_remove (monitor_data->timeout_id);
2570 + free_dir_entries (monitor_data->entries);
2571 + g_free (monitor_data->path);
2572 + g_free (monitor_data);
2577 +monitor_snap_dir (ZfsSnapDirMonitor *monitor_data)
2579 + GList *new_entries;
2581 + if (!g_file_test (monitor_data->path, G_FILE_TEST_IS_DIR))
2583 + monitor_zfs_snap_directory_cancel (monitor_data);
2587 + new_entries = get_dir_entries (monitor_data->path);
2589 + if (are_entries_identical (monitor_data->entries, new_entries))
2591 + free_dir_entries (new_entries);
2595 + free_dir_entries (monitor_data->entries);
2596 + monitor_data->entries = new_entries;
2597 + monitor_data->change_callback (monitor_data, monitor_data->user_data);
2600 + if (monitor_data->backup_path)
2602 + if (!g_file_test (monitor_data->backup_path, G_FILE_TEST_IS_DIR))
2604 + monitor_zfs_snap_directory_cancel (monitor_data);
2608 + new_entries = get_dir_entries (monitor_data->backup_path);
2610 + if (are_entries_identical (monitor_data->backup_entries, new_entries))
2612 + free_dir_entries (new_entries);
2616 + free_dir_entries (monitor_data->backup_entries);
2617 + monitor_data->backup_entries = new_entries;
2618 + monitor_data->change_callback (monitor_data, monitor_data->user_data);
2625 +ZfsSnapDirMonitor *monitor_zfs_snap_directory (char *path,
2626 + char *backup_path,
2627 + ZfsDirChangeCallback change_callback,
2630 + ZfsSnapDirMonitor *monitor_data = g_new0 (ZfsSnapDirMonitor, 1);
2632 + /* printf ("start monitoring %s\n", path); */
2634 + monitor_data->path = g_strdup (path);
2635 + monitor_data->entries = get_dir_entries (path);
2638 + monitor_data->backup_path = g_strdup (backup_path);
2639 + monitor_data->backup_entries = get_dir_entries (backup_path);
2641 + monitor_data->change_callback = change_callback;
2642 + monitor_data->user_data = data;
2644 + monitor_data->timeout_id = g_timeout_add_seconds (5, (GSourceFunc)monitor_snap_dir, monitor_data);
2645 + return monitor_data;
2649 +ts_get_not_zfs_snapshot_dir (GFile *file)
2651 + char tmp_path[PATH_MAX + 1];
2652 + gboolean found = FALSE;
2653 + gboolean end_path = FALSE;
2654 + GFile *d = g_file_get_parent(file);
2656 + char *full_path = g_file_get_path (file);
2657 + char *stripped_path = g_file_get_path (d);
2658 + struct stat64 dir_stat64;
2663 + if (stat64 (full_path, &dir_stat64) == 0)
2664 + { /* check is fs is zfs if so don't try to check for nfs mounted .zfs dir*/
2665 + if (strcmp (dir_stat64.st_fstype, "zfs") == 0)
2669 + while (!found && !end_path)
2671 + g_snprintf (tmp_path, sizeof(tmp_path), "%s/.zfs/snapshot", stripped_path);
2672 + if (g_file_test (tmp_path, G_FILE_TEST_IS_DIR))
2674 + GList *entries = get_dir_entries (tmp_path);
2675 + if (entries != NULL)
2677 + char *after_snap_path = full_path + strlen (stripped_path);
2679 + for (entries; entries; entries = entries->next)
2681 + char test_path[PATH_MAX +1];
2682 + g_sprintf (test_path, "%s/%s/%s", tmp_path,
2685 + if (g_file_test (test_path, G_FILE_TEST_EXISTS))
2691 + free_dir_entries (entries);
2695 + d = g_file_get_parent (tmp);
2696 + g_object_unref (tmp);
2697 + g_free (stripped_path);
2698 + stripped_path=NULL;
2705 + stripped_path = g_file_get_path (d);
2709 + g_free (full_path);
2711 + if (stripped_path)
2712 + g_free (stripped_path);
2715 + return g_strdup (tmp_path);
2721 --- caja-1.28.0/libcaja-private/caja-zfs.h.orig 2024-02-26 08:42:41.079103041 +0100
2722 +++ caja-1.28.0/libcaja-private/caja-zfs.h 2024-02-26 08:42:41.079046173 +0100
2728 +#include <libzfs.h>
2729 +#include <gio/gio.h>
2735 + char *searched_path;
2738 + GCancellable *cancel;
2739 + gboolean match_found;
2740 + gboolean searched_path_match_mp;
2751 + char *used_space_str;
2754 + SearchDataSet *search_dataset;
2758 +GList *ts_get_snapshots_for_dir_async (GFile *file,
2759 + GAsyncReadyCallback result_ready,
2760 + GCancellable *cancel,
2761 + gpointer user_data);
2762 +void ts_free_snapshots (GList *snaps);
2763 +void ts_free_zfs_dataset (ZfsDataSet* zds);
2765 +gboolean ts_is_in_snapshot (char * str);
2766 +gboolean ts_is_in_remote_backup (char *str);
2767 +char* ts_remove_snapshot_dir (char *str);
2768 +char *ts_get_snapshot_dir (char *dir);
2769 +char *ts_get_zfs_filesystem (char *dir);
2770 +char * ts_get_not_zfs_snapshot_dir (GFile *file);
2771 +gboolean ts_is_restore_column_enabled ();
2772 +void ts_is_restore_column_enabled_init ();
2773 +void print_snap_list (char *dir, GList *snap_list);
2774 +char* ts_realpath (char * dir, char *resolved_name);
2777 +caja_date_as_string (time_t time_raw, gboolean use_smallest);
2779 +typedef void (*ZfsDirChangeCallback) (gpointer monitor_data,
2780 + gpointer user_data);
2786 + char * backup_path;
2787 + GList *backup_entries;
2789 + ZfsDirChangeCallback change_callback;
2790 + gpointer user_data;
2791 +} ZfsSnapDirMonitor;
2793 +void monitor_zfs_snap_directory_cancel (ZfsSnapDirMonitor *monitor_data);
2794 +ZfsSnapDirMonitor *monitor_zfs_snap_directory (char *path,
2795 + char *backup_path,
2796 + ZfsDirChangeCallback change_callback,
2798 +#endif /* CAJA_ZFS_H */
2799 --- caja-1.28.0/libcaja-private/Makefile.am.orig 2024-02-20 01:30:36.000000000 +0100
2800 +++ caja-1.28.0/libcaja-private/Makefile.am 2024-02-26 08:42:41.079261409 +0100
2802 $(top_builddir)/eel/libeel-2.la \
2803 $(top_builddir)/libcaja-extension/libcaja-extension.la \
2812 libcaja_private_la_SOURCES = \
2814 caja-window-slot-info.h \
2815 caja-undostack-manager.c \
2816 caja-undostack-manager.h \
2821 nodist_libcaja_private_la_SOURCES =\
2822 --- caja-1.28.0/libcaja-private/org.mate.caja.gschema.xml.orig 2024-02-20 01:30:36.000000000 +0100
2823 +++ caja-1.28.0/libcaja-private/org.mate.caja.gschema.xml 2024-02-26 08:42:41.079490993 +0100
2825 <summary>Switch tabs with [ctrl] + [tab]</summary>
2826 <description>If true, it enables the ability to switch tabs using [ctrl + tab] and [ctrl + shift + tab].</description>
2828 + <key name="enable-time-slider" type="b">
2829 + <default>true</default>
2830 + <summary>Enables the visualization of the ZFS snaphots timeline.</summary>
2831 + <description>If set to true, the visualization of the ZFS snapshots timeline is enabled.</description>
2833 <key name="exit-with-last-window" type="b">
2834 <default>false</default>
2835 <summary>Caja will exit when last window destroyed.</summary>