mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
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
This commit is contained in:
parent
eb13628bb8
commit
a0c29d8857
2 changed files with 572 additions and 124 deletions
|
@ -22,16 +22,19 @@
|
|||
/*Plugin Includes*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "errno.h"
|
||||
|
||||
/* Redefinitons of ANSI C functions. */
|
||||
#include "lib/wrappers.h"
|
||||
#include "lib/helper.h"
|
||||
|
||||
static void thread_create(void);
|
||||
static void thread(void); /* the thread running it all */
|
||||
static void thread(void); /* the thread running commit*/
|
||||
static void allocate_tempbuf(void);
|
||||
static void free_tempbuf(void);
|
||||
static bool do_timed_yield(void);
|
||||
static void _log(const char *fmt, ...);
|
||||
static bool logdump(bool append);
|
||||
/*Aliases*/
|
||||
#if 0
|
||||
#ifdef ROCKBOX_HAS_LOGF
|
||||
|
@ -41,7 +44,6 @@ static void _log(const char *fmt, ...);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define logf _log
|
||||
#define sleep rb->sleep
|
||||
#define qsort rb->qsort
|
||||
|
@ -49,6 +51,7 @@ static void _log(const char *fmt, ...);
|
|||
#define write(x,y,z) rb->write(x,y,z)
|
||||
#define ftruncate rb->ftruncate
|
||||
#define remove rb->remove
|
||||
#define rename rb->rename
|
||||
|
||||
#define vsnprintf rb->vsnprintf
|
||||
#define mkdir rb->mkdir
|
||||
|
@ -60,20 +63,26 @@ static void _log(const char *fmt, ...);
|
|||
|
||||
#define current_tick (*rb->current_tick)
|
||||
#define crc_32(x,y,z) rb->crc_32(x,y,z)
|
||||
#define plugin_get_buffer rb->plugin_get_buffer
|
||||
|
||||
|
||||
#if !defined(SIMULATOR) && !defined(APPLICATION)
|
||||
|
||||
#define errno (*rb->__errno())
|
||||
#endif
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define MAX_LOG_SIZE 16384
|
||||
|
||||
#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF)
|
||||
#define EV_ACTION MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02)
|
||||
#define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01)
|
||||
|
||||
#define BACKUP_DIRECTORY PLUGIN_APPS_DATA_DIR "/db_commit"
|
||||
|
||||
#define RC_SUCCESS 0
|
||||
#define RC_USER_CANCEL 2
|
||||
|
||||
enum fcpy_op_flags
|
||||
{
|
||||
FCPY_MOVE = 0x00, /* Is a move operation (default) */
|
||||
FCPY_COPY = 0x01, /* Is a copy operation */
|
||||
FCPY_OVERWRITE = 0x02, /* Overwrite destination */
|
||||
FCPY_EXDEV = 0x04, /* Actually copy/move across volumes */
|
||||
};
|
||||
|
||||
/* communication to the worker thread */
|
||||
static struct
|
||||
{
|
||||
|
@ -85,6 +94,23 @@ static struct
|
|||
long last_useraction_tick;
|
||||
} gThread;
|
||||
|
||||
/* status of db and commit */
|
||||
static struct
|
||||
{
|
||||
long last_check;
|
||||
bool do_commit;
|
||||
bool auto_commit;
|
||||
bool commit_ready;
|
||||
bool db_exists;
|
||||
bool have_backup;
|
||||
bool bu_exists;
|
||||
} gStatus;
|
||||
|
||||
static unsigned char logbuffer[MAX_LOG_SIZE + 1];
|
||||
static int log_font_h = -1;
|
||||
static int logindex;
|
||||
static bool logwrap;
|
||||
static bool logenabled = true;
|
||||
|
||||
/*Support Fns*/
|
||||
/* 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, ...)
|
|||
|
||||
static void sleep_yield(void)
|
||||
{
|
||||
rb->queue_remove_from_head(&gThread.queue, EV_ACTION);
|
||||
rb->queue_post(&gThread.queue, EV_ACTION, 0);
|
||||
sleep(1);
|
||||
#undef yield
|
||||
rb->yield();
|
||||
|
@ -159,18 +183,10 @@ bool user_check_tag(int index_type, char* build_idx_buf)
|
|||
/* paste the whole tagcache.c file */
|
||||
#include "../tagcache.c"
|
||||
|
||||
static bool logdump(bool append);
|
||||
static unsigned char logbuffer[MAX_LOG_SIZE + 1];
|
||||
static int log_font_h = -1;
|
||||
static int logindex;
|
||||
static bool logwrap;
|
||||
static bool logenabled = true;
|
||||
|
||||
static void check_logindex(void)
|
||||
{
|
||||
if(logindex >= MAX_LOG_SIZE)
|
||||
{
|
||||
/* wrap */
|
||||
logdump(true);
|
||||
//logwrap = true;
|
||||
logindex = 0;
|
||||
|
@ -196,7 +212,6 @@ static void _log(const char *fmt, ...)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USB_ENABLE_SERIAL
|
||||
int old_logindex = logindex;
|
||||
#endif
|
||||
|
@ -291,13 +306,11 @@ static bool logdisplay(void)
|
|||
/* if negative, will be set 0 to zero later */
|
||||
}
|
||||
|
||||
|
||||
rb->lcd_clear_display();
|
||||
|
||||
if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE)
|
||||
gThread.user_index = 0;
|
||||
|
||||
|
||||
if(logwrap)
|
||||
i = logindex;
|
||||
else
|
||||
|
@ -373,7 +386,7 @@ static bool logdump(bool append)
|
|||
/* nothing is logged just yet */
|
||||
return false;
|
||||
}
|
||||
if (!append)
|
||||
if (append)
|
||||
{
|
||||
flags = O_CREAT|O_WRONLY|O_APPEND;
|
||||
}
|
||||
|
@ -431,7 +444,6 @@ static bool do_timed_yield(void)
|
|||
static long wakeup_tick = 0;
|
||||
if (TIME_AFTER(current_tick, wakeup_tick))
|
||||
{
|
||||
|
||||
yield();
|
||||
|
||||
wakeup_tick = current_tick + (HZ/5);
|
||||
|
@ -440,6 +452,402 @@ static bool do_timed_yield(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* copy/move a file */
|
||||
static int fcpy(const char *src, const char *target,
|
||||
unsigned int flags, bool (*poll_cancel)(const char *))
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
while (!(flags & (FCPY_COPY | FCPY_EXDEV))) {
|
||||
if ((flags & FCPY_OVERWRITE) || !file_exists(target)) {
|
||||
/* Rename and possibly overwrite the file */
|
||||
if (poll_cancel && poll_cancel(src)) {
|
||||
rc = RC_USER_CANCEL;
|
||||
} else {
|
||||
rc = rename(src, target);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MULTIVOLUME
|
||||
if (rc < 0 && errno == EXDEV) {
|
||||
/* Failed because cross volume rename doesn't work; force
|
||||
a move instead */
|
||||
flags |= FCPY_EXDEV;
|
||||
break;
|
||||
}
|
||||
#endif /* HAVE_MULTIVOLUME */
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* See if we can get the plugin buffer for the file copy buffer */
|
||||
size_t buffersize;
|
||||
char *buffer = (char *) plugin_get_buffer(&buffersize);
|
||||
if (buffer == NULL || buffersize < 512) {
|
||||
/* Not large enough, try for a disk sector worth of stack
|
||||
instead */
|
||||
buffersize = 512;
|
||||
buffer = (char *)alloca(buffersize);
|
||||
}
|
||||
|
||||
if (buffer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffersize &= ~0x1ff; /* Round buffer size to multiple of sector
|
||||
size */
|
||||
|
||||
int src_fd = open(src, O_RDONLY);
|
||||
if (src_fd >= 0) {
|
||||
int oflag = O_WRONLY|O_CREAT;
|
||||
|
||||
if (!(flags & FCPY_OVERWRITE)) {
|
||||
oflag |= O_EXCL;
|
||||
}
|
||||
|
||||
int target_fd = open(target, oflag, 0666);
|
||||
if (target_fd >= 0) {
|
||||
off_t total_size = 0;
|
||||
off_t next_cancel_test = 0; /* No excessive button polling */
|
||||
|
||||
rc = RC_SUCCESS;
|
||||
|
||||
while (rc == RC_SUCCESS) {
|
||||
if (total_size >= next_cancel_test) {
|
||||
next_cancel_test = total_size + 0x10000;
|
||||
if (poll_cancel && poll_cancel(src)) {
|
||||
rc = RC_USER_CANCEL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t bytesread = read(src_fd, buffer, buffersize);
|
||||
if (bytesread <= 0) {
|
||||
if (bytesread < 0) {
|
||||
rc = -1;
|
||||
}
|
||||
/* else eof on buffer boundary; nothing to write */
|
||||
break;
|
||||
}
|
||||
|
||||
ssize_t byteswritten = write(target_fd, buffer, bytesread);
|
||||
if (byteswritten < bytesread) {
|
||||
/* Some I/O error */
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
total_size += byteswritten;
|
||||
|
||||
if (bytesread < (ssize_t)buffersize) {
|
||||
/* EOF with trailing bytes */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == RC_SUCCESS) {
|
||||
/* If overwriting, set the correct length if original was
|
||||
longer */
|
||||
rc = ftruncate(target_fd, total_size);
|
||||
}
|
||||
|
||||
close(target_fd);
|
||||
|
||||
if (rc != RC_SUCCESS) {
|
||||
/* Copy failed. Cleanup. */
|
||||
remove(target);
|
||||
}
|
||||
}
|
||||
|
||||
close(src_fd);
|
||||
}
|
||||
|
||||
if (rc == RC_SUCCESS && !(flags & FCPY_COPY)) {
|
||||
/* Remove the source file */
|
||||
rc = remove(src);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool backup_restore_tagcache(bool backup)
|
||||
{
|
||||
struct master_header tcmh;
|
||||
char path[MAX_PATH];
|
||||
char bu_path[MAX_PATH];
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
if (backup)
|
||||
{
|
||||
if (!rb->dir_exists(BACKUP_DIRECTORY))
|
||||
mkdir(BACKUP_DIRECTORY);
|
||||
snprintf(path, sizeof(path), "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path);
|
||||
snprintf(bu_path, sizeof(bu_path), "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rb->dir_exists(BACKUP_DIRECTORY))
|
||||
return false;
|
||||
snprintf(path, sizeof(path), "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY);
|
||||
snprintf(bu_path, sizeof(bu_path), "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path);
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY, 0666);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
rc = read(fd, &tcmh, sizeof(struct master_header));
|
||||
close(fd);
|
||||
if (rc != sizeof(struct master_header))
|
||||
{
|
||||
logf("master file read failed");
|
||||
return false;
|
||||
}
|
||||
int entries = tcmh.tch.entry_count;
|
||||
|
||||
logf("master file %d entries", entries);
|
||||
if (backup)
|
||||
logf("backup db to %s", BACKUP_DIRECTORY);
|
||||
else
|
||||
logf("restore db to %s", tc_stat.db_path);
|
||||
|
||||
if (entries > 0)
|
||||
{
|
||||
logf("%s", path);
|
||||
fcpy(path, bu_path, FCPY_COPY|FCPY_OVERWRITE, NULL);
|
||||
|
||||
for (int i = 0; i < TAG_COUNT; i++)
|
||||
{
|
||||
if (TAGCACHE_IS_NUMERIC(i))
|
||||
continue;
|
||||
snprintf(path, sizeof(path),
|
||||
"%s/"TAGCACHE_FILE_INDEX, tc_stat.db_path, i);
|
||||
|
||||
snprintf(bu_path, sizeof(bu_path),
|
||||
"%s/"TAGCACHE_FILE_INDEX, BACKUP_DIRECTORY, i);
|
||||
/* Note: above we swapped paths in the snprintf call here we swap variables */
|
||||
if (backup)
|
||||
{
|
||||
logf("%s", path);
|
||||
if (fcpy(path, bu_path, FCPY_COPY|FCPY_OVERWRITE, NULL) < 0)
|
||||
goto failed;
|
||||
gStatus.have_backup = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logf("%s", bu_path);
|
||||
if (fcpy(bu_path, path, FCPY_COPY|FCPY_OVERWRITE, NULL) < 0)
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
failed:
|
||||
if (backup)
|
||||
{
|
||||
logf("failed backup");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* asks the user if they wish to quit */
|
||||
static bool confirm_quit(void)
|
||||
{
|
||||
const struct text_message prompt =
|
||||
{ (const char*[]) {"Are you sure?", "This will abort commit."}, 2};
|
||||
enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL);
|
||||
return (response == YESNO_YES);
|
||||
}
|
||||
|
||||
/* asks the user if they wish to backup/restore */
|
||||
static bool prompt_backup_restore(bool backup)
|
||||
{
|
||||
const struct text_message bu_prompt = { (const char*[]) {"Backup database?"}, 1};
|
||||
const struct text_message re_prompt =
|
||||
{ (const char*[]) {"Error committing,", "Restore database?"}, 2};
|
||||
enum yesno_res response =
|
||||
rb->gui_syncyesno_run(backup ? &bu_prompt:&re_prompt, NULL, NULL);
|
||||
if(response == YESNO_YES)
|
||||
return backup_restore_tagcache(backup);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* list_get_name_cb(int selected_item, void* data,
|
||||
char* buf, size_t buf_len)
|
||||
{
|
||||
(void) data;
|
||||
(void) buf;
|
||||
(void) buf_len;
|
||||
|
||||
/* buf supplied isn't used so lets use it for a filename buffer */
|
||||
if (TIME_AFTER(current_tick, gStatus.last_check))
|
||||
{
|
||||
snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_NOCOMMIT, tc_stat.db_path);
|
||||
gStatus.auto_commit = !file_exists(buf);
|
||||
snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_TEMP, tc_stat.db_path);
|
||||
gStatus.commit_ready = file_exists(buf);
|
||||
snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path);
|
||||
gStatus.db_exists = file_exists(buf);
|
||||
snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY);
|
||||
gStatus.bu_exists = file_exists(buf);
|
||||
gStatus.last_check = current_tick + HZ;
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
switch(selected_item)
|
||||
{
|
||||
|
||||
case 0: /* exit */
|
||||
return ID2P(LANG_MENU_QUIT);
|
||||
case 1: /*sep*/
|
||||
return ID2P(VOICE_BLANK);
|
||||
case 2: /*backup*/
|
||||
if (!gStatus.db_exists)
|
||||
return ID2P(VOICE_BLANK);
|
||||
return "Backup";
|
||||
case 3: /*restore*/
|
||||
if (!gStatus.bu_exists)
|
||||
return ID2P(VOICE_BLANK);
|
||||
return "Restore";
|
||||
case 4: /*sep*/
|
||||
return ID2P(VOICE_BLANK);
|
||||
case 5: /*auto commit*/
|
||||
if (gStatus.auto_commit)
|
||||
return "Disable auto commit";
|
||||
else
|
||||
return "Enable auto commit";
|
||||
case 6: /*destroy*/
|
||||
if (gStatus.db_exists)
|
||||
return "Delete database";
|
||||
/*fall through*/
|
||||
case 7: /*sep*/
|
||||
return ID2P(VOICE_BLANK);
|
||||
case 8: /*commit*/
|
||||
if (gStatus.commit_ready)
|
||||
return "Commit";
|
||||
else
|
||||
return "Nothing to commit";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static int list_voice_cb(int list_index, void* data)
|
||||
{
|
||||
#define MAX_MENU_NAME 32
|
||||
if (!rb->global_settings->talk_menu)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
char buf[MAX_MENU_NAME];
|
||||
const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
|
||||
long id = P2ID((const unsigned char *)name);
|
||||
if(id>=0)
|
||||
rb->talk_id(id, true);
|
||||
else
|
||||
rb->talk_spell(name, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int commit_menu(void)
|
||||
{
|
||||
struct gui_synclist lists;
|
||||
bool exit = false;
|
||||
int button,i;
|
||||
int selection, ret = 0;
|
||||
|
||||
rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL);
|
||||
rb->gui_synclist_set_icon_callback(&lists, NULL);
|
||||
rb->gui_synclist_set_nb_items(&lists, 9);
|
||||
rb->gui_synclist_select_item(&lists, 0);
|
||||
|
||||
while (!exit)
|
||||
{
|
||||
rb->gui_synclist_draw(&lists);
|
||||
button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
|
||||
if (rb->gui_synclist_do_button(&lists, &button))
|
||||
continue;
|
||||
selection = rb->gui_synclist_get_sel_pos(&lists);
|
||||
|
||||
if (button == ACTION_STD_CANCEL)
|
||||
return 0;
|
||||
else if (button == ACTION_STD_OK)
|
||||
{
|
||||
switch(selection)
|
||||
{
|
||||
case 0: /* exit */
|
||||
exit = true;
|
||||
break;
|
||||
case 1: /*sep*/
|
||||
continue;
|
||||
case 2: /*backup*/
|
||||
if (!gStatus.db_exists)
|
||||
break;
|
||||
if (!backup_restore_tagcache(true))
|
||||
rb->splash(HZ, "Backup failed!");
|
||||
else
|
||||
{
|
||||
rb->splash(HZ, "Backup success!");
|
||||
gStatus.bu_exists = true;
|
||||
}
|
||||
break;
|
||||
case 3: /*restore*/
|
||||
if (!gStatus.bu_exists)
|
||||
break;
|
||||
if (!backup_restore_tagcache(false))
|
||||
rb->splash(HZ, "Restore failed!");
|
||||
else
|
||||
rb->splash(HZ, "Restore success!");
|
||||
break;
|
||||
case 4: /*sep*/
|
||||
continue;
|
||||
case 5: /*auto commit*/
|
||||
{
|
||||
/* build_idx_buf supplied by tagcache.c isn't being used
|
||||
* so lets use it for a filename buffer */
|
||||
snprintf(build_idx_buf, build_idx_bufsz,
|
||||
"%s/" TAGCACHE_FILE_NOCOMMIT, tc_stat.db_path);
|
||||
if(gStatus.auto_commit)
|
||||
close(open(build_idx_buf, O_WRONLY | O_CREAT | O_TRUNC, 0666));
|
||||
else
|
||||
remove(build_idx_buf);
|
||||
gStatus.auto_commit = !file_exists(build_idx_buf);
|
||||
break;
|
||||
}
|
||||
case 6: /*destroy*/
|
||||
{
|
||||
if (!gStatus.db_exists)
|
||||
break;
|
||||
const struct text_message prompt =
|
||||
{ (const char*[]) {"Are you sure?", "This will destroy database."}, 2};
|
||||
if (rb->gui_syncyesno_run(&prompt, NULL, NULL) == YESNO_YES)
|
||||
remove_files();
|
||||
break;
|
||||
}
|
||||
case 7: /*sep*/
|
||||
continue;
|
||||
case 8: /*commit*/
|
||||
if (gStatus.commit_ready)
|
||||
{
|
||||
gStatus.do_commit = true;
|
||||
exit = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MENU_ATTACHED_USB:
|
||||
return PLUGIN_USB_CONNECTED;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} /*while*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/******* plugin_start ******* */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
@ -451,6 +859,8 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
/* Turn off backlight timeout */
|
||||
backlight_ignore_timeout();
|
||||
|
||||
memset(&gThread, 0, sizeof(gThread));
|
||||
memset(&gStatus, 0, sizeof(gStatus));
|
||||
memset(&tc_stat, 0, sizeof(struct tagcache_stat));
|
||||
memset(¤t_tcmh, 0, sizeof(struct master_header));
|
||||
filenametag_fd = -1;
|
||||
|
@ -459,30 +869,102 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */
|
||||
strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path));
|
||||
tc_stat.initialized = true;
|
||||
tc_stat.commit_step = -1;
|
||||
|
||||
memset(&gThread, 0, sizeof(gThread));
|
||||
logf("started");
|
||||
logdump(false);
|
||||
|
||||
int result = commit_menu();
|
||||
|
||||
if (!gStatus.do_commit)
|
||||
{
|
||||
/* Turn on backlight timeout (revert to settings) */
|
||||
backlight_use_settings();
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
logdump(false);
|
||||
allocate_tempbuf();
|
||||
if (gStatus.db_exists && !gStatus.have_backup && !prompt_backup_restore(true))
|
||||
rb->splash(HZ, "Backup failed!");
|
||||
thread_create();
|
||||
gThread.user_index = 0;
|
||||
logdisplay(); /* get something on the screen while user waits */
|
||||
|
||||
allocate_tempbuf();
|
||||
while (!gThread.exiting)
|
||||
{
|
||||
logdisplay();
|
||||
|
||||
commit();
|
||||
int action = rb->get_action(CONTEXT_STD, HZ/20);
|
||||
|
||||
switch( action )
|
||||
{
|
||||
case ACTION_NONE:
|
||||
break;
|
||||
case ACTION_STD_NEXT:
|
||||
case ACTION_STD_NEXTREPEAT:
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
gThread.user_index++;
|
||||
break;
|
||||
case ACTION_STD_PREV:
|
||||
case ACTION_STD_PREVREPEAT:
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
gThread.user_index--;
|
||||
break;
|
||||
case ACTION_STD_OK:
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
gThread.user_index = 0;
|
||||
break;
|
||||
case SYS_POWEROFF:
|
||||
case ACTION_STD_CANCEL:
|
||||
if (tc_stat.commit_step >= 0 && !tc_stat.ready)
|
||||
{
|
||||
if (!confirm_quit())
|
||||
break;
|
||||
tc_stat.commit_delayed = true; /* Cancel the commit */
|
||||
}
|
||||
rb->queue_remove_from_head(&gThread.queue, EV_EXIT);
|
||||
rb->queue_post(&gThread.queue, EV_EXIT, 0);
|
||||
break;
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
case ACTION_TOUCHSCREEN:
|
||||
{
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
short x, y;
|
||||
static int prev_y;
|
||||
|
||||
action = rb->action_get_touchscreen_press(&x, &y);
|
||||
|
||||
if(action & BUTTON_REL)
|
||||
prev_y = 0;
|
||||
else
|
||||
{
|
||||
if(prev_y != 0)
|
||||
gThread.user_index += (prev_y - y) / log_font_h;
|
||||
|
||||
prev_y = y;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
|
||||
rb->thread_wait(gThread.id);
|
||||
rb->queue_delete(&gThread.queue);
|
||||
free_tempbuf();
|
||||
|
||||
if (tc_stat.commit_delayed || !tc_stat.ready)
|
||||
{
|
||||
remove_files();
|
||||
if (gStatus.bu_exists && !prompt_backup_restore(false))
|
||||
rb->splash(HZ, "Restore failed!");
|
||||
}
|
||||
|
||||
if (tc_stat.ready)
|
||||
rb->tagcache_commit_finalize();
|
||||
|
||||
free_tempbuf();
|
||||
|
||||
logdump(true);
|
||||
gThread.user_index++;
|
||||
logdisplay();
|
||||
rb->thread_wait(gThread.id);
|
||||
rb->queue_delete(&gThread.queue);
|
||||
|
||||
/* Turn on backlight timeout (revert to settings) */
|
||||
backlight_use_settings();
|
||||
return PLUGIN_OK;
|
||||
|
@ -506,63 +988,20 @@ static void thread(void)
|
|||
/*fall through*/
|
||||
case EV_STARTUP:
|
||||
logf("Thread Started");
|
||||
cpu_boost(true);
|
||||
if (commit())
|
||||
tc_stat.ready = true;
|
||||
cpu_boost(false);
|
||||
logdump(true);
|
||||
gThread.user_index++;
|
||||
logdisplay();
|
||||
break;
|
||||
case EV_EXIT:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
logdisplay();
|
||||
|
||||
int action = rb->get_action(CONTEXT_STD, HZ/10);
|
||||
|
||||
switch( action )
|
||||
{
|
||||
case ACTION_NONE:
|
||||
break;
|
||||
case ACTION_STD_NEXT:
|
||||
case ACTION_STD_NEXTREPEAT:
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
gThread.user_index++;
|
||||
break;
|
||||
case ACTION_STD_PREV:
|
||||
case ACTION_STD_PREVREPEAT:
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
gThread.user_index--;
|
||||
break;
|
||||
case ACTION_STD_OK:
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
gThread.user_index = 0;
|
||||
break;
|
||||
case SYS_POWEROFF:
|
||||
case ACTION_STD_CANCEL:
|
||||
gThread.exiting = true;
|
||||
return;
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
case ACTION_TOUCHSCREEN:
|
||||
{
|
||||
gThread.last_useraction_tick = current_tick;
|
||||
short x, y;
|
||||
static int prev_y;
|
||||
|
||||
action = rb->action_get_touchscreen_press(&x, &y);
|
||||
|
||||
if(action & BUTTON_REL)
|
||||
prev_y = 0;
|
||||
else
|
||||
{
|
||||
if(prev_y != 0)
|
||||
gThread.user_index += (prev_y - y) / log_font_h;
|
||||
|
||||
prev_y = y;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,9 @@
|
|||
#include "lang.h"
|
||||
#include "eeprom_settings.h"
|
||||
#endif
|
||||
#define USR_CANCEL false
|
||||
#else/*!defined(PLUGIN)*/
|
||||
#define USR_CANCEL (tc_stat.commit_delayed == true)
|
||||
#endif /*!defined(PLUGIN)*/
|
||||
/*
|
||||
* 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)
|
|||
unsigned *crcbuf = (unsigned *)&tempbuf[tempbuf_size-4];
|
||||
unsigned crc32 = 0xffffffff;
|
||||
char chr_lower;
|
||||
for (i = 0; str[i] != '\0' && i < len; i++)
|
||||
for (i = 0; str[i] != '\0' && i < len -1; i++)
|
||||
{
|
||||
chr_lower = tolower(str[i]);
|
||||
crc32 = crc_32(&chr_lower, 1, crc32);
|
||||
|
@ -2404,9 +2407,12 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
|
|||
|
||||
/* Insert it to the buffer. */
|
||||
tempbuf_left -= len;
|
||||
if (tempbuf_left - 4 < 0 || tempbufidx >= commit_entry_count-1)
|
||||
if (tempbuf_left - 4 < 0 || tempbufidx >= commit_entry_count)
|
||||
{
|
||||
logf("temp buf error rem: %ld idx: %d / %d",
|
||||
tempbuf_left, tempbufidx, commit_entry_count-1);
|
||||
return false;
|
||||
|
||||
}
|
||||
if (id >= lookup_buffer_depth)
|
||||
{
|
||||
logf("lookup buf overf. #2: %d", id);
|
||||
|
@ -2585,7 +2591,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
|
|||
return false;
|
||||
}
|
||||
|
||||
while (entries_processed < h->entry_count)
|
||||
while (entries_processed < h->entry_count && !USR_CANCEL)
|
||||
{
|
||||
int count = MIN(h->entry_count - entries_processed, max_entries);
|
||||
|
||||
|
@ -2651,7 +2657,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
|
|||
lseek(masterfd, sizeof(struct master_header), SEEK_SET);
|
||||
|
||||
/* Check if we can resurrect some deleted runtime statistics data. */
|
||||
for (i = 0; i < tcmh.tch.entry_count; i++)
|
||||
for (i = 0; i < tcmh.tch.entry_count && !USR_CANCEL; i++)
|
||||
{
|
||||
/* Read the index entry. */
|
||||
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)
|
|||
lseek(masterfd, masterfd_pos, SEEK_SET);
|
||||
|
||||
/* Commit the data to the index. */
|
||||
for (i = 0; i < count; i++)
|
||||
for (i = 0; i < count && !USR_CANCEL; i++)
|
||||
{
|
||||
int loc = lseek(masterfd, 0, SEEK_CUR);
|
||||
|
||||
|
@ -2895,7 +2901,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
if (TAGCACHE_IS_SORTED(index_type))
|
||||
{
|
||||
logf("loading tags...");
|
||||
for (i = 0; i < tch.entry_count; i++)
|
||||
for (i = 0; i < tch.entry_count && !USR_CANCEL; i++)
|
||||
{
|
||||
struct tagfile_entry entry;
|
||||
int loc = lseek(fd, 0, SEEK_CUR);
|
||||
|
@ -3040,7 +3046,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
|
||||
/* h is the header of the temporary file containing new tags. */
|
||||
logf("inserting new tags...");
|
||||
for (i = 0; i < h->entry_count; i++)
|
||||
for (i = 0; i < h->entry_count && !USR_CANCEL; i++)
|
||||
{
|
||||
struct temp_file_entry entry;
|
||||
|
||||
|
@ -3112,7 +3118,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
*/
|
||||
logf("updating indices...");
|
||||
lseek(masterfd, sizeof(struct master_header), SEEK_SET);
|
||||
for (i = 0; i < tcmh.tch.entry_count; i += idxbuf_pos)
|
||||
for (i = 0; i < tcmh.tch.entry_count && !USR_CANCEL; i += idxbuf_pos)
|
||||
{
|
||||
int j;
|
||||
int loc = lseek(masterfd, 0, SEEK_CUR);
|
||||
|
@ -3172,7 +3178,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
|
|||
lseek(masterfd, masterfd_pos, SEEK_SET);
|
||||
lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
|
||||
lseek(fd, 0, SEEK_END);
|
||||
for (i = 0; i < h->entry_count; i += idxbuf_pos)
|
||||
for (i = 0; i < h->entry_count && !USR_CANCEL; i += idxbuf_pos)
|
||||
{
|
||||
int j;
|
||||
|
||||
|
@ -3412,7 +3418,7 @@ static bool commit(void)
|
|||
tch.datasize = 0;
|
||||
tc_stat.commit_delayed = false;
|
||||
|
||||
for (i = 0; i < TAG_COUNT; i++)
|
||||
for (i = 0; i < TAG_COUNT && !USR_CANCEL; i++)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -3446,6 +3452,8 @@ static bool commit(void)
|
|||
|
||||
tc_stat.commit_step = 0;
|
||||
|
||||
if (!USR_CANCEL)
|
||||
{
|
||||
/* Update the master index headers. */
|
||||
if ( (masterfd = open_master_fd(&tcmh, true)) < 0)
|
||||
goto commit_error;
|
||||
|
@ -3481,6 +3489,7 @@ static bool commit(void)
|
|||
#endif /* HAVE_TC_RAMCACHE */
|
||||
|
||||
rc = true;
|
||||
} /*!USR_CANCEL*/
|
||||
|
||||
commit_error:
|
||||
#ifdef HAVE_TC_RAMCACHE
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue