ret = file_data_check_changed_single_file(fd, st);
work = fd->sidecar_files;
ret = file_data_check_changed_single_file(fd, st);
work = fd->sidecar_files;
if (fd->parent) fd = fd->parent;
if (!stat_utf8(fd->path, &st))
if (fd->parent) fd = fd->parent;
if (!stat_utf8(fd->path, &st))
/* file_data_disconnect_sidecar_file might delete the file,
we have to keep the reference to prevent this */
sidecars = filelist_copy(fd->sidecar_files);
/* file_data_disconnect_sidecar_file might delete the file,
we have to keep the reference to prevent this */
sidecars = filelist_copy(fd->sidecar_files);
file_data_disconnect_sidecar_file(fd, sfd);
}
file_data_check_sidecars(sidecars); /* this will group the sidecars back together */
file_data_disconnect_sidecar_file(fd, sfd);
}
file_data_check_sidecars(sidecars); /* this will group the sidecars back together */
fd->collate_key_name = g_utf8_collate_key(valid_name, -1);
fd->collate_key_name_nocase = g_utf8_collate_key(caseless_name, -1);
fd->collate_key_name = g_utf8_collate_key(valid_name, -1);
fd->collate_key_name_nocase = g_utf8_collate_key(caseless_name, -1);
if (!fd && file_data_planned_change_hash)
{
fd = g_hash_table_lookup(file_data_planned_change_hash, path_utf8);
if (!fd && file_data_planned_change_hash)
{
fd = g_hash_table_lookup(file_data_planned_change_hash, path_utf8);
changed = file_data_check_changed_single_file(fd, st);
DEBUG_2("file_data_pool hit: '%s' %s", fd->path, changed ? "(changed)" : "");
changed = file_data_check_changed_single_file(fd, st);
DEBUG_2("file_data_pool hit: '%s' %s", fd->path, changed ? "(changed)" : "");
if (disable_sidecars) fd->disable_grouping = TRUE;
file_data_set_path(fd, path_utf8); /* set path, name, collate_key_*, original_path */
if (disable_sidecars) fd->disable_grouping = TRUE;
file_data_set_path(fd, path_utf8); /* set path, name, collate_key_*, original_path */
{
struct tm time_str;
uint year, month, day, hour, min, sec;
{
struct tm time_str;
uint year, month, day, hour, min, sec;
sscanf(tmp, "%4d:%2d:%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
time_str.tm_year = year - 1900;
time_str.tm_mon = month - 1;
sscanf(tmp, "%4d:%2d:%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
time_str.tm_year = year - 1900;
time_str.tm_mon = month - 1;
void set_exif_time_data(GList *files)
{
DEBUG_1("%s set_exif_time_data: ...", get_exec_time());
void set_exif_time_data(GList *files)
{
DEBUG_1("%s set_exif_time_data: ...", get_exec_time());
g_free(fd->collate_key_name_nocase);
if (fd->thumb_pixbuf) g_object_unref(fd->thumb_pixbuf);
histmap_free(fd->histmap);
g_free(fd->collate_key_name_nocase);
if (fd->thumb_pixbuf) g_object_unref(fd->thumb_pixbuf);
histmap_free(fd->histmap);
g_assert(fd->sidecar_files == NULL); /* sidecar files must be freed before calling this */
file_data_change_info_free(NULL, fd);
g_assert(fd->sidecar_files == NULL); /* sidecar files must be freed before calling this */
file_data_change_info_free(NULL, fd);
DEBUG_0("fd magick mismatch fd=%p", fd);
#endif
g_assert(fd->magick == FD_MAGICK);
DEBUG_0("fd magick mismatch fd=%p", fd);
#endif
g_assert(fd->magick == FD_MAGICK);
fd->ref--;
#ifdef DEBUG_FILEDATA
DEBUG_2("file_data_unref fd=%p (%d): '%s' @ %s:%d", fd, fd->ref, fd->path, file, line);
fd->ref--;
#ifdef DEBUG_FILEDATA
DEBUG_2("file_data_unref fd=%p (%d): '%s' @ %s:%d", fd, fd->ref, fd->path, file, line);
if (fda->sidecar_priority < fdb->sidecar_priority) return -1;
if (fda->sidecar_priority > fdb->sidecar_priority) return 1;
if (fda->sidecar_priority < fdb->sidecar_priority) return -1;
if (fda->sidecar_priority > fdb->sidecar_priority) return 1;
g_assert(sfd->magick == FD_MAGICK);
DEBUG_2(" sidecar: %p %s", sfd, sfd->name);
}
g_assert(sfd->magick == FD_MAGICK);
DEBUG_2(" sidecar: %p %s", sfd, sfd->name);
}
as sidecars of the first entry (parent_fd) */
work = basename_list->next;
s_work = parent_fd->sidecar_files;
as sidecars of the first entry (parent_fd) */
work = basename_list->next;
s_work = parent_fd->sidecar_files;
file_data_send_notification(old_parent, NOTIFY_REREAD);
file_data_unref(old_parent);
}
file_data_send_notification(old_parent, NOTIFY_REREAD);
file_data_unref(old_parent);
}
file_data_increment_version(sfd); /* increments both sfd and target */
target->sidecar_files = g_list_remove(target->sidecar_files, sfd);
file_data_increment_version(sfd); /* increments both sfd and target */
target->sidecar_files = g_list_remove(target->sidecar_files, sfd);
void file_data_disable_grouping(FileData *fd, gboolean disable)
{
if (!fd->disable_grouping == !disable) return;
void file_data_disable_grouping(FileData *fd, gboolean disable)
{
if (!fd->disable_grouping == !disable) return;
ret = strcmp(fa->collate_key_name_nocase, fb->collate_key_name_nocase);
if (ret != 0) return ret;
ret = strcmp(fa->collate_key_name_nocase, fb->collate_key_name_nocase);
if (ret != 0) return ret;
/* do not return 0 unless the files are really the same
file_data_pool ensures that original_path is unique
*/
/* do not return 0 unless the files are really the same
file_data_pool ensures that original_path is unique
*/
gchar *basename = g_strndup(fd->path, fd->extension - fd->path);
list = g_hash_table_lookup(basename_hash, basename);
gchar *basename = g_strndup(fd->path, fd->extension - fd->path);
list = g_hash_table_lookup(basename_hash, basename);
if (!g_list_find(list, fd))
{
list = g_list_insert_sorted(list, file_data_ref(fd), file_data_sort_by_ext);
if (!g_list_find(list, fd))
{
list = g_list_insert_sorted(list, file_data_ref(fd), file_data_sort_by_ext);
filelist_read_real(dir, &files, NULL, TRUE);
filelist_read_real(dir, &files, NULL, TRUE);
if (!existing_only && !sidecar_path)
{
gchar *base = g_strndup(fd->path, fd->extension - fd->path);
if (!existing_only && !sidecar_path)
{
gchar *base = g_strndup(fd->path, fd->extension - fd->path);
gboolean file_data_get_mark(FileData *fd, gint n)
{
gboolean valid = (fd->valid_marks & (1 << n));
gboolean file_data_get_mark(FileData *fd, gint n)
{
gboolean valid = (fd->valid_marks & (1 << n));
if (file_data_get_mark_func[n] && !valid)
{
guint old = fd->marks;
gboolean value = (file_data_get_mark_func[n])(fd, n, file_data_mark_func_data[n]);
if (file_data_get_mark_func[n] && !valid)
{
guint old = fd->marks;
gboolean value = (file_data_get_mark_func[n])(fd, n, file_data_mark_func_data[n]);
if (file_data_set_mark_func[n])
{
(file_data_set_mark_func[n])(fd, n, value, file_data_mark_func_data[n]);
}
if (file_data_set_mark_func[n])
{
(file_data_set_mark_func[n])(fd, n, value, file_data_mark_func_data[n]);
}
file_data_increment_version(fd);
file_data_send_notification(fd, NOTIFY_MARKS);
}
file_data_increment_version(fd);
file_data_send_notification(fd, NOTIFY_MARKS);
}
gboolean file_data_register_mark_func(gint n, FileDataGetMarkFunc get_mark_func, FileDataSetMarkFunc set_mark_func, gpointer data, GDestroyNotify notify)
{
if (n < 0 || n >= FILEDATA_MARKS_SIZE) return FALSE;
gboolean file_data_register_mark_func(gint n, FileDataGetMarkFunc get_mark_func, FileDataSetMarkFunc set_mark_func, gpointer data, GDestroyNotify notify)
{
if (n < 0 || n >= FILEDATA_MARKS_SIZE) return FALSE;
file_data_get_mark_func[n] = get_mark_func;
file_data_set_mark_func[n] = set_mark_func;
file_data_mark_func_data[n] = data;
file_data_get_mark_func[n] = get_mark_func;
file_data_set_mark_func[n] = set_mark_func;
file_data_mark_func_data[n] = data;
if (sfd->change) return FALSE;
work = work->next;
}
file_data_add_ci(fd, type, NULL, NULL);
if (sfd->change) return FALSE;
work = work->next;
}
file_data_add_ci(fd, type, NULL, NULL);
file_data_add_ci(sfd, type, NULL, NULL);
work = work->next;
}
file_data_add_ci(sfd, type, NULL, NULL);
work = work->next;
}
static gboolean file_data_sc_add_ci_list_call_func(GList *fd_list, const gchar *dest, gboolean (*func)(FileData *, const gchar *))
{
GList *work;
static gboolean file_data_sc_add_ci_list_call_func(GList *fd_list, const gchar *dest, gboolean (*func)(FileData *, const gchar *))
{
GList *work;
static void file_data_update_planned_change_hash(FileData *fd, const gchar *old_path, gchar *new_path)
{
FileDataChangeType type = fd->change->type;
static void file_data_update_planned_change_hash(FileData *fd, const gchar *old_path, gchar *new_path)
{
FileDataChangeType type = fd->change->type;
if (!file_data_planned_change_hash)
file_data_planned_change_hash = g_hash_table_new(g_str_hash, g_str_equal);
if (!file_data_planned_change_hash)
file_data_planned_change_hash = g_hash_table_new(g_str_hash, g_str_equal);
if (old_path && g_hash_table_lookup(file_data_planned_change_hash, old_path) == fd)
{
DEBUG_1("planned change: removing %s -> %s", old_path, fd->path);
if (old_path && g_hash_table_lookup(file_data_planned_change_hash, old_path) == fd)
{
DEBUG_1("planned change: removing %s -> %s", old_path, fd->path);
DEBUG_1("planned change: inserting %s -> %s", new_path, fd->path);
file_data_ref(fd);
g_hash_table_insert(file_data_planned_change_hash, new_path, fd);
DEBUG_1("planned change: inserting %s -> %s", new_path, fd->path);
file_data_ref(fd);
g_hash_table_insert(file_data_planned_change_hash, new_path, fd);
const gchar *extension = extension_from_path(fd->change->source);
gchar *base = remove_extension_from_path(dest_path);
gchar *old_path = fd->change->dest;
const gchar *extension = extension_from_path(fd->change->source);
gchar *base = remove_extension_from_path(dest_path);
gchar *old_path = fd->change->dest;
fd->change->dest = g_strconcat(base, extension, NULL);
file_data_update_planned_change_hash(fd, old_path, fd->change->dest);
fd->change->dest = g_strconcat(base, extension, NULL);
file_data_update_planned_change_hash(fd, old_path, fd->change->dest);
else if (!strchr(dest_path, G_DIR_SEPARATOR)) /* we got only filename, not a full path */
{
gchar *dir = remove_level_from_path(fd->path);
else if (!strchr(dest_path, G_DIR_SEPARATOR)) /* we got only filename, not a full path */
{
gchar *dir = remove_level_from_path(fd->path);
dest_path_full = g_build_filename(dir, dest_path, NULL);
g_free(dir);
dest_path = dest_path_full;
dest_path_full = g_build_filename(dir, dest_path, NULL);
g_free(dir);
dest_path = dest_path_full;
dest_path_full = g_build_filename(dest_path, fd->name, NULL);
dest_path = dest_path_full;
}
dest_path_full = g_build_filename(dest_path, fd->name, NULL);
dest_path = dest_path_full;
}
gboolean file_data_sc_update_ci_move(FileData *fd, const gchar *dest_path)
{
return file_data_sc_check_update_ci(fd, dest_path, FILEDATA_CHANGE_MOVE);
gboolean file_data_sc_update_ci_move(FileData *fd, const gchar *dest_path)
{
return file_data_sc_check_update_ci(fd, dest_path, FILEDATA_CHANGE_MOVE);
if (fd->change->type != FILEDATA_CHANGE_DELETE &&
fd->change->type != FILEDATA_CHANGE_MOVE && /* the unsaved metadata should survive move and rename operations */
fd->change->type != FILEDATA_CHANGE_RENAME &&
if (fd->change->type != FILEDATA_CHANGE_DELETE &&
fd->change->type != FILEDATA_CHANGE_MOVE && /* the unsaved metadata should survive move and rename operations */
fd->change->type != FILEDATA_CHANGE_RENAME &&
ret |= CHANGE_WARN_UNSAVED_META;
DEBUG_1("Change checked: unsaved metadata: %s", fd->path);
}
ret |= CHANGE_WARN_UNSAVED_META;
DEBUG_1("Change checked: unsaved metadata: %s", fd->path);
}
if (fd->change->type != FILEDATA_CHANGE_DELETE &&
fd->change->type != FILEDATA_CHANGE_WRITE_METADATA &&
!access_file(fd->path, R_OK))
if (fd->change->type != FILEDATA_CHANGE_DELETE &&
fd->change->type != FILEDATA_CHANGE_WRITE_METADATA &&
!access_file(fd->path, R_OK))
metadata_path = cache_find_location(CACHE_TYPE_XMP_METADATA, fd->path);
#endif
if (!metadata_path) metadata_path = cache_find_location(CACHE_TYPE_METADATA, fd->path);
metadata_path = cache_find_location(CACHE_TYPE_XMP_METADATA, fd->path);
#endif
if (!metadata_path) metadata_path = cache_find_location(CACHE_TYPE_METADATA, fd->path);
if (recursive_mkdir_if_not_exists(dest_dir, mode))
{
gchar *filename = g_strconcat(fd->name, options->metadata.save_legacy_format ? GQ_CACHE_EXT_METADATA : GQ_CACHE_EXT_XMP_METADATA, NULL);
if (recursive_mkdir_if_not_exists(dest_dir, mode))
{
gchar *filename = g_strconcat(fd->name, options->metadata.save_legacy_format ? GQ_CACHE_EXT_METADATA : GQ_CACHE_EXT_XMP_METADATA, NULL);
if (result->len > 0) g_string_append(result, ", ");
g_string_append(result, _("destination already exists and will be overwritten"));
}
if (result->len > 0) g_string_append(result, ", ");
g_string_append(result, _("destination already exists and will be overwritten"));
}
if (error & CHANGE_WARN_SAME)
{
if (result->len > 0) g_string_append(result, ", ");
if (error & CHANGE_WARN_SAME)
{
if (result->len > 0) g_string_append(result, ", ");
num = g_list_length(list);
errors = g_new(int, num);
work = list;
num = g_list_length(list);
errors = g_new(int, num);
work = list;
if (!file_data_sc_check_ci(fd, type)) return FALSE;
work = fd->sidecar_files;
while (work)
{
FileData *sfd = work->data;
if (!file_data_sc_check_ci(fd, type)) return FALSE;
work = fd->sidecar_files;
while (work)
{
FileData *sfd = work->data;
{
DEBUG_1("planned change: applying %s -> %s", fd->change->dest, fd->path);
file_data_planned_change_remove(fd);
{
DEBUG_1("planned change: applying %s -> %s", fd->change->dest, fd->path);
file_data_planned_change_remove(fd);
if (g_hash_table_lookup(file_data_pool, fd->change->dest))
{
/* this change overwrites another file which is already known to other modules
if (g_hash_table_lookup(file_data_pool, fd->change->dest))
{
/* this change overwrites another file which is already known to other modules
}
file_data_increment_version(fd);
file_data_send_notification(fd, NOTIFY_CHANGE);
}
file_data_increment_version(fd);
file_data_send_notification(fd, NOTIFY_CHANGE);
if (!file_data_sc_check_ci(fd, type)) return FALSE;
work = fd->sidecar_files;
while (work)
{
FileData *sfd = work->data;
if (!file_data_sc_check_ci(fd, type)) return FALSE;
work = fd->sidecar_files;
while (work)
{
FileData *sfd = work->data;
GList *work;
if (fd->parent) fd = fd->parent;
if (!g_list_find(list, fd)) return FALSE;
GList *work;
if (fd->parent) fd = fd->parent;
if (!g_list_find(list, fd)) return FALSE;
if (!file_data_list_contains_whole_group(list, fd))
{
file_data_disable_grouping(fd, TRUE);
if (!file_data_list_contains_whole_group(list, fd))
{
file_data_disable_grouping(fd, TRUE);
/* remove sidecars from the list,
they can be still acessed via main_fd->sidecar_files */
work = list;
/* remove sidecars from the list,
they can be still acessed via main_fd->sidecar_files */
work = list;
if (!fd->parent ||
(!ungroup && !file_data_list_contains_whole_group(list, fd)))
{
out = g_list_prepend(out, file_data_ref(fd));
}
}
if (!fd->parent ||
(!ungroup && !file_data_list_contains_whole_group(list, fd)))
{
out = g_list_prepend(out, file_data_ref(fd));
}
}
notify_func_list = g_list_insert_sorted(notify_func_list, nd, file_data_notify_sort);
DEBUG_2("Notify func registered: %p", nd);
notify_func_list = g_list_insert_sorted(notify_func_list, nd, file_data_notify_sort);
DEBUG_2("Notify func registered: %p", nd);
return TRUE;
}
gboolean file_data_unregister_notify_func(FileDataNotifyFunc func, gpointer data)
{
GList *work = notify_func_list;
return TRUE;
}
gboolean file_data_unregister_notify_func(FileDataNotifyFunc func, gpointer data)
{
GList *work = notify_func_list;
if (nd->func == func && nd->data == data)
{
notify_func_list = g_list_delete_link(notify_func_list, work);
if (nd->func == func && nd->data == data)
{
notify_func_list = g_list_delete_link(notify_func_list, work);
if (!file_data_monitor_pool)
file_data_monitor_pool = g_hash_table_new(g_direct_hash, g_direct_equal);
if (!file_data_monitor_pool)
file_data_monitor_pool = g_hash_table_new(g_direct_hash, g_direct_equal);
count = GPOINTER_TO_INT(g_hash_table_lookup(file_data_monitor_pool, fd));
DEBUG_1("Register realtime %d %s", count, fd->path);
count = GPOINTER_TO_INT(g_hash_table_lookup(file_data_monitor_pool, fd));
DEBUG_1("Register realtime %d %s", count, fd->path);
if (!realtime_monitor_id)
{
realtime_monitor_id = g_timeout_add(5000, realtime_monitor_cb, NULL);
}
if (!realtime_monitor_id)
{
realtime_monitor_id = g_timeout_add(5000, realtime_monitor_cb, NULL);
}
if (count == 0)
g_hash_table_remove(file_data_monitor_pool, fd);
else
g_hash_table_insert(file_data_monitor_pool, fd, GINT_TO_POINTER(count));
file_data_unref(fd);
if (count == 0)
g_hash_table_remove(file_data_monitor_pool, fd);
else
g_hash_table_insert(file_data_monitor_pool, fd, GINT_TO_POINTER(count));
file_data_unref(fd);