diff --git a/CMakeLists.txt b/CMakeLists.txt index f916e3a..e5f9627 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ if (TESTS) endif() if (DEBUG) - add_compile_options($<$:-ggdb>) + set(CMAKE_BUILD_TYPE Debug) endif() if (SANITIZER) diff --git a/src/device.c b/src/device.c index 4d5a016..256e98a 100644 --- a/src/device.c +++ b/src/device.c @@ -68,13 +68,13 @@ ex_status ex_device_read_to_buffer(ssize_t *readed, char *buffer, size_t off, goto failure; } - off_t offset = lseek(fd, off, SEEK_SET); - if ((off_t)off < 0) { status = INVALID_OFFSET; goto failure; } + off_t offset = lseek(fd, off, SEEK_SET); + if ((size_t)offset != off) { status = OFFSET_SEEK_FAILED; goto failure; @@ -97,7 +97,7 @@ ex_status ex_device_read_to_buffer(ssize_t *readed, char *buffer, size_t off, error("device is not opened"); break; case INVALID_OFFSET: - error("lseek: underthrow (off > max(int))"); + error("lseek: underthrow (off > max(int)) (%li, %zu)", off, off); break; case OFFSET_SEEK_FAILED: error("lseek: offset=%li, wanted=%lu", offset, off); @@ -122,13 +122,13 @@ ex_status ex_device_write(size_t off, const char *data, size_t amount) { goto failure; } - off_t offset = lseek(fd, off, SEEK_SET); - if ((off_t)off < 0) { status = INVALID_OFFSET; goto failure; } + off_t offset = lseek(fd, off, SEEK_SET); + if ((size_t)offset != off) { status = OFFSET_SEEK_FAILED; goto failure; diff --git a/src/errors.h b/src/errors.h index c161967..90df897 100644 --- a/src/errors.h +++ b/src/errors.h @@ -33,6 +33,7 @@ typedef enum { INODE_LOAD_FAILED, INODE_IS_NOT_UNLINKABLE, INODE_NOT_FOUND, + PARENT_BLOCK_CANNOT_BE_READED, OK } ex_status; diff --git a/src/ex.c b/src/ex.c index e092f42..f00968f 100644 --- a/src/ex.c +++ b/src/ex.c @@ -121,6 +121,8 @@ int ex_getattr(const char *pathname, struct stat *st) { st->st_nlink = inode->nlinks; st->st_size = inode->size; + st->st_blocks = inode->nblocks; + st->st_blksize = EX_BLOCK_SIZE; st->st_mode = inode->mode; st->st_ino = inode->number; diff --git a/src/inode.c b/src/inode.c index 07d7f27..6959c90 100644 --- a/src/inode.c +++ b/src/inode.c @@ -71,6 +71,88 @@ ex_status ex_root_load(struct ex_inode *root) { return status; } +static const size_t blocks_per_block = EX_BLOCK_SIZE / sizeof(size_t); + +ex_status ex_inode_allocate_indirect_block(struct ex_inode *inode, size_t n) { + + debug("alllocating nth block: %zu", n); + + // TODO: add new kind of error + size_t indirect_block_no = n; + + size_t parent_block_no = EX_DIRECT_BLOCKS + indirect_block_no / blocks_per_block; + size_t block_off = indirect_block_no % blocks_per_block; + + // check if parent of the indirect block is allocated + // TODO: move it to the separeate function + if (!inode->blocks[parent_block_no].allocated) { + + debug("allocating parent inode: %zu", parent_block_no); + + struct ex_inode_block block; + + if (ex_super_allocate_data_block(&block) != OK) { + warning("unable to allocate parent block: %zu for inode: (%lu)", + n, inode->number); + return INODE_BLOCK_ALLOCATION_FAILED; + } + + debug("parent inode is at: %zu", block.address); + + inode->blocks[parent_block_no].address = block.address; + inode->blocks[parent_block_no].allocated = 1; + inode->nblocks++; + + // clear the block space + char empty[EX_BLOCK_SIZE] = {0}; + ex_device_write(block.address, (char *)empty, sizeof(empty)); + + ex_inode_flush(inode); + } + + // read parent block + size_t parent_block_address = inode->blocks[parent_block_no].address; + ssize_t readed = 0; + struct ex_data_block parent_block[blocks_per_block]; + memset(parent_block, 0, sizeof(parent_block)); + + if (ex_device_read_to_buffer(&readed, (char *)parent_block, + parent_block_address, sizeof(parent_block)) != OK) { + warning("unable to read parent block at: %zu", parent_block_address); + return PARENT_BLOCK_CANNOT_BE_READED; + } + + // allocate the block and write changes to the disk + struct ex_data_block block = parent_block[block_off]; + + if (block.allocated) { + warning("indirect block: %zu is already allocated", n); + } else { + + debug("allocating new indirect block"); + + struct ex_inode_block block; + if (ex_super_allocate_data_block(&block) != OK) { + warning("unable to allocate new indirect block: %zu", n); + return INODE_BLOCK_ALLOCATION_FAILED; + } + + debug("block %zu in parent %zu is at (%zu)", block_off, + parent_block_no, block.address); + + parent_block[block_off].allocated = 1; + parent_block[block_off].address = block.address; + + ex_device_write(parent_block_address, + (char *)parent_block, + sizeof(parent_block)); + + inode->nblocks++; + ex_inode_flush(inode); + } + return OK; +} + ex_status ex_inode_allocate_blocks(struct ex_inode *inode) { ex_status status = OK; @@ -79,14 +161,23 @@ ex_status ex_inode_allocate_blocks(struct ex_inode *inode) { for (size_t i = 0; i < EX_DIRECT_BLOCKS; i++) { - struct ex_inode_block block; + struct ex_inode_block block_; - if ((status = ex_super_allocate_data_block(&block)) != OK) { + if ((status = ex_super_allocate_data_block(&block_)) != OK) { warning("failing to allocate nth (%lu) block", i); goto done; } - inode->blocks[i] = block.address; + struct ex_data_block *block = &inode->blocks[i]; + + inode->nblocks += 1; + block->address = block_.address; + block->allocated = 1; + } + + for (size_t i = EX_DIRECT_BLOCKS; i < EX_DIRECT_BLOCKS + EX_INDIRECT_BLOCKS; i++) { + inode->blocks[i].allocated = 0; + inode->blocks[i].address = 0; } done: @@ -105,11 +196,11 @@ void ex_inode_deallocate_blocks(struct ex_inode *inode) { for (size_t i = 0; i < EX_DIRECT_BLOCKS; i++) { - if (inode->blocks[i] == EX_BLOCK_INVALID_ADDRESS) { + if (inode->blocks[i].address == EX_BLOCK_INVALID_ADDRESS) { break; } - ex_super_deallocate_block(inode->blocks[i]); + ex_super_deallocate_block(inode->blocks[i].address); } ex_super_deallocate_inode_block(inode->number); @@ -125,6 +216,7 @@ void ex_inode_print(const struct ex_inode *inode) { info("address: %lu", inode->address); info("links: %u", inode->nlinks); info("size: %lu", inode->size); + info("nblocks: %lu", inode->nblocks); info("uid: %u", inode->uid); info("gid: %u", inode->gid); @@ -166,7 +258,9 @@ struct ex_inode *ex_copy_inode(const struct ex_inode *inode) { copy->gid = inode->gid; copy->uid = inode->uid; - for (size_t i = 0; i < EX_DIRECT_BLOCKS; i++) { + copy->nblocks = inode->nblocks; + + for (size_t i = 0; i < EX_DIRECT_BLOCKS + EX_INDIRECT_BLOCKS; i++) { copy->blocks[i] = inode->blocks[i]; } @@ -209,6 +303,8 @@ ex_status ex_inode_create(struct ex_inode *inode, uint16_t mode, gid_t gid, uid_ inode->nlinks = 1; } + inode->nblocks = 0; + if (ex_inode_allocate_blocks(inode) != OK) { goto free_inode_block; } @@ -229,19 +325,21 @@ ex_status ex_inode_create(struct ex_inode *inode, uint16_t mode, gid_t gid, uid_ size_t ex_inode_find_free_entry_address(struct ex_inode *dir) { + debug("trying to find entry address in: %zu", dir->number); + size_t address = 0; foreach_inode_block(dir, block) { foreach_block_entry(block, entry) { - debug("free=%i, magic=%x, blockaddr=%lu", entry.free, entry.magic, - block.address); + //debug("free=%i, magic=%x, blockaddr=%lu", entry.free, entry.magic, + // block.address); if (!entry.free && entry.magic != EX_ENTRY_MAGIC1) { continue; } - debug("finded: block=%ld, i=%ld", block_iterator.block_number, + debug("free finded: block=%ld, i=%ld", block_iterator.block_number, entry_iterator.entry_number); address = block.address + (entry_iterator.entry_number * @@ -252,7 +350,7 @@ size_t ex_inode_find_free_entry_address(struct ex_inode *dir) { } found: - foreach_inode_block_cleanup(dir, block); +// foreach_inode_block_cleanup(dir, block); return address; } @@ -273,6 +371,21 @@ void ex_inode_entry_update(size_t address, const char *name, ex_device_write(address, (void *)&entry, sizeof(entry)); } +size_t next_indirect(struct ex_inode *inode) { + if (inode->nblocks < EX_DIRECT_BLOCKS) { + return 0; + } + + size_t next = inode->nblocks - EX_DIRECT_BLOCKS; + + if (next == 0) { return next; } + + // subtract the amount of parent indirect blocks + size_t parents = next / blocks_per_block + 1; + + return next - parents; +} + struct ex_inode *ex_inode_set(struct ex_inode *dir, const char *name, struct ex_inode *inode) { @@ -280,8 +393,20 @@ struct ex_inode *ex_inode_set(struct ex_inode *dir, const char *name, size_t entry_address = ex_inode_find_free_entry_address(dir); if (!entry_address) { - info("unable to find space for inode in dirinode"); - return NULL; + + info("unable to find space for inode in dirinode: %zu", dir->number); + + if (ex_inode_allocate_indirect_block(dir, next_indirect(dir)) != OK) { + return NULL; + } + + entry_address = ex_inode_find_free_entry_address(dir); + + if (!entry_address) { + warning("unable to find free space after relocation"); + return NULL; + } + } ex_inode_entry_update(entry_address, name, inode->address, 0); @@ -468,6 +593,8 @@ size_t ex_inode_find_entry_address(struct ex_inode *dir, const char *name) { } not_found: + + found: foreach_inode_block_cleanup(dir, block); @@ -521,6 +648,7 @@ ex_status ex_inode_unlink(struct ex_inode *dir, const char *name) { } entry->free = 1; + entry->name[0] = '-'; ex_inode_flush(&inode); ex_dir_entry_flush(entry_address, entry); @@ -590,6 +718,9 @@ ssize_t ex_inode_write(struct ex_inode *ino, size_t off, const char *data, size_t start_block_idx = off / EX_BLOCK_SIZE; size_t start_block_off = off % EX_BLOCK_SIZE; + info("start_block=%zu, start_block_off=%zu", start_block_idx, start_block_off); + info("max_blocks=%zu", ex_inode_max_blocks()); + if (start_block_idx >= ex_inode_max_blocks() || (start_block_off + amount / EX_BLOCK_SIZE) >= ex_inode_max_blocks()) { return -1; @@ -599,7 +730,15 @@ ssize_t ex_inode_write(struct ex_inode *ino, size_t off, const char *data, ino->size += (off + amount) - ino->size; } - block_address addr = ino->blocks[start_block_idx]; + // TODO + block_address addr = ino->blocks[start_block_idx].address; + char allocated = ino->blocks[start_block_idx].allocated; + + if (!allocated) { + warning("start block (%zu) is not allocated", start_block_idx); + } + + debug("writing to %zu", addr); ex_device_write(ino->address, (void *)ino, sizeof(struct ex_inode)); ex_device_write(addr + start_block_off, data, amount); @@ -617,9 +756,9 @@ ssize_t ex_inode_read(struct ex_inode *ino, size_t off, char *buffer, return 0; } - size_t offset = ino->blocks[start_block_idx] + start_block_off; + size_t offset = ino->blocks[start_block_idx].address + start_block_off; ssize_t readed = 0; - + // XXX: check if block is allocated // XXX: ignore status for now (void)ex_device_read_to_buffer(&readed, buffer, offset, amount); @@ -650,11 +789,24 @@ int ex_inode_rename(struct ex_inode *from_inode, struct ex_inode *to_inode, to_entry_address = ex_inode_find_free_entry_address(to_inode); + // XXX: use function for this, change return values if (!to_entry_address) { - debug("unable to find a free entry address, inode: %ld", - to_inode->number); + + info("unable to find space for inode in: %zu", to_inode->number); + + if (ex_inode_allocate_indirect_block(to_inode, to_inode->nblocks) != OK) { + return -ENOSPC; + } + + to_entry_address = ex_inode_find_free_entry_address(to_inode); + + if (!to_entry_address) { + warning("unable to find free space after relocation"); + } + return -ENOSPC; } + } debug("from/to: %lu/%lu", from_entry_address, to_entry_address); @@ -669,6 +821,78 @@ int ex_inode_rename(struct ex_inode *from_inode, struct ex_inode *to_inode, return 0; } +static inline int ex_indirect_block_is_allocated(struct ex_inode *i, size_t n) { + return i->blocks[n + EX_DIRECT_BLOCKS].address; +} + +static inline int ex_indirect_block_out_of_range(size_t n) { + return n > EX_INDIRECT_BLOCKS; +} + +static inline int ex_indirect_block_should_be_loaded(struct ex_block_iterator *it, + size_t indirect_block_no) { + return it->indirect_block_no != indirect_block_no || !it->indirect.data; +} + +struct ex_inode_block ex_inode_block_iterate_indirect(struct ex_inode *inode, + struct ex_block_iterator *it) { + assert(it->block_number >= EX_DIRECT_BLOCKS); + + size_t __ind = (it->block_number - EX_DIRECT_BLOCKS); + + size_t indirect_block_no = __ind / blocks_per_block; + size_t block_idx = __ind % blocks_per_block; + + debug("ibno: %zu, bi: %zu", indirect_block_no, block_idx); + + if (ex_indirect_block_out_of_range(indirect_block_no) || + !ex_indirect_block_is_allocated(inode, indirect_block_no)) { + + debug("not allocated or out of range"); + + it->last_block.address = EX_BLOCK_INVALID_ADDRESS; + it->last_block.data = NULL; + it->last_block.id = EX_BLOCK_INVALID_ID; + + goto done; + } + + if (ex_indirect_block_should_be_loaded(it, indirect_block_no)) { + size_t indirect_block_address = inode->blocks[indirect_block_no + EX_DIRECT_BLOCKS].address; + + debug("loading indirect block: %zu at %zu", indirect_block_no, indirect_block_address); + ssize_t readed = 0; + (void)ex_device_read_to_buffer(&readed, it->indirect_buffer, + indirect_block_address, EX_BLOCK_SIZE); + it->indirect.data = it->indirect_buffer; + } + + // XXX: this is the end, my only friend, the end + struct ex_data_block block = ((struct ex_data_block *)it->indirect.data)[block_idx]; + + debug("ba: %zu, aloc: %i", block.address, (int)block.allocated); + + // block in the indirect block is not allocated + if (!block.allocated) { + it->last_block.address = EX_BLOCK_INVALID_ADDRESS; + it->last_block.data = NULL; + it->last_block.id = EX_BLOCK_INVALID_ID; + + goto done; + } + + // read the blocks data + ssize_t readed = 0; + (void)ex_device_read_to_buffer(&readed, it->buffer, block.address, EX_BLOCK_SIZE); + + it->last_block.address = block.address; + it->last_block.id = it->block_number; + it->last_block.data = it->buffer; + +done: + return it->last_block; +} + struct ex_inode_block ex_inode_block_iterate(struct ex_inode *inode, struct ex_block_iterator *it) { @@ -682,20 +906,19 @@ struct ex_inode_block ex_inode_block_iterate(struct ex_inode *inode, .address = EX_BLOCK_INVALID_ADDRESS}; if (it->block_number >= EX_DIRECT_BLOCKS) { - goto done; + debug("iterating block: %zu", it->block_number); + return ex_inode_block_iterate_indirect(inode, it); } - block.address = inode->blocks[it->block_number]; + block.address = inode->blocks[it->block_number].address; block.data = it->buffer; + block.id = it->block_number; - // XXX: add buffer into ex_block_iterator and use ex_device_read_to_buffer - // handle read error - ssize_t readed = 0; // XXX: handle read error + ssize_t readed = 0; (void)ex_device_read_to_buffer(&readed, it->buffer, block.address, EX_BLOCK_SIZE); -done: it->last_block = block; return block; } @@ -725,7 +948,7 @@ struct ex_dir_entry ex_inode_entry_iterate(struct ex_inode_block block, return it->last_entry; } -size_t ex_inode_max_blocks(void) { return EX_DIRECT_BLOCKS; } +size_t ex_inode_max_blocks(void) { return EX_DIRECT_BLOCKS + EX_INDIRECT_BLOCKS * blocks_per_block; } int ex_inode_has_perm(struct ex_inode *ino, ex_permission perm, gid_t gid, uid_t uid) { @@ -748,3 +971,4 @@ int ex_inode_has_perm(struct ex_inode *ino, ex_permission perm, gid_t gid, uid_t return 0; } + diff --git a/src/inode.h b/src/inode.h index cba267b..33199fe 100644 --- a/src/inode.h +++ b/src/inode.h @@ -13,12 +13,18 @@ #include #include -#define EX_DIRECT_BLOCKS 256 +#define EX_DIRECT_BLOCKS 64 +#define EX_INDIRECT_BLOCKS 8 extern const uint16_t EX_INODE_MAGIC1; extern const uint8_t EX_DIR_MAGIC1; extern const uint8_t EX_ENTRY_MAGIC1; +struct ex_data_block { + uint64_t address: 63; + uint64_t allocated: 1; +}; + struct ex_inode { // number of inode, it corresponds with allocated block number // e.g. number==0 means that inode has allocated first inode @@ -44,13 +50,16 @@ struct ex_inode { // number of links uint16_t nlinks; + // number of allocated blocks + size_t nblocks; + // size of file when inode is file // size of file metadata (struct ex_inode) if inode is directory size_t size; // if an inode is file content is saved here directly in these blocks // if an inode is directory ex_dir_entries are saved in these blocks - block_address blocks[EX_DIRECT_BLOCKS]; + struct ex_data_block blocks[EX_DIRECT_BLOCKS + EX_INDIRECT_BLOCKS]; }; struct ex_dir_entry { @@ -105,8 +114,13 @@ int ex_inode_has_perm(struct ex_inode *ino, ex_permission perm, gid_t gid, uid_t struct ex_block_iterator { struct ex_inode_block last_block; + struct ex_inode_block indirect; + size_t block_number; + size_t indirect_block_no; + char buffer[EX_BLOCK_SIZE]; + char indirect_buffer[EX_BLOCK_SIZE]; }; struct ex_entry_iterator { diff --git a/src/super.h b/src/super.h index f73c658..8986ce5 100644 --- a/src/super.h +++ b/src/super.h @@ -23,6 +23,7 @@ typedef size_t inode_address; typedef size_t block_address; +// XXX: rename this, it's used only by block iterator struct ex_inode_block { // position in super block inodes block bitmap size_t id; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bfaa0c3..4795ca9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,6 +20,8 @@ set(TEST_SOURCES test_write_max_size.c test_chmod.c test_chown.c + test_stat_block_number.c + test_dir_block_reallocation.c ) find_package(PkgConfig REQUIRED) diff --git a/test/test_dir_block_reallocation.c b/test/test_dir_block_reallocation.c new file mode 100644 index 0000000..6e97ec6 --- /dev/null +++ b/test/test_dir_block_reallocation.c @@ -0,0 +1,79 @@ +#include "../src/ex.h" +#include "../src/mkfs.h" +#include +#include +#include +#include +#include +#include + +void test_dir_block_reallocation(void) { + + // create new device, maximum number of inodes must be greater + // than EX_DIRECT_BLOCKS * (EX_BLOCK_SIZE / sizeof(struct ex_dir_entry)) + // because we want to check that directory is able to use indirect + // blocks + unlink("exdev"); + ex_set_log_level(debug); + + const size_t entry_per_block = EX_BLOCK_SIZE / sizeof(struct ex_dir_entry); + const size_t ninodes = 2 * EX_DIRECT_BLOCKS * entry_per_block; + + struct ex_mkfs_params params; + memset(¶ms, '\0', sizeof(params)); + + params.number_of_inodes = ninodes + 8; // space for . and .., we cannot use + // 2 because number must be divisible + // by 8 + params.device = "exdev"; + params.create = 1; + + ex_mkfs_check_params(¶ms); + + int rv = ex_mkfs(¶ms); + g_assert(!rv); + + // create new directory + rv = ex_mkdir("/dir", S_IRWXU | S_IFDIR, getgid(), getuid()); + g_assert(!rv); + + char buffer[32]; + + // check that we can create files in a directory + for (size_t i = 0; i < ninodes; i++) { + + snprintf(buffer, sizeof(buffer), "/dir/file%zu", i); + + rv = ex_create(buffer, S_IRWXU, getgid(), getuid()); + g_assert(!rv); + } + + // check that we can query files attributes + for (size_t i = 0; i < ninodes; i++) { + + snprintf(buffer, sizeof(buffer), "/dir/file%zu", i); + + struct stat st; + rv = ex_getattr(buffer, &st); + g_assert(!rv); + } + + // check that we cannot remove the populated directory + rv = ex_rmdir("/dir"); + g_assert(rv); + + // check that we are able to delete all files + for (size_t i = 0; i < ninodes; i++) { + + snprintf(buffer, sizeof(buffer), "/dir/file%zu", i); + + rv = ex_unlink(buffer); + g_assert(!rv); + } + + // check that we can remove the populated directory + rv = ex_rmdir("/dir"); + g_assert(!rv); + + ex_deinit(); +} diff --git a/test/test_main.c b/test/test_main.c index f796643..a8f44b8 100644 --- a/test/test_main.c +++ b/test/test_main.c @@ -21,6 +21,8 @@ void test_can_create_maximum_inodes(void); void test_inode_link(void); void test_chmod(void); void test_chown(void); +void test_stat_block_number(void); +void test_dir_block_reallocation(void); int main(int argc, char **argv) { ex_set_log_level(fatal); @@ -52,6 +54,9 @@ int main(int argc, char **argv) { g_test_add_func("/exfuse/test_inode_link", test_inode_link); g_test_add_func("/exfuse/test_chmod", test_chmod); g_test_add_func("/exfuse/test_chown", test_chown); + g_test_add_func("/exfuse/test_stat_block_number", test_stat_block_number); + g_test_add_func("/exfuse/test_dir_block_reallocation", + test_dir_block_reallocation); return g_test_run(); } diff --git a/test/test_mkfs_device_size.c b/test/test_mkfs_device_size.c index 5917d72..c7f3fb1 100644 --- a/test/test_mkfs_device_size.c +++ b/test/test_mkfs_device_size.c @@ -23,7 +23,10 @@ void test_mkfs_device_size(void) { // the size of the super block an inode bitmap and a data bitmap rounded // to block size - size_t expected_device_size = 3 * EX_BLOCK_SIZE; + size_t expected_device_size = round_block(sizeof(struct ex_super_block)); + expected_device_size += round_block(super_block->bitmap.size); + expected_device_size += round_block(super_block->inode_bitmap.size); + // size for `ninodes` inodes expected_device_size += EX_BLOCK_SIZE * ninodes; // number of data blocks for `ninodes` inodes diff --git a/test/test_stat_block_number.c b/test/test_stat_block_number.c new file mode 100644 index 0000000..f5e5e14 --- /dev/null +++ b/test/test_stat_block_number.c @@ -0,0 +1,29 @@ +#include "../src/ex.h" +#include "../src/mkfs.h" +#include +#include +#include +#include +#include + +void test_stat_block_number(void) { + // create new device + unlink(EX_DEVICE); + ex_mkfs_test_init(); + + // create new file + int rv = ex_create("/fname", S_IRWXU, getgid(), getuid()); + g_assert(!rv); + + struct stat st; + + rv = ex_getattr("/fname", &st); + g_assert(!rv); + + // current file should be empty, but because we do preallocate + // all direct blocks nblocks should be EX_DIRECT_BLOCKS + g_assert_cmpint(st.st_blocks, ==, EX_DIRECT_BLOCKS); + + // TODO: write to indirect blocks and check allocated blocks + ex_deinit(); +} diff --git a/test/test_write_max_size.c b/test/test_write_max_size.c index 2c549a4..496c540 100644 --- a/test/test_write_max_size.c +++ b/test/test_write_max_size.c @@ -9,12 +9,15 @@ void test_write_max_size(void) { // create new device unlink(EX_DEVICE); + ex_mkfs_test_init(); - size_t max_size = EX_DIRECT_BLOCKS * EX_BLOCK_SIZE - 1; - char data[max_size]; + size_t max_size = ex_inode_max_blocks() * EX_BLOCK_SIZE - 1; + // +1 because of EFBIG + char *data = malloc(max_size + 1); + g_assert(data); - memset(data, 'a', sizeof(data)); + memset(data, 'a', max_size + 1); // create new file int rv = ex_create("/file", S_IRWXU, getgid(), getuid());