Mercurial > geeqie
annotate src/filedata.c @ 751:f73df252aa05
improved filedata interface
| author | nadvornik |
|---|---|
| date | Sat, 24 May 2008 09:18:09 +0000 |
| parents | eda074e91ddd |
| children | 477f48ba28d8 |
| rev | line source |
|---|---|
| 586 | 1 /* |
| 2 * Geeqie | |
| 3 * (C) 2006 John Ellis | |
| 4 * Copyright (C) 2008 The Geeqie Team | |
| 5 * | |
| 6 * Author: John Ellis | |
| 7 * | |
| 8 * This software is released under the GNU General Public License (GNU GPL). | |
| 9 * Please read the included file COPYING for more information. | |
| 10 * This software comes with no warranty of any kind, use at your own risk! | |
| 11 */ | |
| 12 | |
| 13 | |
| 14 #include "main.h" | |
| 15 #include "filedata.h" | |
| 16 | |
| 17 #include "filefilter.h" | |
| 18 #include "cache.h" | |
| 19 #include "rcfile.h" | |
| 20 #include "secure_save.h" | |
| 21 #include "thumb_standard.h" | |
| 22 #include "ui_fileops.h" | |
| 23 | |
| 24 | |
| 25 static gint sidecar_file_priority(const gchar *path); | |
| 26 | |
| 27 | |
| 28 /* | |
| 29 *----------------------------------------------------------------------------- | |
| 30 * text conversion utils | |
| 31 *----------------------------------------------------------------------------- | |
| 32 */ | |
| 33 | |
| 34 gchar *text_from_size(gint64 size) | |
| 35 { | |
| 36 gchar *a, *b; | |
| 37 gchar *s, *d; | |
| 38 gint l, n, i; | |
| 39 | |
| 40 /* what I would like to use is printf("%'d", size) | |
| 41 * BUT: not supported on every libc :( | |
| 42 */ | |
| 43 if (size > G_MAXUINT) | |
| 44 { | |
| 45 /* the %lld conversion is not valid in all libcs, so use a simple work-around */ | |
| 46 a = g_strdup_printf("%d%09d", (guint)(size / 1000000000), (guint)(size % 1000000000)); | |
| 47 } | |
| 48 else | |
| 49 { | |
| 50 a = g_strdup_printf("%d", (guint)size); | |
| 51 } | |
| 52 l = strlen(a); | |
| 53 n = (l - 1)/ 3; | |
| 54 if (n < 1) return a; | |
| 55 | |
| 56 b = g_new(gchar, l + n + 1); | |
| 57 | |
| 58 s = a; | |
| 59 d = b; | |
| 60 i = l - n * 3; | |
| 61 while (*s != '\0') | |
| 62 { | |
| 63 if (i < 1) | |
| 64 { | |
| 65 i = 3; | |
| 66 *d = ','; | |
| 67 d++; | |
| 68 } | |
| 69 | |
| 70 *d = *s; | |
| 71 s++; | |
| 72 d++; | |
| 73 i--; | |
| 74 } | |
| 75 *d = '\0'; | |
| 76 | |
| 77 g_free(a); | |
| 78 return b; | |
| 79 } | |
| 80 | |
| 81 gchar *text_from_size_abrev(gint64 size) | |
| 82 { | |
| 83 if (size < (gint64)1024) | |
| 84 { | |
| 85 return g_strdup_printf(_("%d bytes"), (gint)size); | |
| 86 } | |
| 87 if (size < (gint64)1048576) | |
| 88 { | |
| 89 return g_strdup_printf(_("%.1f K"), (double)size / 1024.0); | |
| 90 } | |
| 91 if (size < (gint64)1073741824) | |
| 92 { | |
| 93 return g_strdup_printf(_("%.1f MB"), (double)size / 1048576.0); | |
| 94 } | |
| 95 | |
| 96 /* to avoid overflowing the double, do division in two steps */ | |
| 97 size /= 1048576; | |
| 98 return g_strdup_printf(_("%.1f GB"), (double)size / 1024.0); | |
| 99 } | |
| 100 | |
| 101 /* note: returned string is valid until next call to text_from_time() */ | |
| 102 const gchar *text_from_time(time_t t) | |
| 103 { | |
| 104 static gchar *ret = NULL; | |
| 105 gchar buf[128]; | |
| 106 gint buflen; | |
| 107 struct tm *btime; | |
| 108 GError *error = NULL; | |
| 109 | |
| 110 btime = localtime(&t); | |
| 111 | |
| 112 /* the %x warning about 2 digit years is not an error */ | |
| 113 buflen = strftime(buf, sizeof(buf), "%x %H:%M", btime); | |
| 114 if (buflen < 1) return ""; | |
| 115 | |
| 116 g_free(ret); | |
| 117 ret = g_locale_to_utf8(buf, buflen, NULL, NULL, &error); | |
| 118 if (error) | |
| 119 { | |
|
673
fbebf5cf4a55
Do not use printf() directly but use new wrapper function log_printf() instead.
zas_
parents:
671
diff
changeset
|
120 log_printf("Error converting locale strftime to UTF-8: %s\n", error->message); |
| 586 | 121 g_error_free(error); |
| 122 return ""; | |
| 123 } | |
| 124 | |
| 125 return ret; | |
| 126 } | |
| 127 | |
| 128 /* | |
| 129 *----------------------------------------------------------------------------- | |
| 130 * file info struct | |
| 131 *----------------------------------------------------------------------------- | |
| 132 */ | |
| 133 | |
| 134 FileData *file_data_merge_sidecar_files(FileData *target, FileData *source); | |
| 135 static void file_data_check_sidecars(FileData *fd); | |
| 136 FileData *file_data_disconnect_sidecar_file(FileData *target, FileData *sfd); | |
| 137 | |
| 138 | |
| 139 static void file_data_set_path(FileData *fd, const gchar *path) | |
| 140 { | |
| 141 | |
| 725 | 142 if (strcmp(path, G_DIR_SEPARATOR_S) == 0) |
| 586 | 143 { |
| 144 fd->path = g_strdup(path); | |
| 145 fd->name = fd->path; | |
| 146 fd->extension = fd->name + 1; | |
| 147 return; | |
| 148 } | |
| 149 | |
| 150 fd->path = g_strdup(path); | |
| 151 fd->name = filename_from_path(fd->path); | |
| 152 | |
| 153 if (strcmp(fd->name, "..") == 0) | |
| 154 { | |
| 155 gchar *dir = remove_level_from_path(path); | |
| 156 g_free(fd->path); | |
| 157 fd->path = remove_level_from_path(dir); | |
| 158 g_free(dir); | |
| 159 fd->name = ".."; | |
| 160 fd->extension = fd->name + 2; | |
| 161 return; | |
| 162 } | |
| 163 else if (strcmp(fd->name, ".") == 0) | |
| 164 { | |
| 165 g_free(fd->path); | |
| 166 fd->path = remove_level_from_path(path); | |
| 167 fd->name = "."; | |
| 168 fd->extension = fd->name + 1; | |
| 169 return; | |
| 170 } | |
| 171 | |
| 172 fd->extension = extension_from_path(fd->path); | |
| 173 if (fd->extension == NULL) | |
| 174 fd->extension = fd->name + strlen(fd->name); | |
| 175 } | |
| 176 | |
| 177 static void file_data_check_changed_files(FileData *fd, struct stat *st) | |
| 178 { | |
| 179 GList *work; | |
| 180 if (fd->size != st->st_size || | |
| 181 fd->date != st->st_mtime) | |
| 182 { | |
| 183 fd->size = st->st_size; | |
| 184 fd->date = st->st_mtime; | |
| 185 if (fd->pixbuf) g_object_unref(fd->pixbuf); | |
| 186 fd->pixbuf = NULL; | |
| 187 } | |
| 188 | |
| 189 work = fd->sidecar_files; | |
| 190 while (work) | |
| 191 { | |
| 192 FileData *sfd = work->data; | |
| 193 struct stat st; | |
| 194 | |
| 195 if (!stat_utf8(sfd->path, &st)) | |
| 196 { | |
| 197 file_data_disconnect_sidecar_file(fd, sfd); | |
| 198 } | |
| 199 | |
| 200 file_data_check_changed_files(sfd, &st); | |
| 201 work = work->next; | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 static GHashTable *file_data_pool = NULL; | |
| 206 | |
| 207 static FileData *file_data_new(const gchar *path_utf8, struct stat *st, gboolean check_sidecars) | |
| 208 { | |
| 209 FileData *fd; | |
| 210 | |
| 211 DEBUG_2("file_data_new: '%s' %d", path_utf8, check_sidecars); | |
| 212 | |
| 213 if (!file_data_pool) | |
| 214 file_data_pool = g_hash_table_new(g_str_hash, g_str_equal); | |
| 215 | |
| 216 fd = g_hash_table_lookup(file_data_pool, path_utf8); | |
| 217 if (fd) | |
| 218 { | |
| 219 file_data_check_changed_files(fd, st); | |
| 220 DEBUG_2("file_data_pool hit: '%s'", fd->path); | |
| 221 return file_data_ref(fd); | |
| 222 } | |
| 223 | |
| 224 fd = g_new0(FileData, 1); | |
| 225 | |
| 226 file_data_set_path(fd, path_utf8); | |
| 227 | |
| 228 fd->original_path = g_strdup(path_utf8); | |
| 229 fd->size = st->st_size; | |
| 230 fd->date = st->st_mtime; | |
| 231 fd->pixbuf = NULL; | |
| 232 fd->sidecar_files = NULL; | |
| 233 fd->ref = 1; | |
| 234 fd->magick = 0x12345678; | |
| 235 | |
| 236 g_hash_table_insert(file_data_pool, fd->original_path, fd); | |
| 237 | |
| 238 if (check_sidecars && sidecar_file_priority(fd->extension)) | |
| 239 file_data_check_sidecars(fd); | |
| 240 return fd; | |
| 241 } | |
| 242 | |
| 243 static void file_data_check_sidecars(FileData *fd) | |
| 244 { | |
| 245 int base_len = fd->extension - fd->path; | |
| 246 GString *fname = g_string_new_len(fd->path, base_len); | |
| 247 FileData *parent_fd = NULL; | |
| 248 GList *work = sidecar_ext_get_list(); | |
| 249 while (work) | |
| 250 { | |
| 251 /* check for possible sidecar files; | |
| 252 the sidecar files created here are referenced only via fd->sidecar_files or fd->parent, | |
| 253 they have fd->ref set to 0 and file_data unref must chack and free them all together | |
| 254 (using fd->ref would cause loops and leaks) | |
| 255 */ | |
| 256 | |
| 257 FileData *new_fd; | |
| 258 | |
| 259 gchar *ext = work->data; | |
| 260 work = work->next; | |
| 261 | |
| 262 if (strcmp(ext, fd->extension) == 0) | |
| 263 { | |
| 264 new_fd = fd; /* processing the original file */ | |
| 265 } | |
| 266 else | |
| 267 { | |
| 268 struct stat nst; | |
| 269 g_string_truncate(fname, base_len); | |
| 270 g_string_append(fname, ext); | |
| 271 | |
| 272 if (!stat_utf8(fname->str, &nst)) | |
| 273 continue; | |
| 274 | |
| 275 new_fd = file_data_new(fname->str, &nst, FALSE); | |
| 276 new_fd->ref--; /* do not use ref here */ | |
| 277 } | |
| 278 | |
| 279 if (!parent_fd) | |
| 280 parent_fd = new_fd; /* parent is the one with the highest prio, found first */ | |
| 281 else | |
| 282 file_data_merge_sidecar_files(parent_fd, new_fd); | |
| 283 } | |
| 284 g_string_free(fname, TRUE); | |
| 285 } | |
| 286 | |
| 287 | |
| 288 static FileData *file_data_new_local(const gchar *path, struct stat *st, gboolean check_sidecars) | |
| 289 { | |
| 290 gchar *path_utf8 = path_to_utf8(path); | |
| 291 FileData *ret = file_data_new(path_utf8, st, check_sidecars); | |
| 292 g_free(path_utf8); | |
| 293 return ret; | |
| 294 } | |
| 295 | |
| 296 FileData *file_data_new_simple(const gchar *path_utf8) | |
| 297 { | |
| 298 struct stat st; | |
| 299 | |
| 300 if (!stat_utf8(path_utf8, &st)) | |
| 301 { | |
| 302 st.st_size = 0; | |
| 303 st.st_mtime = 0; | |
| 304 } | |
| 305 | |
| 306 return file_data_new(path_utf8, &st, TRUE); | |
| 307 } | |
| 308 | |
| 309 FileData *file_data_add_sidecar_file(FileData *target, FileData *sfd) | |
| 310 { | |
| 311 sfd->parent = target; | |
| 312 if(!g_list_find(target->sidecar_files, sfd)) | |
| 313 target->sidecar_files = g_list_prepend(target->sidecar_files, sfd); | |
| 314 return target; | |
| 315 } | |
| 316 | |
| 317 | |
| 318 FileData *file_data_merge_sidecar_files(FileData *target, FileData *source) | |
| 319 { | |
| 320 GList *work; | |
| 321 file_data_add_sidecar_file(target, source); | |
| 322 | |
| 323 work = source->sidecar_files; | |
| 324 while (work) | |
| 325 { | |
| 326 FileData *sfd = work->data; | |
| 327 file_data_add_sidecar_file(target, sfd); | |
| 328 work = work->next; | |
| 329 } | |
| 330 | |
| 331 g_list_free(source->sidecar_files); | |
| 332 source->sidecar_files = NULL; | |
| 333 | |
| 334 target->sidecar_files = filelist_sort(target->sidecar_files, SORT_NAME, TRUE); | |
| 335 return target; | |
| 336 } | |
| 337 | |
| 338 | |
| 339 | |
| 340 FileData *file_data_ref(FileData *fd) | |
| 341 { | |
| 342 if (fd == NULL) return NULL; | |
| 343 | |
| 344 // return g_memdup(fd, sizeof(FileData)); | |
| 345 g_assert(fd->magick == 0x12345678); | |
| 346 fd->ref++; | |
| 347 return fd; | |
| 348 } | |
| 349 | |
| 350 static void file_data_free(FileData *fd) | |
| 351 { | |
| 352 g_assert(fd->magick == 0x12345678); | |
| 353 g_assert(fd->ref == 0); | |
| 354 | |
| 355 g_hash_table_remove(file_data_pool, fd->original_path); | |
| 356 | |
| 357 g_free(fd->path); | |
| 358 g_free(fd->original_path); | |
| 359 if (fd->pixbuf) g_object_unref(fd->pixbuf); | |
| 360 | |
| 361 | |
| 362 g_assert(fd->sidecar_files == NULL); /* sidecar files must be freed before calling this */ | |
| 363 | |
| 364 file_data_change_info_free(NULL, fd); | |
| 365 g_free(fd); | |
| 366 } | |
| 367 | |
| 368 void file_data_unref(FileData *fd) | |
| 369 { | |
| 370 if (fd == NULL) return; | |
| 371 g_assert(fd->magick == 0x12345678); | |
| 372 | |
| 373 fd->ref--; | |
| 374 DEBUG_2("file_data_unref (%d): '%s'", fd->ref, fd->path); | |
| 375 | |
| 376 if (fd->ref == 0) | |
| 377 { | |
| 378 FileData *parent = fd->parent ? fd->parent : fd; | |
| 379 | |
| 380 GList *work; | |
| 381 | |
| 382 if (parent->ref > 0) | |
| 383 return; | |
| 384 | |
| 385 work = parent->sidecar_files; | |
| 386 while (work) | |
| 387 { | |
| 388 FileData *sfd = work->data; | |
| 389 if (sfd->ref > 0) | |
| 390 return; | |
| 391 work = work->next; | |
| 392 } | |
| 393 | |
| 394 /* none of parent/children is referenced, we can free everything */ | |
| 395 | |
| 396 DEBUG_2("file_data_unref: deleting '%s', parent '%s'", fd->path, parent->path); | |
| 397 | |
| 398 work = parent->sidecar_files; | |
| 399 while (work) | |
| 400 { | |
| 401 FileData *sfd = work->data; | |
| 402 file_data_free(sfd); | |
| 403 work = work->next; | |
| 404 } | |
| 405 | |
| 406 g_list_free(parent->sidecar_files); | |
| 407 parent->sidecar_files = NULL; | |
| 408 | |
| 409 file_data_free(parent); | |
| 410 | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 FileData *file_data_disconnect_sidecar_file(FileData *target, FileData *sfd) | |
| 415 { | |
| 416 sfd->parent = target; | |
| 417 g_assert(g_list_find(target->sidecar_files, sfd)); | |
| 418 | |
| 419 target->sidecar_files = g_list_remove(target->sidecar_files, sfd); | |
| 420 sfd->parent = NULL; | |
| 421 | |
| 422 if (sfd->ref == 0) { | |
| 423 file_data_free(sfd); | |
| 424 return NULL; | |
| 425 } | |
| 426 | |
| 427 return sfd; | |
| 428 } | |
| 429 | |
| 430 /* compare name without extension */ | |
| 431 gint file_data_compare_name_without_ext(FileData *fd1, FileData *fd2) | |
| 432 { | |
| 433 size_t len1 = fd1->extension - fd1->name; | |
| 434 size_t len2 = fd2->extension - fd2->name; | |
| 435 | |
| 436 if (len1 < len2) return -1; | |
| 437 if (len1 > len2) return 1; | |
| 438 | |
| 439 return strncmp(fd1->name, fd2->name, len1); | |
| 440 } | |
| 441 | |
| 442 gboolean file_data_add_change_info(FileData *fd, FileDataChangeType type, const gchar *src, const gchar *dest) | |
| 443 { | |
| 444 | |
| 445 FileDataChangeInfo *fdci; | |
| 446 | |
| 447 if (fd->change) return FALSE; | |
| 448 | |
| 449 fdci = g_new0(FileDataChangeInfo, 1); | |
| 450 | |
| 451 fdci->type = type; | |
| 452 | |
| 453 if (src) | |
| 454 fdci->source = g_strdup(src); | |
| 455 else | |
| 456 fdci->source = g_strdup(fd->path); | |
| 457 | |
| 458 if (dest) | |
| 459 fdci->dest = g_strdup(dest); | |
| 460 | |
| 461 fd->change = fdci; | |
| 462 return TRUE; | |
| 463 } | |
| 464 | |
| 465 void file_data_change_info_free(FileDataChangeInfo *fdci, FileData *fd) | |
| 466 { | |
| 467 if (!fdci && fd) | |
| 468 fdci = fd->change; | |
| 469 | |
| 470 if (!fdci) | |
| 471 return; | |
| 472 | |
| 473 g_free(fdci->source); | |
| 474 g_free(fdci->dest); | |
| 475 | |
| 476 g_free(fdci); | |
| 477 | |
| 478 if (fd) | |
| 479 fd->change = NULL; | |
| 480 } | |
| 481 | |
| 482 | |
| 483 | |
| 484 | |
| 485 /* | |
| 486 *----------------------------------------------------------------------------- | |
| 487 * sidecar file info struct | |
| 488 *----------------------------------------------------------------------------- | |
| 489 */ | |
| 490 | |
| 491 | |
| 492 | |
| 493 static gint sidecar_file_priority(const gchar *path) | |
| 494 { | |
| 495 const char *extension = extension_from_path(path); | |
| 496 int i = 1; | |
| 497 GList *work; | |
| 498 if (extension == NULL) | |
| 499 return 0; | |
| 500 | |
| 501 work = sidecar_ext_get_list(); | |
| 502 | |
| 503 while (work) { | |
| 504 gchar *ext = work->data; | |
| 505 work = work->next; | |
| 506 if (strcmp(extension, ext) == 0) return i; | |
| 507 i++; | |
| 508 } | |
| 509 return 0; | |
| 510 } | |
| 511 | |
| 512 | |
| 513 /* | |
| 514 *----------------------------------------------------------------------------- | |
| 515 * load file list | |
| 516 *----------------------------------------------------------------------------- | |
| 517 */ | |
| 518 | |
| 519 static SortType filelist_sort_method = SORT_NONE; | |
| 520 static gint filelist_sort_ascend = TRUE; | |
| 521 | |
| 522 | |
| 523 gint filelist_sort_compare_filedata(FileData *fa, FileData *fb) | |
| 524 { | |
| 525 if (!filelist_sort_ascend) | |
| 526 { | |
| 527 FileData *tmp = fa; | |
| 528 fa = fb; | |
| 529 fb = tmp; | |
| 530 } | |
| 531 | |
| 532 switch (filelist_sort_method) | |
| 533 { | |
| 534 case SORT_SIZE: | |
| 535 if (fa->size < fb->size) return -1; | |
| 536 if (fa->size > fb->size) return 1; | |
| 537 return CASE_SORT(fa->name, fb->name); /* fall back to name */ | |
| 538 break; | |
| 539 case SORT_TIME: | |
| 540 if (fa->date < fb->date) return -1; | |
| 541 if (fa->date > fb->date) return 1; | |
| 542 return CASE_SORT(fa->name, fb->name); /* fall back to name */ | |
| 543 break; | |
| 544 #ifdef HAVE_STRVERSCMP | |
| 545 case SORT_NUMBER: | |
| 546 return strverscmp(fa->name, fb->name); | |
| 547 break; | |
| 548 #endif | |
| 549 case SORT_NAME: | |
| 550 default: | |
| 551 return CASE_SORT(fa->name, fb->name); | |
| 552 break; | |
| 553 } | |
| 554 } | |
| 555 | |
| 556 gint filelist_sort_compare_filedata_full(FileData *fa, FileData *fb, SortType method, gint ascend) | |
| 557 { | |
| 558 filelist_sort_method = method; | |
| 559 filelist_sort_ascend = ascend; | |
| 560 return filelist_sort_compare_filedata(fa, fb); | |
| 561 } | |
| 562 | |
| 563 static gint filelist_sort_file_cb(void *a, void *b) | |
| 564 { | |
| 565 return filelist_sort_compare_filedata(a, b); | |
| 566 } | |
| 567 | |
| 568 GList *filelist_sort_full(GList *list, SortType method, gint ascend, GCompareFunc cb) | |
| 569 { | |
| 570 filelist_sort_method = method; | |
| 571 filelist_sort_ascend = ascend; | |
| 572 return g_list_sort(list, cb); | |
| 573 } | |
| 574 | |
| 575 GList *filelist_insert_sort_full(GList *list, void *data, SortType method, gint ascend, GCompareFunc cb) | |
| 576 { | |
| 577 filelist_sort_method = method; | |
| 578 filelist_sort_ascend = ascend; | |
| 579 return g_list_insert_sorted(list, data, cb); | |
| 580 } | |
| 581 | |
| 582 GList *filelist_sort(GList *list, SortType method, gint ascend) | |
| 583 { | |
| 584 return filelist_sort_full(list, method, ascend, (GCompareFunc) filelist_sort_file_cb); | |
| 585 } | |
| 586 | |
| 587 GList *filelist_insert_sort(GList *list, FileData *fd, SortType method, gint ascend) | |
| 588 { | |
| 589 return filelist_insert_sort_full(list, fd, method, ascend, (GCompareFunc) filelist_sort_file_cb); | |
| 590 } | |
| 591 | |
| 592 | |
| 593 static GList *filelist_filter_out_sidecars(GList *flist) | |
| 594 { | |
| 595 GList *work = flist; | |
| 596 GList *flist_filtered = NULL; | |
| 597 | |
| 598 while (work) | |
| 599 { | |
| 600 FileData *fd = work->data; | |
| 601 work = work->next; | |
| 602 if (fd->parent) /* remove fd's that are children */ | |
| 603 file_data_unref(fd); | |
| 604 else | |
| 605 flist_filtered = g_list_prepend(flist_filtered, fd); | |
| 606 } | |
| 607 g_list_free(flist); | |
| 608 return flist_filtered; | |
| 609 } | |
| 610 | |
| 611 static gint filelist_read_real(const gchar *path, GList **files, GList **dirs, gint follow_symlinks) | |
| 612 { | |
| 613 DIR *dp; | |
| 614 struct dirent *dir; | |
| 615 struct stat ent_sbuf; | |
| 616 gchar *pathl; | |
| 617 GList *dlist; | |
| 618 GList *flist; | |
| 619 | |
| 620 dlist = NULL; | |
| 621 flist = NULL; | |
| 622 | |
| 623 pathl = path_from_utf8(path); | |
| 624 if (!pathl || (dp = opendir(pathl)) == NULL) | |
| 625 { | |
| 626 g_free(pathl); | |
| 627 if (files) *files = NULL; | |
| 628 if (dirs) *dirs = NULL; | |
| 629 return FALSE; | |
| 630 } | |
| 631 | |
| 632 while ((dir = readdir(dp)) != NULL) | |
| 633 { | |
| 634 gchar *name = dir->d_name; | |
| 635 if (options->file_filter.show_hidden_files || !ishidden(name)) | |
| 636 { | |
| 712 | 637 gchar *filepath = g_build_filename(pathl, name, NULL); |
| 586 | 638 if ((follow_symlinks ? |
| 639 stat(filepath, &ent_sbuf) : | |
| 640 lstat(filepath, &ent_sbuf)) >= 0) | |
| 641 { | |
| 642 if (S_ISDIR(ent_sbuf.st_mode)) | |
| 643 { | |
| 644 /* we ignore the .thumbnails dir for cleanliness */ | |
| 645 if ((dirs) && | |
| 646 !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) && | |
| 647 strcmp(name, GQ_CACHE_LOCAL_THUMB) != 0 && | |
| 648 strcmp(name, GQ_CACHE_LOCAL_METADATA) != 0 && | |
| 649 strcmp(name, THUMB_FOLDER_LOCAL) != 0) | |
| 650 { | |
| 651 dlist = g_list_prepend(dlist, file_data_new_local(filepath, &ent_sbuf, FALSE)); | |
| 652 } | |
| 653 } | |
| 654 else | |
| 655 { | |
| 656 if ((files) && filter_name_exists(name)) | |
| 657 { | |
| 658 flist = g_list_prepend(flist, file_data_new_local(filepath, &ent_sbuf, TRUE)); | |
| 659 } | |
| 660 } | |
| 661 } | |
| 662 g_free(filepath); | |
| 663 } | |
| 664 } | |
| 665 | |
| 666 closedir(dp); | |
| 667 | |
| 668 g_free(pathl); | |
| 669 | |
| 670 flist = filelist_filter_out_sidecars(flist); | |
| 671 | |
| 672 if (dirs) *dirs = dlist; | |
| 673 if (files) *files = flist; | |
| 674 | |
| 675 return TRUE; | |
| 676 } | |
| 677 | |
| 678 gint filelist_read(const gchar *path, GList **files, GList **dirs) | |
| 679 { | |
| 680 return filelist_read_real(path, files, dirs, TRUE); | |
| 681 } | |
| 682 | |
| 683 gint filelist_read_lstat(const gchar *path, GList **files, GList **dirs) | |
| 684 { | |
| 685 return filelist_read_real(path, files, dirs, FALSE); | |
| 686 } | |
| 687 | |
| 688 void filelist_free(GList *list) | |
| 689 { | |
| 690 GList *work; | |
| 691 | |
| 692 work = list; | |
| 693 while (work) | |
| 694 { | |
| 695 file_data_unref((FileData *)work->data); | |
| 696 work = work->next; | |
| 697 } | |
| 698 | |
| 699 g_list_free(list); | |
| 700 } | |
| 701 | |
| 702 | |
| 703 GList *filelist_copy(GList *list) | |
| 704 { | |
| 705 GList *new_list = NULL; | |
| 706 GList *work; | |
| 707 | |
| 708 work = list; | |
| 709 while (work) | |
| 710 { | |
| 711 FileData *fd; | |
| 712 | |
| 713 fd = work->data; | |
| 714 work = work->next; | |
| 715 | |
| 716 new_list = g_list_prepend(new_list, file_data_ref(fd)); | |
| 717 } | |
| 718 | |
| 719 return g_list_reverse(new_list); | |
| 720 } | |
| 721 | |
| 722 GList *filelist_from_path_list(GList *list) | |
| 723 { | |
| 724 GList *new_list = NULL; | |
| 725 GList *work; | |
| 726 | |
| 727 work = list; | |
| 728 while (work) | |
| 729 { | |
| 730 gchar *path; | |
| 731 | |
| 732 path = work->data; | |
| 733 work = work->next; | |
| 734 | |
| 735 new_list = g_list_prepend(new_list, file_data_new_simple(path)); | |
| 736 } | |
| 737 | |
| 738 return g_list_reverse(new_list); | |
| 739 } | |
| 740 | |
| 741 GList *filelist_to_path_list(GList *list) | |
| 742 { | |
| 743 GList *new_list = NULL; | |
| 744 GList *work; | |
| 745 | |
| 746 work = list; | |
| 747 while (work) | |
| 748 { | |
| 749 FileData *fd; | |
| 750 | |
| 751 fd = work->data; | |
| 752 work = work->next; | |
| 753 | |
| 754 new_list = g_list_prepend(new_list, g_strdup(fd->path)); | |
| 755 } | |
| 756 | |
| 757 return g_list_reverse(new_list); | |
| 758 } | |
| 759 | |
| 760 GList *filelist_filter(GList *list, gint is_dir_list) | |
| 761 { | |
| 762 GList *work; | |
| 763 | |
| 764 if (!is_dir_list && options->file_filter.disable && options->file_filter.show_hidden_files) return list; | |
| 765 | |
| 766 work = list; | |
| 767 while (work) | |
| 768 { | |
| 769 FileData *fd = (FileData *)(work->data); | |
| 770 const gchar *name = fd->name; | |
| 771 | |
| 772 if ((!options->file_filter.show_hidden_files && ishidden(name)) || | |
| 773 (!is_dir_list && !filter_name_exists(name)) || | |
| 774 (is_dir_list && name[0] == '.' && (strcmp(name, GQ_CACHE_LOCAL_THUMB) == 0 || | |
| 775 strcmp(name, GQ_CACHE_LOCAL_METADATA) == 0)) ) | |
| 776 { | |
| 777 GList *link = work; | |
| 778 work = work->next; | |
| 779 list = g_list_remove_link(list, link); | |
| 780 file_data_unref(fd); | |
| 781 g_list_free(link); | |
| 782 } | |
| 783 else | |
| 784 { | |
| 785 work = work->next; | |
| 786 } | |
| 787 } | |
| 788 | |
| 789 return list; | |
| 790 } | |
| 791 | |
| 792 /* | |
| 793 *----------------------------------------------------------------------------- | |
| 794 * filelist recursive | |
| 795 *----------------------------------------------------------------------------- | |
| 796 */ | |
| 797 | |
| 798 static gint filelist_sort_path_cb(gconstpointer a, gconstpointer b) | |
| 799 { | |
| 800 return CASE_SORT(((FileData *)a)->path, ((FileData *)b)->path); | |
| 801 } | |
| 802 | |
| 803 GList *filelist_sort_path(GList *list) | |
| 804 { | |
| 805 return g_list_sort(list, filelist_sort_path_cb); | |
| 806 } | |
| 807 | |
| 808 static void filelist_recursive_append(GList **list, GList *dirs) | |
| 809 { | |
| 810 GList *work; | |
| 811 | |
| 812 work = dirs; | |
| 813 while (work) | |
| 814 { | |
| 815 FileData *fd = (FileData *)(work->data); | |
| 816 const gchar *path = fd->path; | |
| 817 GList *f = NULL; | |
| 818 GList *d = NULL; | |
| 819 | |
| 820 if (filelist_read(path, &f, &d)) | |
| 821 { | |
| 822 f = filelist_filter(f, FALSE); | |
| 823 f = filelist_sort_path(f); | |
| 824 *list = g_list_concat(*list, f); | |
| 825 | |
| 826 d = filelist_filter(d, TRUE); | |
| 827 d = filelist_sort_path(d); | |
| 828 filelist_recursive_append(list, d); | |
| 829 filelist_free(d); | |
| 830 } | |
| 831 | |
| 832 work = work->next; | |
| 833 } | |
| 834 } | |
| 835 | |
| 836 GList *filelist_recursive(const gchar *path) | |
| 837 { | |
| 838 GList *list = NULL; | |
| 839 GList *d = NULL; | |
| 840 | |
| 841 if (!filelist_read(path, &list, &d)) return NULL; | |
| 842 list = filelist_filter(list, FALSE); | |
| 843 list = filelist_sort_path(list); | |
| 844 | |
| 845 d = filelist_filter(d, TRUE); | |
| 846 d = filelist_sort_path(d); | |
| 847 filelist_recursive_append(&list, d); | |
| 848 filelist_free(d); | |
| 849 | |
| 850 return list; | |
| 851 } | |
| 590 | 852 |
| 853 | |
| 854 | |
| 855 /* | |
| 856 * file_data - operates on the given fd | |
| 857 * file_data_sc - operates on the given fd + sidecars - all fds linked via fd->sidecar_files or fd->parent | |
| 858 */ | |
| 859 | |
| 860 | |
| 861 /* return list of sidecar file extensions in a string */ | |
| 596 | 862 gchar *file_data_sc_list_to_string(FileData *fd) |
| 863 { | |
| 864 GList *work; | |
| 865 GString *result = g_string_new(""); | |
| 866 | |
| 867 work = fd->sidecar_files; | |
| 868 while (work) | |
| 869 { | |
| 870 FileData *sfd = work->data; | |
| 871 result = g_string_append(result, "+ "); | |
| 872 result = g_string_append(result, sfd->extension); | |
| 873 work = work->next; | |
| 874 if (work) result = g_string_append_c(result, ' '); | |
| 875 } | |
| 876 | |
| 877 return g_string_free(result, FALSE); | |
| 878 } | |
| 590 | 879 |
| 880 | |
| 881 /* disables / enables grouping for particular file, sends UPDATE notification */ | |
| 882 void file_data_disable_grouping(FileData *fd); // now file_data_disconnect_sidecar_file, broken | |
| 883 void file_data_disable_grouping(FileData *fd); | |
| 884 | |
| 885 /* runs stat on a file and sends UPDATE notification if it has been changed */ | |
| 886 void file_data_sc_update(FileData *fd); | |
| 887 | |
| 888 | |
| 889 | |
| 890 | |
| 891 /* | |
| 892 * add FileDataChangeInfo (see typedefs.h) for the given operation | |
| 893 * uses file_data_add_change_info | |
| 894 * | |
| 895 * fails if the fd->change already exists - change operations can't run in parallel | |
| 896 * fd->change_info works as a lock | |
| 897 * | |
| 898 * dest can be NULL - in this case the current name is used for now, it will | |
| 899 * be changed later | |
| 900 */ | |
| 901 | |
| 902 /* | |
| 903 FileDataChangeInfo types: | |
| 904 COPY | |
| 905 MOVE - patch is changed, name may be changed too | |
| 906 RENAME - path remains unchanged, name is changed | |
| 907 extension should remain (FIXME should we allow editing extension? it will make problems wth grouping) | |
| 908 sidecar names are changed too, extensions are not changed | |
| 909 DELETE | |
| 910 UPDATE - file size, date or grouping has been changed | |
| 911 */ | |
| 912 | |
| 913 gboolean file_data_add_ci(FileData *fd, FileDataChangeType type, const gchar *src, const gchar *dest) | |
| 914 { | |
| 915 | |
| 916 FileDataChangeInfo *fdci; | |
| 917 | |
| 918 if (fd->change) return FALSE; | |
| 919 | |
| 920 fdci = g_new0(FileDataChangeInfo, 1); | |
| 921 | |
| 922 fdci->type = type; | |
| 923 | |
| 924 if (src) | |
| 925 fdci->source = g_strdup(src); | |
| 926 else | |
| 927 fdci->source = g_strdup(fd->path); | |
| 928 | |
| 929 if (dest) | |
| 930 fdci->dest = g_strdup(dest); | |
| 931 | |
| 932 fd->change = fdci; | |
| 933 | |
| 934 return TRUE; | |
| 935 } | |
| 936 | |
| 937 void file_data_free_ci(FileData *fd) | |
| 938 { | |
| 939 FileDataChangeInfo *fdci = fd->change; | |
| 940 | |
| 941 if (!fdci) | |
| 942 return; | |
| 943 | |
| 944 g_free(fdci->source); | |
| 945 g_free(fdci->dest); | |
| 946 | |
| 947 g_free(fdci); | |
| 948 | |
| 949 fd->change = NULL; | |
| 950 } | |
| 951 | |
| 952 | |
| 953 static gboolean file_data_sc_add_ci(FileData *fd, FileDataChangeType type) | |
| 954 { | |
| 955 GList *work; | |
| 956 if (fd->parent) fd = fd->parent; | |
| 957 | |
| 958 if (fd->change) return FALSE; | |
| 959 work = fd->sidecar_files; | |
| 960 while (work) | |
| 961 { | |
| 962 FileData *sfd = work->data; | |
| 963 if (sfd->change) return FALSE; | |
| 964 work = work->next; | |
| 965 } | |
| 966 | |
| 967 file_data_add_ci(fd, type, NULL, NULL); | |
| 968 | |
| 969 work = fd->sidecar_files; | |
| 970 while (work) | |
| 971 { | |
| 972 FileData *sfd = work->data; | |
| 973 file_data_add_ci(sfd, type, NULL, NULL); | |
| 974 work = work->next; | |
| 975 } | |
| 976 | |
| 977 return TRUE; | |
| 978 } | |
| 979 | |
| 980 static gboolean file_data_sc_check_ci(FileData *fd, FileDataChangeType type) | |
| 981 { | |
| 982 GList *work; | |
| 983 if (fd->parent) fd = fd->parent; | |
| 984 | |
| 985 if (!fd->change) return FALSE; | |
| 986 if (fd->change->type != type) return FALSE; | |
| 987 work = fd->sidecar_files; | |
| 988 while (work) | |
| 989 { | |
| 990 FileData *sfd = work->data; | |
| 991 if (!sfd->change) return FALSE; | |
| 992 if (sfd->change->type != type) return FALSE; | |
| 993 work = work->next; | |
| 994 } | |
| 995 return TRUE; | |
| 996 } | |
| 997 | |
| 998 | |
| 751 | 999 gboolean file_data_sc_add_ci_copy(FileData *fd, const gchar *dest_path) |
| 590 | 1000 { |
| 1001 if (!file_data_sc_add_ci(fd, FILEDATA_CHANGE_COPY)) return FALSE; | |
| 1002 file_data_sc_update_ci_copy(fd, dest_path); | |
| 1003 return TRUE; | |
| 1004 } | |
| 1005 | |
| 751 | 1006 gboolean file_data_sc_add_ci_move(FileData *fd, const gchar *dest_path) |
| 590 | 1007 { |
| 1008 if (!file_data_sc_add_ci(fd, FILEDATA_CHANGE_MOVE)) return FALSE; | |
| 1009 file_data_sc_update_ci_move(fd, dest_path); | |
| 1010 return TRUE; | |
| 1011 } | |
| 1012 | |
| 751 | 1013 gboolean file_data_sc_add_ci_rename(FileData *fd, const gchar *dest_path) |
| 590 | 1014 { |
| 1015 if (!file_data_sc_add_ci(fd, FILEDATA_CHANGE_RENAME)) return FALSE; | |
| 1016 file_data_sc_update_ci_rename(fd, dest_path); | |
| 1017 return TRUE; | |
| 1018 } | |
| 1019 | |
| 1020 gboolean file_data_sc_add_ci_delete(FileData *fd) | |
| 1021 { | |
| 1022 return file_data_sc_add_ci(fd, FILEDATA_CHANGE_DELETE); | |
| 1023 } | |
| 1024 | |
| 1025 gboolean file_data_sc_add_ci_update(FileData *fd) | |
| 1026 { | |
| 1027 return file_data_sc_add_ci(fd, FILEDATA_CHANGE_UPDATE); | |
| 1028 } | |
| 1029 | |
| 1030 void file_data_sc_free_ci(FileData *fd) | |
| 1031 { | |
| 1032 GList *work; | |
| 1033 if (fd->parent) fd = fd->parent; | |
| 1034 | |
| 1035 file_data_free_ci(fd); | |
| 1036 | |
| 1037 work = fd->sidecar_files; | |
| 1038 while (work) | |
| 1039 { | |
| 1040 FileData *sfd = work->data; | |
| 1041 file_data_free_ci(sfd); | |
| 1042 work = work->next; | |
| 1043 } | |
| 1044 } | |
| 1045 | |
| 751 | 1046 gboolean file_data_sc_add_ci_delete_list(GList *fd_list) |
| 1047 { | |
| 1048 GList *work; | |
| 1049 gboolean ret = TRUE; | |
| 1050 work = fd_list; | |
| 1051 while (work) | |
| 1052 { | |
| 1053 FileData *fd = work->data; | |
| 1054 if (!file_data_sc_add_ci_delete(fd)) ret = FALSE; | |
| 1055 work = work->next; | |
| 1056 } | |
| 1057 return ret; | |
| 1058 } | |
| 1059 | |
| 1060 gboolean file_data_sc_add_ci_copy_list(GList *fd_list, const gchar *dest) | |
| 1061 { | |
| 1062 GList *work; | |
| 1063 gboolean ret = TRUE; | |
| 1064 work = fd_list; | |
| 1065 while (work) | |
| 1066 { | |
| 1067 FileData *fd = work->data; | |
| 1068 if (!file_data_sc_add_ci_copy(fd, dest)) ret = FALSE; | |
| 1069 work = work->next; | |
| 1070 } | |
| 1071 return ret; | |
| 1072 } | |
| 1073 | |
| 1074 gboolean file_data_sc_add_ci_move_list(GList *fd_list, const gchar *dest) | |
| 1075 { | |
| 1076 GList *work; | |
| 1077 gboolean ret = TRUE; | |
| 1078 work = fd_list; | |
| 1079 while (work) | |
| 1080 { | |
| 1081 FileData *fd = work->data; | |
| 1082 if (!file_data_sc_add_ci_move(fd, dest)) ret = FALSE; | |
| 1083 work = work->next; | |
| 1084 } | |
| 1085 return ret; | |
| 1086 } | |
| 1087 | |
| 1088 gboolean file_data_sc_add_ci_rename_list(GList *fd_list, const gchar *dest) | |
| 1089 { | |
| 1090 GList *work; | |
| 1091 gboolean ret = TRUE; | |
| 1092 work = fd_list; | |
| 1093 while (work) | |
| 1094 { | |
| 1095 FileData *fd = work->data; | |
| 1096 if (!file_data_sc_add_ci_rename(fd, dest)) ret = FALSE; | |
| 1097 work = work->next; | |
| 1098 } | |
| 1099 return ret; | |
| 1100 } | |
| 1101 | |
| 1102 void file_data_sc_free_ci_list(GList *fd_list) | |
| 1103 { | |
| 1104 GList *work; | |
| 1105 work = fd_list; | |
| 1106 while (work) | |
| 1107 { | |
| 1108 FileData *fd = work->data; | |
| 1109 file_data_sc_free_ci(fd); | |
| 1110 work = work->next; | |
| 1111 } | |
| 1112 } | |
| 590 | 1113 |
| 1114 /* | |
| 1115 * update existing fd->change, it will be used from dialog callbacks for interactive editing | |
| 1116 * fails if fd->change does not exist or the change type does not match | |
| 1117 */ | |
| 1118 | |
| 751 | 1119 static void file_data_update_ci_dest(FileData *fd, const gchar *dest_path) |
| 590 | 1120 { |
| 1121 g_free(fd->change->dest); | |
| 1122 fd->change->dest = g_strdup(dest_path); | |
| 1123 } | |
| 1124 | |
| 751 | 1125 static void file_data_update_ci_dest_preserve_ext(FileData *fd, const gchar *dest_path) |
| 590 | 1126 { |
| 1127 const char *extension = extension_from_path(fd->change->source); | |
| 751 | 1128 gchar *base = remove_extension_from_path(dest_path); |
| 590 | 1129 g_free(fd->change->dest); |
| 751 | 1130 fd->change->dest = g_strdup_printf("%s%s", base, extension); |
| 1131 g_free(base); | |
| 590 | 1132 } |
| 1133 | |
| 751 | 1134 static void file_data_sc_update_ci(FileData *fd, const gchar *dest_path) |
| 590 | 1135 { |
| 1136 GList *work; | |
| 751 | 1137 gchar *dest_path_full = NULL; |
| 590 | 1138 if (fd->parent) fd = fd->parent; |
| 1139 | |
| 751 | 1140 if (!dest_path) dest_path = fd->path; |
| 1141 | |
| 1142 if (!strchr(dest_path, G_DIR_SEPARATOR)) /* we got only filename, not a full path */ | |
| 1143 { | |
| 1144 gchar *dir = remove_level_from_path(fd->path); | |
| 1145 dest_path_full = g_build_filename(dir, dest_path, NULL); | |
| 1146 g_free(dir); | |
| 1147 dest_path = dest_path_full; | |
| 1148 } | |
| 1149 | |
| 1150 if (isdir(dest_path)) | |
| 1151 { | |
| 1152 dest_path_full = g_build_filename(dest_path, fd->name, NULL); | |
| 1153 dest_path = dest_path_full; | |
| 1154 } | |
| 1155 | |
| 1156 | |
| 590 | 1157 file_data_update_ci_dest(fd, dest_path); |
| 1158 work = fd->sidecar_files; | |
| 1159 while (work) | |
| 1160 { | |
| 1161 FileData *sfd = work->data; | |
| 1162 file_data_update_ci_dest_preserve_ext(sfd, dest_path); | |
| 1163 work = work->next; | |
| 1164 } | |
| 751 | 1165 g_free(dest_path_full); |
| 590 | 1166 } |
| 1167 | |
| 751 | 1168 gint file_data_sc_update_ci_copy(FileData *fd, const gchar *dest_path) |
| 590 | 1169 { |
| 1170 if (!file_data_sc_check_ci(fd, FILEDATA_CHANGE_COPY)) return FALSE; | |
| 1171 file_data_sc_update_ci(fd, dest_path); | |
| 1172 return TRUE; | |
| 1173 } | |
| 1174 | |
| 751 | 1175 gint file_data_sc_update_ci_move(FileData *fd, const gchar *dest_path) |
| 590 | 1176 { |
| 1177 if (!file_data_sc_check_ci(fd, FILEDATA_CHANGE_MOVE)) return FALSE; | |
| 1178 file_data_sc_update_ci(fd, dest_path); | |
| 1179 return TRUE; | |
| 1180 } | |
| 1181 | |
| 751 | 1182 gint file_data_sc_update_ci_rename(FileData *fd, const gchar *dest_path) |
| 590 | 1183 { |
| 1184 if (!file_data_sc_check_ci(fd, FILEDATA_CHANGE_RENAME)) return FALSE; | |
| 1185 file_data_sc_update_ci(fd, dest_path); | |
| 1186 return TRUE; | |
| 1187 } | |
| 1188 | |
| 1189 | |
| 751 | 1190 gboolean file_data_sc_update_ci_move_list(GList *fd_list, const gchar *dest) |
| 1191 { | |
| 1192 GList *work; | |
| 1193 gboolean ret = TRUE; | |
| 1194 work = fd_list; | |
| 1195 while (work) | |
| 1196 { | |
| 1197 FileData *fd = work->data; | |
| 1198 if (!file_data_sc_update_ci_move(fd, dest)) ret = FALSE; | |
| 1199 work = work->next; | |
| 1200 } | |
| 1201 return ret; | |
| 1202 } | |
| 1203 | |
| 1204 gboolean file_data_sc_update_ci_copy_list(GList *fd_list, const gchar *dest) | |
| 1205 { | |
| 1206 GList *work; | |
| 1207 gboolean ret = TRUE; | |
| 1208 work = fd_list; | |
| 1209 while (work) | |
| 1210 { | |
| 1211 FileData *fd = work->data; | |
| 1212 if (!file_data_sc_update_ci_copy(fd, dest)) ret = FALSE; | |
| 1213 work = work->next; | |
| 1214 } | |
| 1215 return ret; | |
| 1216 } | |
| 1217 | |
| 590 | 1218 |
| 1219 /* | |
| 1220 * check dest paths - dest image exists, etc. | |
| 1221 * returns FIXME | |
| 1222 * it should detect all possible problems with the planned operation | |
| 1223 */ | |
| 1224 | |
| 1225 gint file_data_sc_check_ci_dest(FileData *fd) | |
| 1226 { | |
| 1227 } | |
| 1228 | |
| 1229 | |
| 1230 | |
| 1231 | |
| 1232 /* | |
| 1233 * perform the change described by FileFataChangeInfo | |
| 1234 * it is used for internal operations, | |
| 1235 * this function actually operates with files on the filesystem | |
| 1236 * it should implement safe delete | |
| 1237 */ | |
| 1238 | |
| 1239 static gboolean file_data_perform_move(FileData *fd) | |
| 1240 { | |
| 1241 g_assert(!strcmp(fd->change->source, fd->path)); | |
| 1242 return move_file(fd->change->source, fd->change->dest); | |
| 1243 } | |
| 1244 | |
| 1245 static gboolean file_data_perform_copy(FileData *fd) | |
| 1246 { | |
| 1247 g_assert(!strcmp(fd->change->source, fd->path)); | |
| 1248 return copy_file(fd->change->source, fd->change->dest); | |
| 1249 } | |
| 1250 | |
| 1251 static gboolean file_data_perform_delete(FileData *fd) | |
| 1252 { | |
| 1253 return unlink_file(fd->path); | |
| 1254 } | |
| 1255 | |
| 1256 static gboolean file_data_perform_ci(FileData *fd) | |
| 1257 { | |
| 1258 FileDataChangeType type = fd->change->type; | |
| 1259 switch (type) | |
| 1260 { | |
| 1261 case FILEDATA_CHANGE_MOVE: | |
| 1262 return file_data_perform_move(fd); | |
| 1263 case FILEDATA_CHANGE_COPY: | |
| 1264 return file_data_perform_copy(fd); | |
| 1265 case FILEDATA_CHANGE_RENAME: | |
| 1266 return file_data_perform_move(fd); /* the same as move */ | |
| 1267 case FILEDATA_CHANGE_DELETE: | |
| 1268 return file_data_perform_delete(fd); | |
| 1269 case FILEDATA_CHANGE_UPDATE: | |
| 596 | 1270 /* nothing to do here */ |
| 590 | 1271 break; |
| 1272 } | |
| 1273 return TRUE; | |
| 1274 } | |
| 1275 | |
| 1276 | |
| 1277 | |
| 1278 gboolean file_data_sc_perform_ci(FileData *fd) | |
| 1279 { | |
| 1280 GList *work; | |
| 1281 gboolean ret = TRUE; | |
| 1282 FileDataChangeType type = fd->change->type; | |
| 1283 if (!file_data_sc_check_ci(fd, type)) return FALSE; | |
| 1284 | |
| 1285 work = fd->sidecar_files; | |
| 1286 while (work) | |
| 1287 { | |
| 1288 FileData *sfd = work->data; | |
| 1289 if (!file_data_perform_ci(sfd)) ret = FALSE; | |
| 1290 work = work->next; | |
| 1291 } | |
| 1292 if (!file_data_perform_ci(fd)) ret = FALSE; | |
| 1293 return ret; | |
| 1294 } | |
| 1295 | |
| 1296 /* | |
| 1297 * updates FileData structure according to FileDataChangeInfo | |
| 1298 */ | |
| 1299 | |
| 1300 static void file_data_apply_ci(FileData *fd) | |
| 1301 { | |
| 1302 FileDataChangeType type = fd->change->type; | |
| 1303 /* FIXME delete ?*/ | |
| 1304 if (type == FILEDATA_CHANGE_MOVE || type == FILEDATA_CHANGE_COPY || type == FILEDATA_CHANGE_RENAME) | |
| 1305 { | |
| 1306 g_free(fd->path); | |
| 1307 g_hash_table_remove(file_data_pool, fd->original_path); | |
| 1308 g_free(fd->original_path); | |
| 1309 file_data_set_path(fd, fd->change->dest); | |
| 1310 fd->original_path = g_strdup(fd->change->dest); | |
| 1311 g_hash_table_insert(file_data_pool, fd->original_path, fd); | |
| 1312 } | |
| 1313 } | |
| 1314 | |
| 596 | 1315 gint file_data_sc_apply_ci(FileData *fd) |
| 590 | 1316 { |
| 1317 GList *work; | |
| 1318 FileDataChangeType type = fd->change->type; | |
| 1319 if (!file_data_sc_check_ci(fd, type)) return FALSE; | |
| 1320 | |
| 1321 work = fd->sidecar_files; | |
| 1322 while (work) | |
| 1323 { | |
| 1324 FileData *sfd = work->data; | |
| 1325 file_data_apply_ci(sfd); | |
| 1326 work = work->next; | |
| 1327 } | |
| 1328 file_data_apply_ci(fd); | |
| 1329 return TRUE; | |
| 1330 } | |
| 1331 | |
| 1332 | |
| 1333 /* | |
| 1334 * notify other modules about the change described by FileFataChangeInfo | |
| 1335 */ | |
| 1336 | |
| 1337 /* might use file_maint_ functions for now, later it should be changed to a system of callbacks | |
| 1338 FIXME do we need the ignore_list? It looks like a workaround for ineffective | |
| 1339 implementation in view_file_list.c */ | |
| 1340 | |
| 1341 void file_data_sc_send_notification(FileData *fd) | |
| 1342 { | |
| 1343 } | |
| 1344 | |
| 1345 |
