diff --git a/elem.h b/elem.h index e9c13eff..06f2accc 100644 --- a/elem.h +++ b/elem.h @@ -65,8 +65,6 @@ struct snapraid_filter { tommy_node node; /**< Next node in the list. */ }; -struct snapraid_file; - /** * The block has both the hash and the parity computed. * This is the normal state of a saved block. @@ -312,6 +310,11 @@ struct snapraid_map { tommy_node node; }; +/** + * Info. + */ +typedef unsigned snapraid_info; + /** * Allocates a content. */ @@ -675,5 +678,14 @@ struct snapraid_map* map_alloc(const char* name, unsigned position, const char* */ void map_free(struct snapraid_map* map); +/** + * Make an info. + */ +static inline snapraid_info info_make(time_t last_access) +{ + /* clear the low bit to keep some free bits */ + return last_access & ~0xFF; +} + #endif diff --git a/snapraid.1 b/snapraid.1 index 153ad38c..833db42e 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -1067,6 +1067,10 @@ for which the parity is computed using the previous value. .PP This field is used only when you interrupt manually the \(a"sync\(a" command. +.SS inf BLOCK TIME +Information shared by all the block at the specified offset. +TIME is the last time of the hash/parity verification done at this +block. .SS symlink DISK PATH Defines a symbolic link in the specified DISK. .SS hardlink DISK PATH diff --git a/snapraid.d b/snapraid.d index 9106656c..f4fa6a31 100644 --- a/snapraid.d +++ b/snapraid.d @@ -793,6 +793,11 @@ Content This field is used only when you interrupt manually the "sync" command. + inf BLOCK TIME + Information shared by all the block at the specified offset. + TIME is the last time of the hash/parity verification done at this + block. + symlink DISK PATH Defines a symbolic link in the specified DISK. diff --git a/state.c b/state.c index f4a56e58..3a8eb0d8 100644 --- a/state.c +++ b/state.c @@ -54,6 +54,7 @@ void state_init(struct snapraid_state* state) tommy_list_init(&state->filterlist); tommy_list_init(&state->importlist); tommy_hashdyn_init(&state->importset); + tommy_array_init(&state->infoarr); state->loaded_blockmax = 0; } @@ -65,6 +66,7 @@ void state_done(struct snapraid_state* state) tommy_list_foreach(&state->filterlist, (tommy_foreach_func*)filter_free); tommy_list_foreach(&state->importlist, (tommy_foreach_func*)import_file_free); tommy_hashdyn_done(&state->importset); + tommy_array_done(&state->infoarr); } /** @@ -1007,6 +1009,39 @@ void state_read(struct snapraid_state* state) /* stat */ ++count_block; + } else if (strcmp(tag, "inf") == 0) { + /* "inf" command */ + block_off_t v_pos; + snapraid_info info; + uint32_t t; + + hash = oathash8(hash, 'i'); + + ret = sgetu32(f, &v_pos); + if (ret < 0) { + fprintf(stderr, "Invalid 'inf' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + hash = oathash32(hash, v_pos); + + c = sgetc(f); + if (c != ' ') { + fprintf(stderr, "Invalid 'inf' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + + ret = sgetu32(f, &t); + if (ret < 0) { + fprintf(stderr, "Invalid 'inf' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + hash = oathash32(hash, t); + + info = info_make(t); + + /* insert the block in the block array */ + tommy_array_grow(&state->infoarr, v_pos + 1); + tommy_array_set(&state->infoarr, v_pos, (void*)info); } else if (strcmp(tag, "off") == 0) { /* "off" command */ block_off_t v_pos; @@ -1623,6 +1658,8 @@ void state_write(struct snapraid_state* state) unsigned count_dir; unsigned count_content; tommy_node* i; + block_off_t b; + block_off_t infomax; unsigned k; oathash_t hash; @@ -1632,6 +1669,7 @@ void state_write(struct snapraid_state* state) count_symlink = 0; count_dir = 0; hash = 0; + infomax = 0; /* index of the maximum info saved from all the disks */ /* count the content files */ count_content = 0; @@ -1734,11 +1772,12 @@ void state_write(struct snapraid_state* state) for(i=state->disklist;i!=0;i=i->next) { tommy_node* j; struct snapraid_disk* disk = i->data; + block_off_t blockmax; + int first_deleted; /* for each file */ for(j=disk->filelist;j!=0;j=j->next) { struct snapraid_file* file = j->data; - block_off_t k; uint64_t size; uint64_t mtime_sec; int32_t mtime_nsec; @@ -1777,8 +1816,8 @@ void state_write(struct snapraid_state* state) } /* for each block in the file */ - for(k=0;kblockmax;++k) { - struct snapraid_block* block = &file->blockvec[k]; + for(b=0;bblockmax;++b) { + struct snapraid_block* block = &file->blockvec[b]; unsigned block_state; block_state = block_state_get(block); @@ -1800,6 +1839,10 @@ void state_write(struct snapraid_state* state) exit(EXIT_FAILURE); } + /* keep track of the maximum block */ + if (block->parity_pos > infomax) + infomax = block->parity_pos; + sputu32(block->parity_pos, f); hash = oathash32(hash, block->parity_pos); @@ -1874,49 +1917,81 @@ void state_write(struct snapraid_state* state) ++count_dir; } - /* save all the delete blocks */ - { - block_off_t k; - block_off_t blockmax; - int first_deleted; - - first_deleted = 1; - blockmax = tommy_array_size(&disk->blockarr); + /* maximum block */ + blockmax = tommy_array_size(&disk->blockarr); - /* for each deleted block in the disk */ - for(k=0;kblockarr, k); - if (block_state_get(block) == BLOCK_STATE_DELETED) { - if (first_deleted) { - first_deleted = 0; - - sputsl("hole ", f); - hash = oathash8(hash, 'h'); - sputs(disk->name, f); - hash = oathashs(hash, disk->name); - sputeol(f); - if (serror(f)) { - fprintf(stderr, "Error writing the content file '%s'. %s.\n", serrorfile(f), strerror(errno)); - exit(EXIT_FAILURE); - } - } - - sputsl("off ", f); - hash = oathash8(hash, 'o'); - - sputu32(k, f); - hash = oathash32(hash, k); - - sputc(' ', f); - sputhex(block->hash, HASH_SIZE, f); - hash = oathashm(hash, block->hash, HASH_SIZE); + /* for each deleted block in the disk */ + first_deleted = 1; + for(b=0;bblockarr, b); + if (block_state_get(block) == BLOCK_STATE_DELETED) { + if (first_deleted) { + first_deleted = 0; + sputsl("hole ", f); + hash = oathash8(hash, 'h'); + sputs(disk->name, f); + hash = oathashs(hash, disk->name); sputeol(f); if (serror(f)) { fprintf(stderr, "Error writing the content file '%s'. %s.\n", serrorfile(f), strerror(errno)); exit(EXIT_FAILURE); } } + + sputsl("off ", f); + hash = oathash8(hash, 'o'); + + /* keep track of the maximum block */ + if (b > infomax) + infomax = b; + + sputu32(b, f); + hash = oathash32(hash, b); + + sputc(' ', f); + sputhex(block->hash, HASH_SIZE, f); + hash = oathashm(hash, block->hash, HASH_SIZE); + + sputeol(f); + if (serror(f)) { + fprintf(stderr, "Error writing the content file '%s'. %s.\n", serrorfile(f), strerror(errno)); + exit(EXIT_FAILURE); + } + } + } + } + + /* note that here infomax contains the maximum block for which we wrote something */ + /* tha could be smaller than of blocks we have in memory, in case of deleted blocks */ + + /* don't try to write more info than stored */ + if (infomax > tommy_array_size(&state->infoarr)) + infomax = tommy_array_size(&state->infoarr); + + /* for each block */ + for(b=0;binfoarr, b); + + /* save only stuff different than 0 */ + if (info != 0) { + sputsl("inf ", f); + hash = oathash8(hash, 'i'); + + sputu32(b, f); + hash = oathash32(hash, b); + + sputc(' ', f); + + sputu32(info, f); + hash = oathash32(hash, info); + + sputeol(f); + if (serror(f)) { + fprintf(stderr, "Error writing the content file '%s'. %s.\n", serrorfile(f), strerror(errno)); + exit(EXIT_FAILURE); } } } diff --git a/state.h b/state.h index 079281ac..b02ab753 100644 --- a/state.h +++ b/state.h @@ -62,6 +62,7 @@ struct snapraid_state { tommy_list filterlist; /**< List of inclusion/exclusion. */ tommy_list importlist; /**< List of import file. */ tommy_hashdyn importset; /**< Hashtable by hash of all the import blocks. */ + tommy_array infoarr; /**< Block information array. */ block_off_t loaded_blockmax; /**< Previous size of the parity file, computed from the loaded state. */ time_t progress_start; /**< Start of processing for progress visualization. */ time_t progress_last; /**< Last update of progress visualization. */