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