diff --git a/cmdline/elem.c b/cmdline/elem.c index e1f67bda..21b7d239 100644 --- a/cmdline/elem.c +++ b/cmdline/elem.c @@ -462,18 +462,30 @@ struct snapraid_file* file_alloc(unsigned block_size, const char* sub, data_off_ { struct snapraid_file* file; block_off_t i; + block_off_t blockmax; + + blockmax = size / block_size; + if (size % block_size != 0) + ++blockmax; + +#if SIZE_MAX == UINT32_MAX + if (blockmax > (block_off_t)(SIZE_MAX / block_sizeof())) { + log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", sub, blockmax); + exit(EXIT_FAILURE); + } +#endif file = malloc_nofail(sizeof(struct snapraid_file)); file->sub = strdup_nofail(sub); file->size = size; - file->blockmax = (size + block_size - 1) / block_size; + file->blockmax = blockmax; file->mtime_sec = mtime_sec; file->mtime_nsec = mtime_nsec; file->inode = inode; file->physical = physical; file->flag = 0; file->shared_flag = 0; - file->blockvec = nalloc_nofail(file->blockmax, block_sizeof()); + file->blockvec = nalloc_nofail((size_t)file->blockmax, block_sizeof()); for (i = 0; i < file->blockmax; ++i) { struct snapraid_block* block = file_block(file, i); @@ -489,6 +501,13 @@ struct snapraid_file* file_dup(struct snapraid_file* copy) struct snapraid_file* file; block_off_t i; +#if SIZE_MAX == UINT32_MAX + if (copy->blockmax > (block_off_t)(SIZE_MAX / block_sizeof())) { + log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", copy->sub, copy->blockmax); + exit(EXIT_FAILURE); + } +#endif + file = malloc_nofail(sizeof(struct snapraid_file)); file->sub = strdup_nofail(copy->sub); file->size = copy->size; @@ -499,7 +518,7 @@ struct snapraid_file* file_dup(struct snapraid_file* copy) file->physical = copy->physical; file->flag = copy->flag; file->shared_flag = 0; - file->blockvec = nalloc_nofail(file->blockmax, block_sizeof()); + file->blockvec = nalloc_nofail((size_t)file->blockmax, block_sizeof()); for (i = 0; i < file->blockmax; ++i) { struct snapraid_block* block = file_block(file, i); @@ -847,14 +866,26 @@ int dir_name_compare(const void* void_arg, const void* void_data) struct snapraid_dealloc* dealloc_alloc(unsigned block_size, const char* sub, data_off_t size, int64_t mtime_sec, int32_t mtime_nsec) { struct snapraid_dealloc* dealloc; + block_off_t blockmax; + + blockmax = size / block_size; + if (size % block_size != 0) + ++blockmax; + +#if SIZE_MAX == UINT32_MAX + if (blockmax > (block_off_t)(SIZE_MAX / BLOCK_HASH_SIZE)) { + log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", sub, blockmax); + exit(EXIT_FAILURE); + } +#endif dealloc = malloc_nofail(sizeof(struct snapraid_dealloc)); dealloc->sub = strdup_nofail(sub); dealloc->size = size; dealloc->mtime_sec = mtime_sec; dealloc->mtime_nsec = mtime_nsec; - dealloc->blockmax = (size + block_size - 1) / block_size; - dealloc->blockhash = nalloc_nofail(dealloc->blockmax, BLOCK_HASH_SIZE); + dealloc->blockmax = blockmax; + dealloc->blockhash = nalloc_nofail((size_t)dealloc->blockmax, BLOCK_HASH_SIZE); return dealloc; } @@ -1488,6 +1519,15 @@ void fs_allocate(struct snapraid_disk* disk, block_off_t parity_pos, struct snap struct snapraid_extent* parity_extent; struct snapraid_extent* file_extent; +#if SIZE_MAX == UINT32_MAX + if (parity_pos > (block_off_t)(SIZE_MAX - 4096)) { + /* LCOV_EXCL_START */ + log_fatal(ESOFT, "Parity position %" PRIu64 " is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", parity_pos); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } +#endif + fs_lock(disk); if (file_pos > 0) { diff --git a/cmdline/elem.h b/cmdline/elem.h index fe0ede2e..72ac6cd5 100644 --- a/cmdline/elem.h +++ b/cmdline/elem.h @@ -866,7 +866,7 @@ void file_copy(struct snapraid_file* src_file, struct snapraid_file* dest_file); * * Note that the block size if a runtime value. */ -static inline struct snapraid_block* file_block(struct snapraid_file* file, size_t pos) +static inline struct snapraid_block* file_block(struct snapraid_file* file, block_off_t pos) { unsigned char* ptr = (unsigned char*)file->blockvec; diff --git a/cmdline/import.c b/cmdline/import.c index 7f8a6ac1..62b6cd03 100644 --- a/cmdline/import.c +++ b/cmdline/import.c @@ -49,12 +49,24 @@ static void import_file(struct snapraid_state* state, const char* path, uint64_t int flags; unsigned block_size = state->block_size; struct advise_struct advise; + block_off_t blockmax; + + blockmax = size / block_size; + if (size % block_size != 0) + ++blockmax; + +#if SIZE_MAX == UINT32_MAX + if (blockmax > (block_off_t)(SIZE_MAX / sizeof(struct snapraid_import_block))) { + log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", path, blockmax); + exit(EXIT_FAILURE); + } +#endif file = malloc_nofail(sizeof(struct snapraid_import_file)); file->path = strdup_nofail(path); file->size = size; - file->blockmax = (size + block_size - 1) / block_size; - file->blockimp = nalloc_nofail(file->blockmax, sizeof(struct snapraid_import_block)); + file->blockmax = blockmax; + file->blockimp = nalloc_nofail((size_t)file->blockmax, sizeof(struct snapraid_import_block)); file->is_runtime = 1; buffer = malloc_nofail(block_size); @@ -148,6 +160,7 @@ static void import_dealloc(struct snapraid_state* state, const char* dir, struct char path[PATH_MAX]; struct snapraid_import_file* file; block_off_t i; + block_off_t blockmax; data_off_t offset; data_off_t size; unsigned block_size = state->block_size; @@ -156,11 +169,22 @@ static void import_dealloc(struct snapraid_state* state, const char* dir, struct pathcat(path, sizeof(path), dealloc->sub); size = dealloc->size; + blockmax = size / block_size; + if (size % block_size != 0) + ++blockmax; + +#if SIZE_MAX == UINT32_MAX + if (blockmax > (block_off_t)(SIZE_MAX / sizeof(struct snapraid_import_block))) { + log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", path, blockmax); + exit(EXIT_FAILURE); + } +#endif + file = malloc_nofail(sizeof(struct snapraid_import_file)); file->path = strdup_nofail(path); file->size = size; - file->blockmax = (size + block_size - 1) / block_size; - file->blockimp = nalloc_nofail(file->blockmax, sizeof(struct snapraid_import_block)); + file->blockmax = blockmax; + file->blockimp = nalloc_nofail((size_t)file->blockmax, sizeof(struct snapraid_import_block)); file->is_runtime = 0; offset = 0; diff --git a/cmdline/state.c b/cmdline/state.c index 01d07e1d..d0eb2470 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -2004,6 +2004,16 @@ static void state_content_check(struct snapraid_state* state, const char* path) { tommy_node* i; +#if SIZE_MAX == UINT32_MAX + block_off_t blockmax = parity_allocated_size(state); + if (blockmax > (block_off_t)(SIZE_MAX - 4096)) { + /* LCOV_EXCL_START */ + log_fatal(ESOFT, "Array with %" PRIu64 " blocks in '%s' is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", blockmax, path); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } +#endif + /* check that any map has different name and position */ for (i = state->maplist; i != 0; i = i->next) { struct snapraid_map* map = i->data; diff --git a/cmdline/util.h b/cmdline/util.h index c5663b57..babdcf84 100644 --- a/cmdline/util.h +++ b/cmdline/util.h @@ -269,7 +269,7 @@ typedef unsigned char bit_vect_t; static inline size_t bit_vect_size(size_t max) { - return (max + BIT_VECT_SIZE - 1) / BIT_VECT_SIZE; + return (max / BIT_VECT_SIZE) + ((max % BIT_VECT_SIZE) != 0); } static inline void bit_vect_set(bit_vect_t* bit_vect, size_t off)