diff --git a/NEWS b/NEWS index 00d6fbbc..cbbe04a6 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ xbps-0.42 (???): + * xbps-create(8): fixed issue #64 "xbps-create(8) incorrect installed-size with hardlinks". + https://github.com/voidlinux/xbps/issues/64 + * Added a new configuration keyword "bestmatching", which expects "true" or "false" and disabled by default. If enabled the pkg with the greatest version available in all registered repositories will be choosen, rather than the first package diff --git a/bin/xbps-create/main.c b/bin/xbps-create/main.c index 74963acb..9e655990 100644 --- a/bin/xbps-create/main.c +++ b/bin/xbps-create/main.c @@ -58,6 +58,7 @@ struct xentry { TAILQ_ENTRY(xentry) entries; char *file, *type, *target, *hash; + ino_t inode; }; static TAILQ_HEAD(xentry_head, xentry) xentry_list = @@ -315,8 +316,24 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _u assert(xe->target); free(buf); } else if (type == FTW_F) { + struct xentry *xep; + bool hlink = false; + /* + * Regular files. First find out if it's a hardlink: + * - st_nlink > 1 + * and then search for a stored file matching its inode. + */ + TAILQ_FOREACH(xep, &xentry_list, entries) { + if (sb->st_nlink > 1 && xep->inode == sb->st_ino) { + /* matched */ + hlink = true; + break; + } + } + if (!hlink) + instsize += sb->st_size; + /* - * Regular files. * Find out if it's a configuration file or not * and calculate sha256 hash. */ @@ -329,8 +346,7 @@ ftw_cb(const char *fpath, const struct stat *sb, int type, struct FTW *ftwbuf _u if ((xe->hash = xbps_file_hash(fpath)) == NULL) die("failed to process hash for %s:", fpath); - if (sb->st_nlink <= 1) - instsize += sb->st_size; + xe->inode = sb->st_ino; } else if (type == FTW_D || type == FTW_DP) { /* directory */ diff --git a/tests/xbps/Kyuafile b/tests/xbps/Kyuafile index c98aa3f6..e034f94f 100644 --- a/tests/xbps/Kyuafile +++ b/tests/xbps/Kyuafile @@ -3,7 +3,8 @@ syntax("kyuafile", 1) test_suite("xbps") include('libxbps/Kyuafile') +include('xbps-checkvers/Kyuafile') +include('xbps-create/Kyuafile') include('xbps-install/Kyuafile') include('xbps-query/Kyuafile') include('xbps-rindex/Kyuafile') -include('xbps-checkvers/Kyuafile') diff --git a/tests/xbps/Makefile b/tests/xbps/Makefile index 14d5e96f..d982763e 100644 --- a/tests/xbps/Makefile +++ b/tests/xbps/Makefile @@ -1,5 +1,5 @@ -include ../../config.mk -SUBDIRS = common libxbps xbps-install xbps-query xbps-rindex xbps-checkvers +SUBDIRS = common libxbps xbps-checkvers xbps-create xbps-install xbps-query xbps-rindex include ../../mk/subdir.mk diff --git a/tests/xbps/xbps-create/Kyuafile b/tests/xbps/xbps-create/Kyuafile new file mode 100644 index 00000000..7f4e52c4 --- /dev/null +++ b/tests/xbps/xbps-create/Kyuafile @@ -0,0 +1,4 @@ +syntax("kyuafile", 1) + +test_suite("xbps-create") +atf_test_program{name="basic_test"} diff --git a/tests/xbps/xbps-create/Makefile b/tests/xbps/xbps-create/Makefile new file mode 100644 index 00000000..a989aca4 --- /dev/null +++ b/tests/xbps/xbps-create/Makefile @@ -0,0 +1,8 @@ +TOPDIR = ../../.. +-include $(TOPDIR)/config.mk + +TESTSHELL = basic_test +TESTSSUBDIR = xbps/xbps-create +EXTRA_FILES = Kyuafile + +include $(TOPDIR)/mk/test.mk diff --git a/tests/xbps/xbps-create/basic_test.sh b/tests/xbps/xbps-create/basic_test.sh new file mode 100644 index 00000000..67690476 --- /dev/null +++ b/tests/xbps/xbps-create/basic_test.sh @@ -0,0 +1,35 @@ +#! /usr/bin/env atf-sh +# Test that xbps-create(8) works as expected. + +atf_test_case hardlinks_size + +hardlinks_size_head() { + atf_set "descr" "xbps-create(8): installed-size behaviour with hardlinks" +} + +hardlinks_size_body() { + mkdir -p repo pkg_A + echo 123456789 > pkg_A/file00 + ln pkg_A/file00 pkg_A/file01 + ln pkg_A/file00 pkg_A/file02 + ln pkg_A/file00 pkg_A/file03 + cd repo + xbps-create -A noarch -n foo-1.0_1 -s "foo pkg" ../pkg_A + atf_check_equal $? 0 + cd .. + xbps-rindex -d -a repo/*.xbps + atf_check_equal $? 0 + result="$(xbps-query -r root -C empty.conf --repository=$PWD/repo -p installed_size foo)" + expected="10B" + rv=0 + if [ "$result" != "$expected" ]; then + echo "result: $result" + echo "expected: $expected" + rv=1 + fi + atf_check_equal $rv 0 +} + +atf_init_test_cases() { + atf_add_test_case hardlinks_size +}