diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/tagcache/tagcache.c | 583 | ||||
-rw-r--r-- | apps/tagcache.c | 83 |
2 files changed, 557 insertions, 109 deletions
diff --git a/apps/plugins/tagcache/tagcache.c b/apps/plugins/tagcache/tagcache.c index 55ca2e2695..cce9efbed9 100644 --- a/apps/plugins/tagcache/tagcache.c +++ b/apps/plugins/tagcache/tagcache.c | |||
@@ -22,16 +22,19 @@ | |||
22 | /*Plugin Includes*/ | 22 | /*Plugin Includes*/ |
23 | 23 | ||
24 | #include "plugin.h" | 24 | #include "plugin.h" |
25 | #include "errno.h" | ||
26 | |||
25 | /* Redefinitons of ANSI C functions. */ | 27 | /* Redefinitons of ANSI C functions. */ |
26 | #include "lib/wrappers.h" | 28 | #include "lib/wrappers.h" |
27 | #include "lib/helper.h" | 29 | #include "lib/helper.h" |
28 | 30 | ||
29 | static void thread_create(void); | 31 | static void thread_create(void); |
30 | static void thread(void); /* the thread running it all */ | 32 | static void thread(void); /* the thread running commit*/ |
31 | static void allocate_tempbuf(void); | 33 | static void allocate_tempbuf(void); |
32 | static void free_tempbuf(void); | 34 | static void free_tempbuf(void); |
33 | static bool do_timed_yield(void); | 35 | static bool do_timed_yield(void); |
34 | static void _log(const char *fmt, ...); | 36 | static void _log(const char *fmt, ...); |
37 | static bool logdump(bool append); | ||
35 | /*Aliases*/ | 38 | /*Aliases*/ |
36 | #if 0 | 39 | #if 0 |
37 | #ifdef ROCKBOX_HAS_LOGF | 40 | #ifdef ROCKBOX_HAS_LOGF |
@@ -41,7 +44,6 @@ static void _log(const char *fmt, ...); | |||
41 | #endif | 44 | #endif |
42 | #endif | 45 | #endif |
43 | 46 | ||
44 | |||
45 | #define logf _log | 47 | #define logf _log |
46 | #define sleep rb->sleep | 48 | #define sleep rb->sleep |
47 | #define qsort rb->qsort | 49 | #define qsort rb->qsort |
@@ -49,6 +51,7 @@ static void _log(const char *fmt, ...); | |||
49 | #define write(x,y,z) rb->write(x,y,z) | 51 | #define write(x,y,z) rb->write(x,y,z) |
50 | #define ftruncate rb->ftruncate | 52 | #define ftruncate rb->ftruncate |
51 | #define remove rb->remove | 53 | #define remove rb->remove |
54 | #define rename rb->rename | ||
52 | 55 | ||
53 | #define vsnprintf rb->vsnprintf | 56 | #define vsnprintf rb->vsnprintf |
54 | #define mkdir rb->mkdir | 57 | #define mkdir rb->mkdir |
@@ -60,20 +63,26 @@ static void _log(const char *fmt, ...); | |||
60 | 63 | ||
61 | #define current_tick (*rb->current_tick) | 64 | #define current_tick (*rb->current_tick) |
62 | #define crc_32(x,y,z) rb->crc_32(x,y,z) | 65 | #define crc_32(x,y,z) rb->crc_32(x,y,z) |
66 | #define plugin_get_buffer rb->plugin_get_buffer | ||
63 | 67 | ||
64 | |||
65 | #if !defined(SIMULATOR) && !defined(APPLICATION) | ||
66 | |||
67 | #define errno (*rb->__errno()) | ||
68 | #endif | ||
69 | #define ENOENT 2 /* No such file or directory */ | ||
70 | #define EEXIST 17 /* File exists */ | ||
71 | #define MAX_LOG_SIZE 16384 | 68 | #define MAX_LOG_SIZE 16384 |
72 | 69 | ||
73 | #define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF) | 70 | #define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF) |
74 | #define EV_ACTION MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02) | ||
75 | #define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01) | 71 | #define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01) |
76 | 72 | ||
73 | #define BACKUP_DIRECTORY PLUGIN_APPS_DATA_DIR "/db_commit" | ||
74 | |||
75 | #define RC_SUCCESS 0 | ||
76 | #define RC_USER_CANCEL 2 | ||
77 | |||
78 | enum fcpy_op_flags | ||
79 | { | ||
80 | FCPY_MOVE = 0x00, /* Is a move operation (default) */ | ||
81 | FCPY_COPY = 0x01, /* Is a copy operation */ | ||
82 | FCPY_OVERWRITE = 0x02, /* Overwrite destination */ | ||
83 | FCPY_EXDEV = 0x04, /* Actually copy/move across volumes */ | ||
84 | }; | ||
85 | |||
77 | /* communication to the worker thread */ | 86 | /* communication to the worker thread */ |
78 | static struct | 87 | static struct |
79 | { | 88 | { |
@@ -85,6 +94,23 @@ static struct | |||
85 | long last_useraction_tick; | 94 | long last_useraction_tick; |
86 | } gThread; | 95 | } gThread; |
87 | 96 | ||
97 | /* status of db and commit */ | ||
98 | static struct | ||
99 | { | ||
100 | long last_check; | ||
101 | bool do_commit; | ||
102 | bool auto_commit; | ||
103 | bool commit_ready; | ||
104 | bool db_exists; | ||
105 | bool have_backup; | ||
106 | bool bu_exists; | ||
107 | } gStatus; | ||
108 | |||
109 | static unsigned char logbuffer[MAX_LOG_SIZE + 1]; | ||
110 | static int log_font_h = -1; | ||
111 | static int logindex; | ||
112 | static bool logwrap; | ||
113 | static bool logenabled = true; | ||
88 | 114 | ||
89 | /*Support Fns*/ | 115 | /*Support Fns*/ |
90 | /* open but with a builtin printf for assembling the path */ | 116 | /* open but with a builtin printf for assembling the path */ |
@@ -103,8 +129,6 @@ int open_pathfmt(char *buf, size_t size, int oflag, const char *pathfmt, ...) | |||
103 | 129 | ||
104 | static void sleep_yield(void) | 130 | static void sleep_yield(void) |
105 | { | 131 | { |
106 | rb->queue_remove_from_head(&gThread.queue, EV_ACTION); | ||
107 | rb->queue_post(&gThread.queue, EV_ACTION, 0); | ||
108 | sleep(1); | 132 | sleep(1); |
109 | #undef yield | 133 | #undef yield |
110 | rb->yield(); | 134 | rb->yield(); |
@@ -159,18 +183,10 @@ bool user_check_tag(int index_type, char* build_idx_buf) | |||
159 | /* paste the whole tagcache.c file */ | 183 | /* paste the whole tagcache.c file */ |
160 | #include "../tagcache.c" | 184 | #include "../tagcache.c" |
161 | 185 | ||
162 | static bool logdump(bool append); | ||
163 | static unsigned char logbuffer[MAX_LOG_SIZE + 1]; | ||
164 | static int log_font_h = -1; | ||
165 | static int logindex; | ||
166 | static bool logwrap; | ||
167 | static bool logenabled = true; | ||
168 | |||
169 | static void check_logindex(void) | 186 | static void check_logindex(void) |
170 | { | 187 | { |
171 | if(logindex >= MAX_LOG_SIZE) | 188 | if(logindex >= MAX_LOG_SIZE) |
172 | { | 189 | { |
173 | /* wrap */ | ||
174 | logdump(true); | 190 | logdump(true); |
175 | //logwrap = true; | 191 | //logwrap = true; |
176 | logindex = 0; | 192 | logindex = 0; |
@@ -196,7 +212,6 @@ static void _log(const char *fmt, ...) | |||
196 | return; | 212 | return; |
197 | } | 213 | } |
198 | 214 | ||
199 | |||
200 | #ifdef USB_ENABLE_SERIAL | 215 | #ifdef USB_ENABLE_SERIAL |
201 | int old_logindex = logindex; | 216 | int old_logindex = logindex; |
202 | #endif | 217 | #endif |
@@ -291,13 +306,11 @@ static bool logdisplay(void) | |||
291 | /* if negative, will be set 0 to zero later */ | 306 | /* if negative, will be set 0 to zero later */ |
292 | } | 307 | } |
293 | 308 | ||
294 | |||
295 | rb->lcd_clear_display(); | 309 | rb->lcd_clear_display(); |
296 | 310 | ||
297 | if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE) | 311 | if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE) |
298 | gThread.user_index = 0; | 312 | gThread.user_index = 0; |
299 | 313 | ||
300 | |||
301 | if(logwrap) | 314 | if(logwrap) |
302 | i = logindex; | 315 | i = logindex; |
303 | else | 316 | else |
@@ -373,7 +386,7 @@ static bool logdump(bool append) | |||
373 | /* nothing is logged just yet */ | 386 | /* nothing is logged just yet */ |
374 | return false; | 387 | return false; |
375 | } | 388 | } |
376 | if (!append) | 389 | if (append) |
377 | { | 390 | { |
378 | flags = O_CREAT|O_WRONLY|O_APPEND; | 391 | flags = O_CREAT|O_WRONLY|O_APPEND; |
379 | } | 392 | } |
@@ -431,7 +444,6 @@ static bool do_timed_yield(void) | |||
431 | static long wakeup_tick = 0; | 444 | static long wakeup_tick = 0; |
432 | if (TIME_AFTER(current_tick, wakeup_tick)) | 445 | if (TIME_AFTER(current_tick, wakeup_tick)) |
433 | { | 446 | { |
434 | |||
435 | yield(); | 447 | yield(); |
436 | 448 | ||
437 | wakeup_tick = current_tick + (HZ/5); | 449 | wakeup_tick = current_tick + (HZ/5); |
@@ -440,6 +452,402 @@ static bool do_timed_yield(void) | |||
440 | return false; | 452 | return false; |
441 | } | 453 | } |
442 | 454 | ||
455 | /* copy/move a file */ | ||
456 | static int fcpy(const char *src, const char *target, | ||
457 | unsigned int flags, bool (*poll_cancel)(const char *)) | ||
458 | { | ||
459 | int rc = -1; | ||
460 | |||
461 | while (!(flags & (FCPY_COPY | FCPY_EXDEV))) { | ||
462 | if ((flags & FCPY_OVERWRITE) || !file_exists(target)) { | ||
463 | /* Rename and possibly overwrite the file */ | ||
464 | if (poll_cancel && poll_cancel(src)) { | ||
465 | rc = RC_USER_CANCEL; | ||
466 | } else { | ||
467 | rc = rename(src, target); | ||
468 | } | ||
469 | |||
470 | #ifdef HAVE_MULTIVOLUME | ||
471 | if (rc < 0 && errno == EXDEV) { | ||
472 | /* Failed because cross volume rename doesn't work; force | ||
473 | a move instead */ | ||
474 | flags |= FCPY_EXDEV; | ||
475 | break; | ||
476 | } | ||
477 | #endif /* HAVE_MULTIVOLUME */ | ||
478 | } | ||
479 | |||
480 | return rc; | ||
481 | } | ||
482 | |||
483 | /* See if we can get the plugin buffer for the file copy buffer */ | ||
484 | size_t buffersize; | ||
485 | char *buffer = (char *) plugin_get_buffer(&buffersize); | ||
486 | if (buffer == NULL || buffersize < 512) { | ||
487 | /* Not large enough, try for a disk sector worth of stack | ||
488 | instead */ | ||
489 | buffersize = 512; | ||
490 | buffer = (char *)alloca(buffersize); | ||
491 | } | ||
492 | |||
493 | if (buffer == NULL) { | ||
494 | return -1; | ||
495 | } | ||
496 | |||
497 | buffersize &= ~0x1ff; /* Round buffer size to multiple of sector | ||
498 | size */ | ||
499 | |||
500 | int src_fd = open(src, O_RDONLY); | ||
501 | if (src_fd >= 0) { | ||
502 | int oflag = O_WRONLY|O_CREAT; | ||
503 | |||
504 | if (!(flags & FCPY_OVERWRITE)) { | ||
505 | oflag |= O_EXCL; | ||
506 | } | ||
507 | |||
508 | int target_fd = open(target, oflag, 0666); | ||
509 | if (target_fd >= 0) { | ||
510 | off_t total_size = 0; | ||
511 | off_t next_cancel_test = 0; /* No excessive button polling */ | ||
512 | |||
513 | rc = RC_SUCCESS; | ||
514 | |||
515 | while (rc == RC_SUCCESS) { | ||
516 | if (total_size >= next_cancel_test) { | ||
517 | next_cancel_test = total_size + 0x10000; | ||
518 | if (poll_cancel && poll_cancel(src)) { | ||
519 | rc = RC_USER_CANCEL; | ||
520 | break; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | ssize_t bytesread = read(src_fd, buffer, buffersize); | ||
525 | if (bytesread <= 0) { | ||
526 | if (bytesread < 0) { | ||
527 | rc = -1; | ||
528 | } | ||
529 | /* else eof on buffer boundary; nothing to write */ | ||
530 | break; | ||
531 | } | ||
532 | |||
533 | ssize_t byteswritten = write(target_fd, buffer, bytesread); | ||
534 | if (byteswritten < bytesread) { | ||
535 | /* Some I/O error */ | ||
536 | rc = -1; | ||
537 | break; | ||
538 | } | ||
539 | |||
540 | total_size += byteswritten; | ||
541 | |||
542 | if (bytesread < (ssize_t)buffersize) { | ||
543 | /* EOF with trailing bytes */ | ||
544 | break; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | if (rc == RC_SUCCESS) { | ||
549 | /* If overwriting, set the correct length if original was | ||
550 | longer */ | ||
551 | rc = ftruncate(target_fd, total_size); | ||
552 | } | ||
553 | |||
554 | close(target_fd); | ||
555 | |||
556 | if (rc != RC_SUCCESS) { | ||
557 | /* Copy failed. Cleanup. */ | ||
558 | remove(target); | ||
559 | } | ||
560 | } | ||
561 | |||
562 | close(src_fd); | ||
563 | } | ||
564 | |||
565 | if (rc == RC_SUCCESS && !(flags & FCPY_COPY)) { | ||
566 | /* Remove the source file */ | ||
567 | rc = remove(src); | ||
568 | } | ||
569 | |||
570 | return rc; | ||
571 | } | ||
572 | |||
573 | static bool backup_restore_tagcache(bool backup) | ||
574 | { | ||
575 | struct master_header tcmh; | ||
576 | char path[MAX_PATH]; | ||
577 | char bu_path[MAX_PATH]; | ||
578 | int fd; | ||
579 | int rc; | ||
580 | |||
581 | if (backup) | ||
582 | { | ||
583 | if (!rb->dir_exists(BACKUP_DIRECTORY)) | ||
584 | mkdir(BACKUP_DIRECTORY); | ||
585 | snprintf(path, sizeof(path), "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path); | ||
586 | snprintf(bu_path, sizeof(bu_path), "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY); | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | if (!rb->dir_exists(BACKUP_DIRECTORY)) | ||
591 | return false; | ||
592 | snprintf(path, sizeof(path), "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY); | ||
593 | snprintf(bu_path, sizeof(bu_path), "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path); | ||
594 | } | ||
595 | |||
596 | fd = open(path, O_RDONLY, 0666); | ||
597 | |||
598 | if (fd >= 0) | ||
599 | { | ||
600 | rc = read(fd, &tcmh, sizeof(struct master_header)); | ||
601 | close(fd); | ||
602 | if (rc != sizeof(struct master_header)) | ||
603 | { | ||
604 | logf("master file read failed"); | ||
605 | return false; | ||
606 | } | ||
607 | int entries = tcmh.tch.entry_count; | ||
608 | |||
609 | logf("master file %d entries", entries); | ||
610 | if (backup) | ||
611 | logf("backup db to %s", BACKUP_DIRECTORY); | ||
612 | else | ||
613 | logf("restore db to %s", tc_stat.db_path); | ||
614 | |||
615 | if (entries > 0) | ||
616 | { | ||
617 | logf("%s", path); | ||
618 | fcpy(path, bu_path, FCPY_COPY|FCPY_OVERWRITE, NULL); | ||
619 | |||
620 | for (int i = 0; i < TAG_COUNT; i++) | ||
621 | { | ||
622 | if (TAGCACHE_IS_NUMERIC(i)) | ||
623 | continue; | ||
624 | snprintf(path, sizeof(path), | ||
625 | "%s/"TAGCACHE_FILE_INDEX, tc_stat.db_path, i); | ||
626 | |||
627 | snprintf(bu_path, sizeof(bu_path), | ||
628 | "%s/"TAGCACHE_FILE_INDEX, BACKUP_DIRECTORY, i); | ||
629 | /* Note: above we swapped paths in the snprintf call here we swap variables */ | ||
630 | if (backup) | ||
631 | { | ||
632 | logf("%s", path); | ||
633 | if (fcpy(path, bu_path, FCPY_COPY|FCPY_OVERWRITE, NULL) < 0) | ||
634 | goto failed; | ||
635 | gStatus.have_backup = true; | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | logf("%s", bu_path); | ||
640 | if (fcpy(bu_path, path, FCPY_COPY|FCPY_OVERWRITE, NULL) < 0) | ||
641 | goto failed; | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | return true; | ||
646 | } | ||
647 | failed: | ||
648 | if (backup) | ||
649 | { | ||
650 | logf("failed backup"); | ||
651 | } | ||
652 | |||
653 | return false; | ||
654 | } | ||
655 | |||
656 | /* asks the user if they wish to quit */ | ||
657 | static bool confirm_quit(void) | ||
658 | { | ||
659 | const struct text_message prompt = | ||
660 | { (const char*[]) {"Are you sure?", "This will abort commit."}, 2}; | ||
661 | enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL); | ||
662 | return (response == YESNO_YES); | ||
663 | } | ||
664 | |||
665 | /* asks the user if they wish to backup/restore */ | ||
666 | static bool prompt_backup_restore(bool backup) | ||
667 | { | ||
668 | const struct text_message bu_prompt = { (const char*[]) {"Backup database?"}, 1}; | ||
669 | const struct text_message re_prompt = | ||
670 | { (const char*[]) {"Error committing,", "Restore database?"}, 2}; | ||
671 | enum yesno_res response = | ||
672 | rb->gui_syncyesno_run(backup ? &bu_prompt:&re_prompt, NULL, NULL); | ||
673 | if(response == YESNO_YES) | ||
674 | return backup_restore_tagcache(backup); | ||
675 | return true; | ||
676 | } | ||
677 | |||
678 | static const char* list_get_name_cb(int selected_item, void* data, | ||
679 | char* buf, size_t buf_len) | ||
680 | { | ||
681 | (void) data; | ||
682 | (void) buf; | ||
683 | (void) buf_len; | ||
684 | |||
685 | /* buf supplied isn't used so lets use it for a filename buffer */ | ||
686 | if (TIME_AFTER(current_tick, gStatus.last_check)) | ||
687 | { | ||
688 | snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_NOCOMMIT, tc_stat.db_path); | ||
689 | gStatus.auto_commit = !file_exists(buf); | ||
690 | snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_TEMP, tc_stat.db_path); | ||
691 | gStatus.commit_ready = file_exists(buf); | ||
692 | snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path); | ||
693 | gStatus.db_exists = file_exists(buf); | ||
694 | snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY); | ||
695 | gStatus.bu_exists = file_exists(buf); | ||
696 | gStatus.last_check = current_tick + HZ; | ||
697 | buf[0] = '\0'; | ||
698 | } | ||
699 | |||
700 | switch(selected_item) | ||
701 | { | ||
702 | |||
703 | case 0: /* exit */ | ||
704 | return ID2P(LANG_MENU_QUIT); | ||
705 | case 1: /*sep*/ | ||
706 | return ID2P(VOICE_BLANK); | ||
707 | case 2: /*backup*/ | ||
708 | if (!gStatus.db_exists) | ||
709 | return ID2P(VOICE_BLANK); | ||
710 | return "Backup"; | ||
711 | case 3: /*restore*/ | ||
712 | if (!gStatus.bu_exists) | ||
713 | return ID2P(VOICE_BLANK); | ||
714 | return "Restore"; | ||
715 | case 4: /*sep*/ | ||
716 | return ID2P(VOICE_BLANK); | ||
717 | case 5: /*auto commit*/ | ||
718 | if (gStatus.auto_commit) | ||
719 | return "Disable auto commit"; | ||
720 | else | ||
721 | return "Enable auto commit"; | ||
722 | case 6: /*destroy*/ | ||
723 | if (gStatus.db_exists) | ||
724 | return "Delete database"; | ||
725 | /*fall through*/ | ||
726 | case 7: /*sep*/ | ||
727 | return ID2P(VOICE_BLANK); | ||
728 | case 8: /*commit*/ | ||
729 | if (gStatus.commit_ready) | ||
730 | return "Commit"; | ||
731 | else | ||
732 | return "Nothing to commit"; | ||
733 | default: | ||
734 | return "?"; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | static int list_voice_cb(int list_index, void* data) | ||
739 | { | ||
740 | #define MAX_MENU_NAME 32 | ||
741 | if (!rb->global_settings->talk_menu) | ||
742 | return -1; | ||
743 | else | ||
744 | { | ||
745 | char buf[MAX_MENU_NAME]; | ||
746 | const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf)); | ||
747 | long id = P2ID((const unsigned char *)name); | ||
748 | if(id>=0) | ||
749 | rb->talk_id(id, true); | ||
750 | else | ||
751 | rb->talk_spell(name, true); | ||
752 | } | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static int commit_menu(void) | ||
757 | { | ||
758 | struct gui_synclist lists; | ||
759 | bool exit = false; | ||
760 | int button,i; | ||
761 | int selection, ret = 0; | ||
762 | |||
763 | rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL); | ||
764 | rb->gui_synclist_set_icon_callback(&lists, NULL); | ||
765 | rb->gui_synclist_set_nb_items(&lists, 9); | ||
766 | rb->gui_synclist_select_item(&lists, 0); | ||
767 | |||
768 | while (!exit) | ||
769 | { | ||
770 | rb->gui_synclist_draw(&lists); | ||
771 | button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); | ||
772 | if (rb->gui_synclist_do_button(&lists, &button)) | ||
773 | continue; | ||
774 | selection = rb->gui_synclist_get_sel_pos(&lists); | ||
775 | |||
776 | if (button == ACTION_STD_CANCEL) | ||
777 | return 0; | ||
778 | else if (button == ACTION_STD_OK) | ||
779 | { | ||
780 | switch(selection) | ||
781 | { | ||
782 | case 0: /* exit */ | ||
783 | exit = true; | ||
784 | break; | ||
785 | case 1: /*sep*/ | ||
786 | continue; | ||
787 | case 2: /*backup*/ | ||
788 | if (!gStatus.db_exists) | ||
789 | break; | ||
790 | if (!backup_restore_tagcache(true)) | ||
791 | rb->splash(HZ, "Backup failed!"); | ||
792 | else | ||
793 | { | ||
794 | rb->splash(HZ, "Backup success!"); | ||
795 | gStatus.bu_exists = true; | ||
796 | } | ||
797 | break; | ||
798 | case 3: /*restore*/ | ||
799 | if (!gStatus.bu_exists) | ||
800 | break; | ||
801 | if (!backup_restore_tagcache(false)) | ||
802 | rb->splash(HZ, "Restore failed!"); | ||
803 | else | ||
804 | rb->splash(HZ, "Restore success!"); | ||
805 | break; | ||
806 | case 4: /*sep*/ | ||
807 | continue; | ||
808 | case 5: /*auto commit*/ | ||
809 | { | ||
810 | /* build_idx_buf supplied by tagcache.c isn't being used | ||
811 | * so lets use it for a filename buffer */ | ||
812 | snprintf(build_idx_buf, build_idx_bufsz, | ||
813 | "%s/" TAGCACHE_FILE_NOCOMMIT, tc_stat.db_path); | ||
814 | if(gStatus.auto_commit) | ||
815 | close(open(build_idx_buf, O_WRONLY | O_CREAT | O_TRUNC, 0666)); | ||
816 | else | ||
817 | remove(build_idx_buf); | ||
818 | gStatus.auto_commit = !file_exists(build_idx_buf); | ||
819 | break; | ||
820 | } | ||
821 | case 6: /*destroy*/ | ||
822 | { | ||
823 | if (!gStatus.db_exists) | ||
824 | break; | ||
825 | const struct text_message prompt = | ||
826 | { (const char*[]) {"Are you sure?", "This will destroy database."}, 2}; | ||
827 | if (rb->gui_syncyesno_run(&prompt, NULL, NULL) == YESNO_YES) | ||
828 | remove_files(); | ||
829 | break; | ||
830 | } | ||
831 | case 7: /*sep*/ | ||
832 | continue; | ||
833 | case 8: /*commit*/ | ||
834 | if (gStatus.commit_ready) | ||
835 | { | ||
836 | gStatus.do_commit = true; | ||
837 | exit = true; | ||
838 | } | ||
839 | break; | ||
840 | |||
841 | case MENU_ATTACHED_USB: | ||
842 | return PLUGIN_USB_CONNECTED; | ||
843 | default: | ||
844 | return 0; | ||
845 | } | ||
846 | } | ||
847 | } /*while*/ | ||
848 | return ret; | ||
849 | } | ||
850 | |||
443 | /*-----------------------------------------------------------------------------*/ | 851 | /*-----------------------------------------------------------------------------*/ |
444 | /******* plugin_start ******* */ | 852 | /******* plugin_start ******* */ |
445 | /*-----------------------------------------------------------------------------*/ | 853 | /*-----------------------------------------------------------------------------*/ |
@@ -451,6 +859,8 @@ enum plugin_status plugin_start(const void* parameter) | |||
451 | /* Turn off backlight timeout */ | 859 | /* Turn off backlight timeout */ |
452 | backlight_ignore_timeout(); | 860 | backlight_ignore_timeout(); |
453 | 861 | ||
862 | memset(&gThread, 0, sizeof(gThread)); | ||
863 | memset(&gStatus, 0, sizeof(gStatus)); | ||
454 | memset(&tc_stat, 0, sizeof(struct tagcache_stat)); | 864 | memset(&tc_stat, 0, sizeof(struct tagcache_stat)); |
455 | memset(¤t_tcmh, 0, sizeof(struct master_header)); | 865 | memset(¤t_tcmh, 0, sizeof(struct master_header)); |
456 | filenametag_fd = -1; | 866 | filenametag_fd = -1; |
@@ -459,62 +869,32 @@ enum plugin_status plugin_start(const void* parameter) | |||
459 | if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */ | 869 | if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */ |
460 | strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path)); | 870 | strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path)); |
461 | tc_stat.initialized = true; | 871 | tc_stat.initialized = true; |
872 | tc_stat.commit_step = -1; | ||
462 | 873 | ||
463 | memset(&gThread, 0, sizeof(gThread)); | ||
464 | logf("started"); | 874 | logf("started"); |
465 | logdump(false); | ||
466 | 875 | ||
876 | int result = commit_menu(); | ||
877 | |||
878 | if (!gStatus.do_commit) | ||
879 | { | ||
880 | /* Turn on backlight timeout (revert to settings) */ | ||
881 | backlight_use_settings(); | ||
882 | return PLUGIN_OK; | ||
883 | } | ||
884 | |||
885 | logdump(false); | ||
886 | allocate_tempbuf(); | ||
887 | if (gStatus.db_exists && !gStatus.have_backup && !prompt_backup_restore(true)) | ||
888 | rb->splash(HZ, "Backup failed!"); | ||
467 | thread_create(); | 889 | thread_create(); |
468 | gThread.user_index = 0; | 890 | gThread.user_index = 0; |
469 | logdisplay(); /* get something on the screen while user waits */ | 891 | logdisplay(); /* get something on the screen while user waits */ |
470 | 892 | ||
471 | allocate_tempbuf(); | ||
472 | |||
473 | commit(); | ||
474 | |||
475 | if (tc_stat.ready) | ||
476 | rb->tagcache_commit_finalize(); | ||
477 | |||
478 | free_tempbuf(); | ||
479 | |||
480 | logdump(true); | ||
481 | gThread.user_index++; | ||
482 | logdisplay(); | ||
483 | rb->thread_wait(gThread.id); | ||
484 | rb->queue_delete(&gThread.queue); | ||
485 | |||
486 | /* Turn on backlight timeout (revert to settings) */ | ||
487 | backlight_use_settings(); | ||
488 | return PLUGIN_OK; | ||
489 | } | ||
490 | |||
491 | /****************** main thread + helper ******************/ | ||
492 | static void thread(void) | ||
493 | { | ||
494 | struct queue_event ev; | ||
495 | while (!gThread.exiting) | 893 | while (!gThread.exiting) |
496 | { | 894 | { |
497 | rb->queue_wait_w_tmo(&gThread.queue, &ev, 1); | ||
498 | switch (ev.id) | ||
499 | { | ||
500 | case SYS_USB_CONNECTED: | ||
501 | rb->usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
502 | logenabled = false; | ||
503 | break; | ||
504 | case SYS_USB_DISCONNECTED: | ||
505 | logenabled = true; | ||
506 | /*fall through*/ | ||
507 | case EV_STARTUP: | ||
508 | logf("Thread Started"); | ||
509 | break; | ||
510 | case EV_EXIT: | ||
511 | return; | ||
512 | default: | ||
513 | break; | ||
514 | } | ||
515 | logdisplay(); | 895 | logdisplay(); |
516 | 896 | ||
517 | int action = rb->get_action(CONTEXT_STD, HZ/10); | 897 | int action = rb->get_action(CONTEXT_STD, HZ/20); |
518 | 898 | ||
519 | switch( action ) | 899 | switch( action ) |
520 | { | 900 | { |
@@ -536,8 +916,15 @@ static void thread(void) | |||
536 | break; | 916 | break; |
537 | case SYS_POWEROFF: | 917 | case SYS_POWEROFF: |
538 | case ACTION_STD_CANCEL: | 918 | case ACTION_STD_CANCEL: |
539 | gThread.exiting = true; | 919 | if (tc_stat.commit_step >= 0 && !tc_stat.ready) |
540 | return; | 920 | { |
921 | if (!confirm_quit()) | ||
922 | break; | ||
923 | tc_stat.commit_delayed = true; /* Cancel the commit */ | ||
924 | } | ||
925 | rb->queue_remove_from_head(&gThread.queue, EV_EXIT); | ||
926 | rb->queue_post(&gThread.queue, EV_EXIT, 0); | ||
927 | break; | ||
541 | #ifdef HAVE_TOUCHSCREEN | 928 | #ifdef HAVE_TOUCHSCREEN |
542 | case ACTION_TOUCHSCREEN: | 929 | case ACTION_TOUCHSCREEN: |
543 | { | 930 | { |
@@ -561,8 +948,60 @@ static void thread(void) | |||
561 | default: | 948 | default: |
562 | break; | 949 | break; |
563 | } | 950 | } |
951 | yield(); | ||
952 | } | ||
953 | |||
954 | rb->thread_wait(gThread.id); | ||
955 | rb->queue_delete(&gThread.queue); | ||
956 | free_tempbuf(); | ||
957 | |||
958 | if (tc_stat.commit_delayed || !tc_stat.ready) | ||
959 | { | ||
960 | remove_files(); | ||
961 | if (gStatus.bu_exists && !prompt_backup_restore(false)) | ||
962 | rb->splash(HZ, "Restore failed!"); | ||
963 | } | ||
964 | |||
965 | if (tc_stat.ready) | ||
966 | rb->tagcache_commit_finalize(); | ||
564 | 967 | ||
968 | /* Turn on backlight timeout (revert to settings) */ | ||
969 | backlight_use_settings(); | ||
970 | return PLUGIN_OK; | ||
971 | } | ||
565 | 972 | ||
973 | /****************** main thread + helper ******************/ | ||
974 | static void thread(void) | ||
975 | { | ||
976 | struct queue_event ev; | ||
977 | while (!gThread.exiting) | ||
978 | { | ||
979 | rb->queue_wait_w_tmo(&gThread.queue, &ev, 1); | ||
980 | switch (ev.id) | ||
981 | { | ||
982 | case SYS_USB_CONNECTED: | ||
983 | rb->usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
984 | logenabled = false; | ||
985 | break; | ||
986 | case SYS_USB_DISCONNECTED: | ||
987 | logenabled = true; | ||
988 | /*fall through*/ | ||
989 | case EV_STARTUP: | ||
990 | logf("Thread Started"); | ||
991 | cpu_boost(true); | ||
992 | if (commit()) | ||
993 | tc_stat.ready = true; | ||
994 | cpu_boost(false); | ||
995 | logdump(true); | ||
996 | gThread.user_index++; | ||
997 | logdisplay(); | ||
998 | break; | ||
999 | case EV_EXIT: | ||
1000 | gThread.exiting = true; | ||
1001 | return; | ||
1002 | default: | ||
1003 | break; | ||
1004 | } | ||
566 | yield(); | 1005 | yield(); |
567 | } | 1006 | } |
568 | } | 1007 | } |
diff --git a/apps/tagcache.c b/apps/tagcache.c index b12d1de7f6..40f9c28c33 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c | |||
@@ -92,6 +92,9 @@ | |||
92 | #include "lang.h" | 92 | #include "lang.h" |
93 | #include "eeprom_settings.h" | 93 | #include "eeprom_settings.h" |
94 | #endif | 94 | #endif |
95 | #define USR_CANCEL false | ||
96 | #else/*!defined(PLUGIN)*/ | ||
97 | #define USR_CANCEL (tc_stat.commit_delayed == true) | ||
95 | #endif /*!defined(PLUGIN)*/ | 98 | #endif /*!defined(PLUGIN)*/ |
96 | /* | 99 | /* |
97 | * Define this to support non-native endian tagcache files. | 100 | * Define this to support non-native endian tagcache files. |
@@ -2370,7 +2373,7 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique) | |||
2370 | unsigned *crcbuf = (unsigned *)&tempbuf[tempbuf_size-4]; | 2373 | unsigned *crcbuf = (unsigned *)&tempbuf[tempbuf_size-4]; |
2371 | unsigned crc32 = 0xffffffff; | 2374 | unsigned crc32 = 0xffffffff; |
2372 | char chr_lower; | 2375 | char chr_lower; |
2373 | for (i = 0; str[i] != '\0' && i < len; i++) | 2376 | for (i = 0; str[i] != '\0' && i < len -1; i++) |
2374 | { | 2377 | { |
2375 | chr_lower = tolower(str[i]); | 2378 | chr_lower = tolower(str[i]); |
2376 | crc32 = crc_32(&chr_lower, 1, crc32); | 2379 | crc32 = crc_32(&chr_lower, 1, crc32); |
@@ -2404,9 +2407,12 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique) | |||
2404 | 2407 | ||
2405 | /* Insert it to the buffer. */ | 2408 | /* Insert it to the buffer. */ |
2406 | tempbuf_left -= len; | 2409 | tempbuf_left -= len; |
2407 | if (tempbuf_left - 4 < 0 || tempbufidx >= commit_entry_count-1) | 2410 | if (tempbuf_left - 4 < 0 || tempbufidx >= commit_entry_count) |
2411 | { | ||
2412 | logf("temp buf error rem: %ld idx: %d / %d", | ||
2413 | tempbuf_left, tempbufidx, commit_entry_count-1); | ||
2408 | return false; | 2414 | return false; |
2409 | 2415 | } | |
2410 | if (id >= lookup_buffer_depth) | 2416 | if (id >= lookup_buffer_depth) |
2411 | { | 2417 | { |
2412 | logf("lookup buf overf. #2: %d", id); | 2418 | logf("lookup buf overf. #2: %d", id); |
@@ -2585,7 +2591,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) | |||
2585 | return false; | 2591 | return false; |
2586 | } | 2592 | } |
2587 | 2593 | ||
2588 | while (entries_processed < h->entry_count) | 2594 | while (entries_processed < h->entry_count && !USR_CANCEL) |
2589 | { | 2595 | { |
2590 | int count = MIN(h->entry_count - entries_processed, max_entries); | 2596 | int count = MIN(h->entry_count - entries_processed, max_entries); |
2591 | 2597 | ||
@@ -2651,7 +2657,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) | |||
2651 | lseek(masterfd, sizeof(struct master_header), SEEK_SET); | 2657 | lseek(masterfd, sizeof(struct master_header), SEEK_SET); |
2652 | 2658 | ||
2653 | /* Check if we can resurrect some deleted runtime statistics data. */ | 2659 | /* Check if we can resurrect some deleted runtime statistics data. */ |
2654 | for (i = 0; i < tcmh.tch.entry_count; i++) | 2660 | for (i = 0; i < tcmh.tch.entry_count && !USR_CANCEL; i++) |
2655 | { | 2661 | { |
2656 | /* Read the index entry. */ | 2662 | /* Read the index entry. */ |
2657 | if (read_index_entries(masterfd, &idx, 1) != sizeof(struct index_entry)) | 2663 | if (read_index_entries(masterfd, &idx, 1) != sizeof(struct index_entry)) |
@@ -2742,7 +2748,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd) | |||
2742 | lseek(masterfd, masterfd_pos, SEEK_SET); | 2748 | lseek(masterfd, masterfd_pos, SEEK_SET); |
2743 | 2749 | ||
2744 | /* Commit the data to the index. */ | 2750 | /* Commit the data to the index. */ |
2745 | for (i = 0; i < count; i++) | 2751 | for (i = 0; i < count && !USR_CANCEL; i++) |
2746 | { | 2752 | { |
2747 | int loc = lseek(masterfd, 0, SEEK_CUR); | 2753 | int loc = lseek(masterfd, 0, SEEK_CUR); |
2748 | 2754 | ||
@@ -2895,7 +2901,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) | |||
2895 | if (TAGCACHE_IS_SORTED(index_type)) | 2901 | if (TAGCACHE_IS_SORTED(index_type)) |
2896 | { | 2902 | { |
2897 | logf("loading tags..."); | 2903 | logf("loading tags..."); |
2898 | for (i = 0; i < tch.entry_count; i++) | 2904 | for (i = 0; i < tch.entry_count && !USR_CANCEL; i++) |
2899 | { | 2905 | { |
2900 | struct tagfile_entry entry; | 2906 | struct tagfile_entry entry; |
2901 | int loc = lseek(fd, 0, SEEK_CUR); | 2907 | int loc = lseek(fd, 0, SEEK_CUR); |
@@ -3040,7 +3046,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) | |||
3040 | lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET); | 3046 | lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET); |
3041 | /* h is the header of the temporary file containing new tags. */ | 3047 | /* h is the header of the temporary file containing new tags. */ |
3042 | logf("inserting new tags..."); | 3048 | logf("inserting new tags..."); |
3043 | for (i = 0; i < h->entry_count; i++) | 3049 | for (i = 0; i < h->entry_count && !USR_CANCEL; i++) |
3044 | { | 3050 | { |
3045 | struct temp_file_entry entry; | 3051 | struct temp_file_entry entry; |
3046 | 3052 | ||
@@ -3112,7 +3118,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) | |||
3112 | */ | 3118 | */ |
3113 | logf("updating indices..."); | 3119 | logf("updating indices..."); |
3114 | lseek(masterfd, sizeof(struct master_header), SEEK_SET); | 3120 | lseek(masterfd, sizeof(struct master_header), SEEK_SET); |
3115 | for (i = 0; i < tcmh.tch.entry_count; i += idxbuf_pos) | 3121 | for (i = 0; i < tcmh.tch.entry_count && !USR_CANCEL; i += idxbuf_pos) |
3116 | { | 3122 | { |
3117 | int j; | 3123 | int j; |
3118 | int loc = lseek(masterfd, 0, SEEK_CUR); | 3124 | int loc = lseek(masterfd, 0, SEEK_CUR); |
@@ -3172,7 +3178,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) | |||
3172 | lseek(masterfd, masterfd_pos, SEEK_SET); | 3178 | lseek(masterfd, masterfd_pos, SEEK_SET); |
3173 | lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET); | 3179 | lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET); |
3174 | lseek(fd, 0, SEEK_END); | 3180 | lseek(fd, 0, SEEK_END); |
3175 | for (i = 0; i < h->entry_count; i += idxbuf_pos) | 3181 | for (i = 0; i < h->entry_count && !USR_CANCEL; i += idxbuf_pos) |
3176 | { | 3182 | { |
3177 | int j; | 3183 | int j; |
3178 | 3184 | ||
@@ -3412,7 +3418,7 @@ static bool commit(void) | |||
3412 | tch.datasize = 0; | 3418 | tch.datasize = 0; |
3413 | tc_stat.commit_delayed = false; | 3419 | tc_stat.commit_delayed = false; |
3414 | 3420 | ||
3415 | for (i = 0; i < TAG_COUNT; i++) | 3421 | for (i = 0; i < TAG_COUNT && !USR_CANCEL; i++) |
3416 | { | 3422 | { |
3417 | int ret; | 3423 | int ret; |
3418 | 3424 | ||
@@ -3446,41 +3452,44 @@ static bool commit(void) | |||
3446 | 3452 | ||
3447 | tc_stat.commit_step = 0; | 3453 | tc_stat.commit_step = 0; |
3448 | 3454 | ||
3449 | /* Update the master index headers. */ | 3455 | if (!USR_CANCEL) |
3450 | if ( (masterfd = open_master_fd(&tcmh, true)) < 0) | 3456 | { |
3451 | goto commit_error; | 3457 | /* Update the master index headers. */ |
3458 | if ( (masterfd = open_master_fd(&tcmh, true)) < 0) | ||
3459 | goto commit_error; | ||
3452 | 3460 | ||
3453 | remove_db_file(TAGCACHE_FILE_TEMP); | 3461 | remove_db_file(TAGCACHE_FILE_TEMP); |
3454 | 3462 | ||
3455 | tcmh.tch.entry_count += tch.entry_count; | 3463 | tcmh.tch.entry_count += tch.entry_count; |
3456 | tcmh.tch.datasize = sizeof(struct master_header) | 3464 | tcmh.tch.datasize = sizeof(struct master_header) |
3457 | + sizeof(struct index_entry) * tcmh.tch.entry_count | 3465 | + sizeof(struct index_entry) * tcmh.tch.entry_count |
3458 | + tch.datasize; | 3466 | + tch.datasize; |
3459 | tcmh.dirty = false; | 3467 | tcmh.dirty = false; |
3460 | tcmh.commitid++; | 3468 | tcmh.commitid++; |
3461 | 3469 | ||
3462 | lseek(masterfd, 0, SEEK_SET); | 3470 | lseek(masterfd, 0, SEEK_SET); |
3463 | write_master_header(masterfd, &tcmh); | 3471 | write_master_header(masterfd, &tcmh); |
3464 | close(masterfd); | 3472 | close(masterfd); |
3465 | 3473 | ||
3466 | logf("tagcache committed"); | 3474 | logf("tagcache committed"); |
3467 | tagcache_commit_finalize(); | 3475 | tagcache_commit_finalize(); |
3468 | 3476 | ||
3469 | #if defined(HAVE_TC_RAMCACHE) | 3477 | #if defined(HAVE_TC_RAMCACHE) |
3470 | if (ramcache_buffer_stolen) | 3478 | if (ramcache_buffer_stolen) |
3471 | { | 3479 | { |
3472 | tempbuf = NULL; | 3480 | tempbuf = NULL; |
3473 | tempbuf_size = 0; | 3481 | tempbuf_size = 0; |
3474 | ramcache_buffer_stolen = false; | 3482 | ramcache_buffer_stolen = false; |
3475 | tcrc_buffer_unlock(); | 3483 | tcrc_buffer_unlock(); |
3476 | } | 3484 | } |
3477 | 3485 | ||
3478 | /* Reload tagcache. */ | 3486 | /* Reload tagcache. */ |
3479 | if (tc_stat.ramcache_allocated > 0) | 3487 | if (tc_stat.ramcache_allocated > 0) |
3480 | tagcache_start_scan(); | 3488 | tagcache_start_scan(); |
3481 | #endif /* HAVE_TC_RAMCACHE */ | 3489 | #endif /* HAVE_TC_RAMCACHE */ |
3482 | 3490 | ||
3483 | rc = true; | 3491 | rc = true; |
3492 | } /*!USR_CANCEL*/ | ||
3484 | 3493 | ||
3485 | commit_error: | 3494 | commit_error: |
3486 | #ifdef HAVE_TC_RAMCACHE | 3495 | #ifdef HAVE_TC_RAMCACHE |