From aae43d362fa39e3d1b9ea5865f0a5df920e93a33 Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Wed, 4 Jan 2017 11:27:19 +0300 Subject: [PATCH] (vfs_adjust_stat): new VFS API, currently used to calculate st_blocks. Signed-off-by: Andrew Borodin --- lib/vfs/direntry.c | 39 +++++- lib/vfs/parse_ls_vga.c | 4 +- lib/vfs/vfs.h | 2 + src/vfs/extfs/extfs.c | 4 +- src/vfs/fish/fish.c | 1 + src/vfs/ftpfs/ftpfs.c | 1 + src/vfs/sftpfs/internal.c | 5 +- src/vfs/tar/tar.c | 1 + tests/lib/vfs/Makefile.am | 4 + tests/lib/vfs/vfs_adjust_stat.c | 213 ++++++++++++++++++++++++++++++++ 10 files changed, 261 insertions(+), 13 deletions(-) create mode 100644 tests/lib/vfs/vfs_adjust_stat.c diff --git a/lib/vfs/direntry.c b/lib/vfs/direntry.c index 4c2ad4e76..f4f281a82 100644 --- a/lib/vfs/direntry.c +++ b/lib/vfs/direntry.c @@ -974,16 +974,49 @@ vfs_s_default_stat (struct vfs_class *me, mode_t mode) st.st_gid = getgid (); #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE st.st_blksize = 512; -#endif -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - st.st_blocks = 0; #endif st.st_size = 0; st.st_mtime = st.st_atime = st.st_ctime = time (NULL); + vfs_adjust_stat (&st); + return &st; } +/* --------------------------------------------------------------------------------------------- */ +/** + * Calculate number of st_blocks using st_size and st_blksize. + * In according to stat(2), st_blocks is the size in 512-byte units. + * + * @param s stat info + */ + +void +vfs_adjust_stat (struct stat *s) +{ +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + if (s->st_size == 0) + s->st_blocks = 0; + else + { +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + blkcnt_t ioblocks; + blksize_t ioblock_size; + + /* 1. Calculate how many IO blocks are occupied */ + ioblocks = 1 + (s->st_size - 1) / s->st_blksize; + /* 2. Calculate size of st_blksize in 512-byte units */ + ioblock_size = 1 + (s->st_blksize - 1) / 512; + /* 3. Calculate number of blocks */ + s->st_blocks = ioblocks * ioblock_size; +#else + /* Let IO block size is 512 bytes */ + s->st_blocks = 1 + (s->st_size - 1) / 512; +#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + } +#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */ +} + /* --------------------------------------------------------------------------------------------- */ struct vfs_s_entry * diff --git a/lib/vfs/parse_ls_vga.c b/lib/vfs/parse_ls_vga.c index 33c6d411d..2fda951ff 100644 --- a/lib/vfs/parse_ls_vga.c +++ b/lib/vfs/parse_ls_vga.c @@ -813,9 +813,7 @@ vfs_parse_ls_lga (const char *p, struct stat * s, char **filename, char **linkna #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE s->st_blksize = 512; #endif -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - s->st_blocks = (s->st_size + 511) / 512; -#endif + vfs_adjust_stat (s); if (num_spaces != NULL) { diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index 5cfb6ec8f..2510195a6 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -230,6 +230,8 @@ int vfs_s_stat (const vfs_path_t * vpath, struct stat *buf); int vfs_s_lstat (const vfs_path_t * vpath, struct stat *buf); int vfs_s_fstat (void *fh, struct stat *buf); +void vfs_adjust_stat (struct stat *s); + vfsid vfs_getid (const vfs_path_t * vpath); void vfs_init (void); diff --git a/src/vfs/extfs/extfs.c b/src/vfs/extfs/extfs.c index fb71cbe5d..dc739742a 100644 --- a/src/vfs/extfs/extfs.c +++ b/src/vfs/extfs/extfs.c @@ -1095,9 +1095,7 @@ extfs_stat_move (struct stat *buf, const struct inode *inode) #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE buf->st_blksize = RECORDSIZE; #endif -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - buf->st_blocks = (inode->size + RECORDSIZE - 1) / RECORDSIZE; -#endif + vfs_adjust_stat (buf); buf->st_atime = inode->atime; buf->st_mtime = inode->mtime; buf->st_ctime = inode->ctime; diff --git a/src/vfs/fish/fish.c b/src/vfs/fish/fish.c index d617f9c5a..1ae9dba88 100644 --- a/src/vfs/fish/fish.c +++ b/src/vfs/fish/fish.c @@ -179,6 +179,7 @@ fish_default_stat (struct vfs_class *me) s = vfs_s_default_stat (me, S_IFDIR | 0755); fish_set_blksize (s); + vfs_adjust_stat (s); return s; } diff --git a/src/vfs/ftpfs/ftpfs.c b/src/vfs/ftpfs/ftpfs.c index 941e72f19..9a21a4041 100644 --- a/src/vfs/ftpfs/ftpfs.c +++ b/src/vfs/ftpfs/ftpfs.c @@ -289,6 +289,7 @@ ftpfs_default_stat (struct vfs_class *me) s = vfs_s_default_stat (me, S_IFDIR | 0755); ftpfs_set_blksize (s); + vfs_adjust_stat (s); return s; } diff --git a/src/vfs/sftpfs/internal.c b/src/vfs/sftpfs/internal.c index ebb300457..392589596 100644 --- a/src/vfs/sftpfs/internal.c +++ b/src/vfs/sftpfs/internal.c @@ -131,11 +131,8 @@ sftpfs_blksize (struct stat *s) { #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE s->st_blksize = LIBSSH2_CHANNEL_WINDOW_DEFAULT; /* FIXME */ -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - /* In according to stat(2), this is the size in 512-byte units */ - s->st_blocks = 1 + ((s->st_size - 1) / 512); -#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */ #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + vfs_adjust_stat (s); } /* --------------------------------------------------------------------------------------------- */ diff --git a/src/vfs/tar/tar.c b/src/vfs/tar/tar.c index efbecf357..04e393b5d 100644 --- a/src/vfs/tar/tar.c +++ b/src/vfs/tar/tar.c @@ -449,6 +449,7 @@ tar_fill_stat (struct vfs_s_super *archive, struct stat *st, union record *heade #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE st->st_blksize = 8 * 1024; /* FIXME */ #endif + vfs_adjust_stat (st); } /* --------------------------------------------------------------------------------------------- */ diff --git a/tests/lib/vfs/Makefile.am b/tests/lib/vfs/Makefile.am index c6e133ce5..ebb531ac7 100644 --- a/tests/lib/vfs/Makefile.am +++ b/tests/lib/vfs/Makefile.am @@ -23,6 +23,7 @@ TESTS = \ path_serialize \ relative_cd \ tempdir \ + vfs_adjust_stat \ vfs_parse_ls_lga \ vfs_path_from_str_flags \ vfs_path_string_convert \ @@ -65,6 +66,9 @@ relative_cd_SOURCES = \ tempdir_SOURCES = \ tempdir.c +vfs_adjust_stat_SOURCES = \ + vfs_adjust_stat.c + vfs_get_encoding_SOURCES = \ vfs_get_encoding.c diff --git a/tests/lib/vfs/vfs_adjust_stat.c b/tests/lib/vfs/vfs_adjust_stat.c new file mode 100644 index 000000000..ea8fda69f --- /dev/null +++ b/tests/lib/vfs/vfs_adjust_stat.c @@ -0,0 +1,213 @@ +/* + lib/vfs - test vfs_adjust_stat() functionality + + Copyright (C) 2017 + Free Software Foundation, Inc. + + Written by: + Andrew Borodin , 2017 + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#define TEST_SUITE_NAME "/lib/vfs" + +#include "tests/mctest.h" + +#include + +/* --------------------------------------------------------------------------------------------- */ + +/* @DataSource("test_test_vfs_adjust_stat_ds") */ +/* *INDENT-OFF* */ +static const struct test_vfs_adjust_stat_ds +{ + struct stat etalon_stat; +} test_vfs_adjust_stat_ds[] = +{ + /* 0 */ + { + .etalon_stat = + { + .st_size = 0, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 512, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 0 +#endif + } + }, + /* 1 */ + { + .etalon_stat = + { + .st_size = 4096, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 512, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 8 +#endif + } + }, + /* 2 */ + { + .etalon_stat = + { + .st_size = 4096, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 1024, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 8 +#endif + } + }, + /* 3 */ + { + .etalon_stat = + { + .st_size = 4096, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 2048, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 8 +#endif + } + }, + /* 4 */ + { + .etalon_stat = + { + .st_size = 4096, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 4096, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 8 +#endif + } + }, + /* 5 */ + { + .etalon_stat = + { + .st_size = 5000, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 512, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 10 +#endif + } + }, + /* 6 */ + { + .etalon_stat = + { + .st_size = 5000, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 1024, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 10 +#endif + } + }, + /* 7 */ + { + .etalon_stat = + { + .st_size = 5000, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 2048, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 12 +#endif + } + }, + /* 8 */ + { + .etalon_stat = + { + .st_size = 5000, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + .st_blksize = 4096, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + .st_blocks = 16 +#endif + } + } +}; +/* *INDENT-ON* */ + +/* --------------------------------------------------------------------------------------------- */ + +/* @Test(dataSource = "test_vfs_adjust_stat_ds") */ +/* *INDENT-OFF* */ +START_PARAMETRIZED_TEST (test_vfs_adjust_stat, test_vfs_adjust_stat_ds) +/* *INDENT-ON* */ +{ +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + /* given */ + struct stat expected_stat; + + expected_stat.st_size = data->etalon_stat.st_size; +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + expected_stat.st_blksize = data->etalon_stat.st_blksize; +#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + /* when */ + vfs_adjust_stat (&expected_stat); + + /* then */ + mctest_assert_int_eq (data->etalon_stat.st_blocks, expected_stat.st_blocks); +#else + mctest_assert_int_eq (0, 0); +#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */ +} +/* *INDENT-OFF* */ +END_PARAMETRIZED_TEST +/* *INDENT-ON* */ + +/* --------------------------------------------------------------------------------------------- */ + +int +main (void) +{ + int number_failed; + + Suite *s = suite_create (TEST_SUITE_NAME); + TCase *tc_core = tcase_create ("Core"); + SRunner *sr; + + /* Add new tests here: *************** */ + mctest_add_parameterized_test (tc_core, test_vfs_adjust_stat, test_vfs_adjust_stat_ds); + /* *********************************** */ + + suite_add_tcase (s, tc_core); + sr = srunner_create (s); + srunner_set_log (sr, "vfs_adjust_stat.log"); + srunner_run_all (sr, CK_ENV); + number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* --------------------------------------------------------------------------------------------- */