From a0c29d8857ee3c697a9c7f8b396b3a25c88acab4 Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Fri, 6 Oct 2023 10:57:05 -0400 Subject: 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 --- apps/plugins/tagcache/tagcache.c | 583 ++++++++++++++++++++++++++++++++++----- 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 @@ /*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,62 +869,32 @@ 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(); - - commit(); - - 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; -} - -/****************** main thread + helper ******************/ -static void thread(void) -{ - struct queue_event ev; while (!gThread.exiting) { - rb->queue_wait_w_tmo(&gThread.queue, &ev, 1); - switch (ev.id) - { - case SYS_USB_CONNECTED: - rb->usb_acknowledge(SYS_USB_CONNECTED_ACK); - logenabled = false; - break; - case SYS_USB_DISCONNECTED: - logenabled = true; - /*fall through*/ - case EV_STARTUP: - logf("Thread Started"); - break; - case EV_EXIT: - return; - default: - break; - } logdisplay(); - int action = rb->get_action(CONTEXT_STD, HZ/10); + int action = rb->get_action(CONTEXT_STD, HZ/20); switch( action ) { @@ -536,8 +916,15 @@ static void thread(void) break; case SYS_POWEROFF: case ACTION_STD_CANCEL: - gThread.exiting = true; - return; + 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: { @@ -561,8 +948,60 @@ static void thread(void) 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(); + /* Turn on backlight timeout (revert to settings) */ + backlight_use_settings(); + return PLUGIN_OK; +} +/****************** main thread + helper ******************/ +static void thread(void) +{ + struct queue_event ev; + while (!gThread.exiting) + { + rb->queue_wait_w_tmo(&gThread.queue, &ev, 1); + switch (ev.id) + { + case SYS_USB_CONNECTED: + rb->usb_acknowledge(SYS_USB_CONNECTED_ACK); + logenabled = false; + break; + case SYS_USB_DISCONNECTED: + logenabled = true; + /*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: + gThread.exiting = true; + return; + default: + break; + } yield(); } } 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 @@ #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,41 +3452,44 @@ static bool commit(void) tc_stat.commit_step = 0; - /* Update the master index headers. */ - if ( (masterfd = open_master_fd(&tcmh, true)) < 0) - goto commit_error; + if (!USR_CANCEL) + { + /* Update the master index headers. */ + if ( (masterfd = open_master_fd(&tcmh, true)) < 0) + goto commit_error; - remove_db_file(TAGCACHE_FILE_TEMP); + remove_db_file(TAGCACHE_FILE_TEMP); - tcmh.tch.entry_count += tch.entry_count; - tcmh.tch.datasize = sizeof(struct master_header) - + sizeof(struct index_entry) * tcmh.tch.entry_count - + tch.datasize; - tcmh.dirty = false; - tcmh.commitid++; + tcmh.tch.entry_count += tch.entry_count; + tcmh.tch.datasize = sizeof(struct master_header) + + sizeof(struct index_entry) * tcmh.tch.entry_count + + tch.datasize; + tcmh.dirty = false; + tcmh.commitid++; - lseek(masterfd, 0, SEEK_SET); - write_master_header(masterfd, &tcmh); - close(masterfd); + lseek(masterfd, 0, SEEK_SET); + write_master_header(masterfd, &tcmh); + close(masterfd); - logf("tagcache committed"); - tagcache_commit_finalize(); + logf("tagcache committed"); + tagcache_commit_finalize(); #if defined(HAVE_TC_RAMCACHE) - if (ramcache_buffer_stolen) - { - tempbuf = NULL; - tempbuf_size = 0; - ramcache_buffer_stolen = false; - tcrc_buffer_unlock(); - } + if (ramcache_buffer_stolen) + { + tempbuf = NULL; + tempbuf_size = 0; + ramcache_buffer_stolen = false; + tcrc_buffer_unlock(); + } - /* Reload tagcache. */ - if (tc_stat.ramcache_allocated > 0) - tagcache_start_scan(); + /* Reload tagcache. */ + if (tc_stat.ramcache_allocated > 0) + tagcache_start_scan(); #endif /* HAVE_TC_RAMCACHE */ - rc = true; + rc = true; + } /*!USR_CANCEL*/ commit_error: #ifdef HAVE_TC_RAMCACHE -- cgit v1.2.3