summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2023-10-06 10:57:05 -0400
committerWilliam Wilgus <me.theuser@yahoo.com>2023-10-10 05:48:37 -0400
commita0c29d8857ee3c697a9c7f8b396b3a25c88acab4 (patch)
treea047267e3f34b24a6f31d00046aba5ae685006a5
parenteb13628bb86084bdf822e109c1301277d88d23d7 (diff)
downloadrockbox-a0c29d8857ee3c697a9c7f8b396b3a25c88acab4.tar.gz
rockbox-a0c29d8857ee3c697a9c7f8b396b3a25c88acab4.zip
db_commit swap threads, add ability to cancel, backup/restore
extends the db_commit plugin with the ability to delete the database backup, restore, dis/enable auto-commit Change-Id: Id61546e463d151399d2ac8459480e6adc5d6fac6
-rw-r--r--apps/plugins/tagcache/tagcache.c583
-rw-r--r--apps/tagcache.c83
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
29static void thread_create(void); 31static void thread_create(void);
30static void thread(void); /* the thread running it all */ 32static void thread(void); /* the thread running commit*/
31static void allocate_tempbuf(void); 33static void allocate_tempbuf(void);
32static void free_tempbuf(void); 34static void free_tempbuf(void);
33static bool do_timed_yield(void); 35static bool do_timed_yield(void);
34static void _log(const char *fmt, ...); 36static void _log(const char *fmt, ...);
37static 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
78enum 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 */
78static struct 87static 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 */
98static 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
109static unsigned char logbuffer[MAX_LOG_SIZE + 1];
110static int log_font_h = -1;
111static int logindex;
112static bool logwrap;
113static 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
104static void sleep_yield(void) 130static 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
162static bool logdump(bool append);
163static unsigned char logbuffer[MAX_LOG_SIZE + 1];
164static int log_font_h = -1;
165static int logindex;
166static bool logwrap;
167static bool logenabled = true;
168
169static void check_logindex(void) 186static 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 */
456static 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
573static 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 }
647failed:
648 if (backup)
649 {
650 logf("failed backup");
651 }
652
653 return false;
654}
655
656/* asks the user if they wish to quit */
657static 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 */
666static 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
678static 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
738static 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
756static 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(&current_tcmh, 0, sizeof(struct master_header)); 865 memset(&current_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 ******************/
492static 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 ******************/
974static 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
3485commit_error: 3494commit_error:
3486#ifdef HAVE_TC_RAMCACHE 3495#ifdef HAVE_TC_RAMCACHE