ソースを参照

libdpkg: Add new tar extractor test cases

Test the different supported tar formats, and verify that we can parse
them correctly.
Guillem Jover 11 年 前
コミット
f71e02c8e9
共有5 個のファイルを変更した288 個の追加3 個の削除を含む
  1. 1 0
      debian/changelog
  2. 2 0
      lib/dpkg/test/.gitignore
  3. 19 3
      lib/dpkg/test/Makefile.am
  4. 141 0
      lib/dpkg/test/t-tar.t
  5. 125 0
      lib/dpkg/test/t-tarextract.c

+ 1 - 0
debian/changelog

@@ -104,6 +104,7 @@ dpkg (1.17.14) UNRELEASED; urgency=low
   * Test suite:
     - Do not leave temporary files behind on failure or when interrupted.
     - Add basic unit tests for the FNV hashing function.
+    - Add unit tests for the libdpkg tar extractor.
   * Add --build and --extract command aliases to dpkg-source.
   * Print file or package names instead of pointers in dpkg debug output,
     to make it more meaningful and reproducible.

+ 2 - 0
lib/dpkg/test/.gitignore

@@ -13,6 +13,8 @@ t-pkg-queue
 t-progname
 t-string
 t-subproc
+t-tar/
+t-tarextract
 t-test
 t-test-skip
 t-trigger

+ 19 - 3
lib/dpkg/test/Makefile.am

@@ -9,9 +9,13 @@ LDADD = \
 	$(top_builddir)/lib/dpkg/libdpkg.la \
 	$(LIBINTL)
 
+EXTRA_DIST = \
+	$(test_scripts) \
+	$(nil)
+
 
 # The tests are sorted in order of increasing complexity.
-check_PROGRAMS = \
+test_programs = \
 	t-test \
 	t-test-skip \
 	t-macros \
@@ -31,8 +35,20 @@ check_PROGRAMS = \
 	t-pkg-list \
 	t-pkg-queue \
 	t-trigger \
-	t-mod-db
+	t-mod-db \
+	$(nil)
+
+test_scripts = \
+	t-tar.t \
+	$(nil)
 
-test_programs = $(check_PROGRAMS)
+check_PROGRAMS = \
+	$(test_programs) \
+	t-tarextract \
+	$(nil)
+
+test_tmpdir = t.tmp
 
 include $(top_srcdir)/check.am
+
+clean-local: check-clean

+ 141 - 0
lib/dpkg/test/t-tar.t

@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+#
+# Copyright © 2014 Guillem Jover <guillem@debian.org>
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 <https://www.gnu.org/licenses/>.
+
+use Test::More tests => 12;
+use Cwd;
+use File::Path qw(make_path remove_tree);
+use File::Temp qw(tempdir);
+use File::Spec;
+use File::Find;
+use POSIX qw(mkfifo);
+
+use Dpkg::IPC;
+
+use strict;
+use warnings;
+
+my $srcdir = $ENV{srcdir} || '.';
+my $builddir = $ENV{builddir} || '.';
+my $tmpdir = 't.tmp/t-tar';
+
+sub create {
+    my ($pathname) = @_;
+
+    open my $fh, '>>', $pathname or die "cannot touch $pathname: $!";
+    close $fh;
+}
+
+sub tar_create_tree {
+    my $type = shift;
+
+    my $long_a = 'a' x 29;
+    my $long_b = 'b' x 29;
+    my $long_c = 'c' x 29;
+    my $long_d = 'd' x 29;
+    my $long_e = 'e' x 29;
+    my $long_f = 'f' x 22;
+
+    # Popullate tar hierarchy
+    create('file');
+    link 'file', 'hardlink';
+
+    make_path("$long_a/$long_b/$long_c/$long_d/$long_e/");
+    make_path("$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/");
+    create("$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/long");
+    symlink "$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/long",
+            'symlink-long';
+
+    symlink 'file', 'symlink-a';
+    symlink 'hardlink', 'symlink-b';
+    symlink 'dangling', 'symlink-c';
+
+    mkdir 'directory';
+    mkfifo('fifo', 0770);
+
+    # FIXME: Need root.
+    # system 'mknod', 'chardev', 'c', '1', '3';
+    # system 'mknod', 'blockdev', 'b', '0', '0';
+}
+
+sub test_tar_extractor {
+    my $stdout;
+    my $stderr;
+
+    my $expected_tar = <<TAR;
+. mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./fifo mode=10750 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=fifo
+./file mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=file size=0
+./hardlink mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=hardlink linkto=./file size=0
+./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff/long mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=file size=0
+./directory mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
+./symlink-a mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=file size=0
+./symlink-b mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=hardlink size=0
+./symlink-c mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=dangling size=0
+./symlink-long mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff/long size=0
+TAR
+
+    make_path($tmpdir);
+
+    my $cwd = cwd();
+
+    # Check generated tarballs.
+    foreach my $type (qw(v7 ustar oldgnu gnu)) {
+        my $dirtree = "$tmpdir/$type";
+        my @paths;
+
+        mkdir $dirtree;
+        chdir $dirtree;
+        tar_create_tree($type);
+        find({ no_chdir => 1, wanted => sub {
+                   return if $type eq 'v7' and length > 99;
+                   return if $type eq 'v7' and -l and length readlink > 99;
+                   return if $type eq 'v7' and not (-f or -l or -d);
+                   return if $type eq 'ustar' and length > 256;
+                   return if $type eq 'ustar' and -l and length readlink > 100;
+                   push @paths, $_;
+               },
+               preprocess => sub { my (@files) = sort @_; @files } }, '.');
+        chdir $cwd;
+
+        my $paths_list = join "\0", @paths;
+        spawn(exec => [ 'tar', '-cf', "$dirtree.tar", '--format', $type,
+                        '-C', $dirtree, "--mtime=\@100000000",
+                        "--owner=user:100", "--group=group:200",
+                        '--null', '--no-unquote', '--no-recursion', '-T-' ],
+              wait_child => 1, from_string => \$paths_list);
+
+        my $expected = $expected_tar;
+        $expected =~ s/[ug]name=[^ ]+ //g if $type eq 'v7';
+        $expected =~ s/\n^.*fifo.*$//mg if $type eq 'v7';
+        $expected =~ s/\n^.*dddd.*$//mg if $type eq 'v7';
+        $expected =~ s/\n^.*symlink-long.*$//mg if $type eq 'ustar';
+
+        spawn(exec => [ './t-tarextract', "$dirtree.tar" ],
+              nocheck => 1, to_string => \$stdout, to_error => \$stderr);
+        ok($? == 0, "tar extractor $type should succeed");
+        is($stderr, undef, "tar extractor $type stderr is empty");
+        is($stdout, $expected, "tar extractor $type is ok");
+    }
+}
+
+test_tar_extractor();

+ 125 - 0
lib/dpkg/test/t-tarextract.c

@@ -0,0 +1,125 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-tarextract.c - test tar extractor
+ *
+ * Copyright © 2014 Guillem Jover <guillem@debian.org>
+ *
+ * This 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 2,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dpkg/ehandle.h>
+#include <dpkg/fdio.h>
+#include <dpkg/tarfn.h>
+
+struct tar_context {
+	int tar_fd;
+};
+
+static int
+tar_read(void *ctx, char *buffer, int size)
+{
+	struct tar_context *tc = ctx;
+
+	return fd_read(tc->tar_fd, buffer, size);
+}
+
+static int
+tar_object(void *ctx, struct tar_entry *te)
+{
+	printf("%s mode=%o time=%ld.%.9d uid=%d gid=%d", te->name,
+	       te->stat.mode, te->mtime, 0, te->stat.uid, te->stat.gid);
+	if (te->stat.uname)
+		printf(" uname=%s", te->stat.uname);
+	if (te->stat.gname)
+		printf(" gname=%s", te->stat.gname);
+
+	switch (te->type) {
+	case TAR_FILETYPE_FILE0:
+	case TAR_FILETYPE_FILE:
+		printf(" type=file size=%jd", te->size);
+		break;
+	case TAR_FILETYPE_HARDLINK:
+		printf(" type=hardlink linkto=%s size=%jd",
+		       te->linkname, te->size);
+		break;
+	case TAR_FILETYPE_SYMLINK:
+		printf(" type=symlink linkto=%s size=%jd",
+		       te->linkname, te->size);
+		break;
+	case TAR_FILETYPE_DIR:
+		printf(" type=dir");
+		break;
+	case TAR_FILETYPE_CHARDEV:
+	case TAR_FILETYPE_BLOCKDEV:
+		printf(" type=device id=%d.%d", major(te->dev), minor(te->dev));
+		break;
+	case TAR_FILETYPE_FIFO:
+		printf(" type=fifo");
+		break;
+	default:
+		ohshit("unexpected tar entry type '%c'", te->type);
+	}
+
+	printf("\n");
+
+	return 0;
+}
+
+struct tar_operations tar_ops = {
+	.read = tar_read,
+	.extract_file = tar_object,
+	.link = tar_object,
+	.symlink = tar_object,
+	.mkdir = tar_object,
+	.mknod = tar_object,
+};
+
+int
+main(int argc, char **argv)
+{
+	struct tar_context ctx;
+	const char *tar_name = argv[1];
+
+	setvbuf(stdout, NULL, _IOLBF, 0);
+
+	push_error_context();
+
+	if (tar_name) {
+		ctx.tar_fd = open(tar_name, O_RDONLY);
+		if (ctx.tar_fd < 0)
+			ohshite("cannot open file '%s'", tar_name);
+	} else {
+		ctx.tar_fd = STDIN_FILENO;
+	}
+
+	if (tar_extractor(&ctx, &tar_ops))
+		ohshite("extracting tar");
+
+	if (tar_name)
+		close(ctx.tar_fd);
+
+	pop_error_context(ehflag_normaltidy);
+
+	return 0;
+}