diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c --- a/usr.sbin/makefs/ffs.c +++ b/usr.sbin/makefs/ffs.c @@ -591,6 +591,51 @@ return (fsopts->fd); } +static void +ffs_add_size(fsinfo_t *fsopts, size_t file_len) +{ + ffs_opt_t *ffs_opts = fsopts->fs_specific; + size_t indir_blocks, fs_inopb; + int indir_level; + + if (file_len < ffs_opts->fsize + + (UFS_NDADDR - 1) * (size_t)ffs_opts->bsize) { + fsopts->size += roundup(file_len, ffs_opts->fsize); + return; + } + + if (file_len <= UFS_NDADDR * (size_t)ffs_opts->bsize) { + fsopts->size += roundup(file_len, ffs_opts->bsize); + return; + } + + /* We do not fit into direct blocks, count indirect blocks */ + indir_blocks = howmany(file_len - UFS_NDADDR * (size_t)ffs_opts->bsize, + ffs_opts->bsize); + fs_inopb = (size_t)ffs_opts->bsize / ((ffs_opts->version <= 1) ? + DINODE1_SIZE : DINODE2_SIZE); + + indir_level = 0; + while (indir_blocks > 1 && indir_level < 3) { + /* one indirect block is stored in di_ib[] */ + indir_blocks = howmany(indir_blocks, fs_inopb) - 1; + fsopts->size += ffs_opts->bsize * indir_blocks; + indir_level++; + } + + /* Top-level indirection block */ + assert(indir_blocks == 1); + fsopts->size += ffs_opts->bsize; + if (debug & DEBUG_FS_SIZE_DIR_NODE) { + printf("ffs_size_dir: size %lld, using %d levels of indirect " + "blocks\n", (long long)file_len, indir_level); + } + /* + * If the file is big enough to use indirect blocks, + * we allocate bsize block for trailing data. + */ + fsopts->size += roundup(file_len, ffs_opts->bsize); +} static void ffs_size_dir(fsnode *root, fsinfo_t *fsopts) @@ -622,20 +667,6 @@ e, tmpdir.d_namlen, this, curdirsize); \ } while (0); -#define ADDSIZE(x) do { \ - if ((size_t)(x) < UFS_NDADDR * (size_t)ffs_opts->bsize) { \ - fsopts->size += roundup((x), ffs_opts->fsize); \ - } else { \ - /* Count space consumed by indirecttion blocks. */ \ - fsopts->size += ffs_opts->bsize * \ - (howmany((x), UFS_NDADDR * ffs_opts->bsize) - 1); \ - /* \ - * If the file is big enough to use indirect blocks, \ - * we allocate bsize block for trailing data. \ - */ \ - fsopts->size += roundup((x), ffs_opts->bsize); \ - } \ -} while (0); curdirsize = 0; for (node = root; node != NULL; node = node->next) { @@ -652,7 +683,7 @@ (long long)node->inode->st.st_size); fsopts->inodes++; if (node->type == S_IFREG) - ADDSIZE(node->inode->st.st_size); + ffs_add_size(fsopts, node->inode->st.st_size); if (node->type == S_IFLNK) { size_t slen; @@ -660,13 +691,13 @@ if (slen >= (ffs_opts->version == 1 ? UFS1_MAXSYMLINKLEN : UFS2_MAXSYMLINKLEN)) - ADDSIZE(slen); + ffs_add_size(fsopts, slen); } } if (node->type == S_IFDIR) ffs_size_dir(node->child, fsopts); } - ADDSIZE(curdirsize); + ffs_add_size(fsopts, curdirsize); if (debug & DEBUG_FS_SIZE_DIR) printf("ffs_size_dir: exit: size %lld inodes %lld\n",