1 #!@sbindir@/nbdkit perl
8 nbdkit-tar-plugin - read and write files inside tar files without unpacking
12 nbdkit tar tar=FILENAME.tar file=PATH_INSIDE_TAR
16 =head2 Serve a single file inside a tarball
18 nbdkit tar tar=file.tar file=some/disk.img
19 guestfish --format=raw -a nbd://localhost
21 =head2 Opening a disk image inside an OVA file
23 The popular "Open Virtual Appliance" (OVA) format is really an
24 uncompressed tar file containing (usually) VMDK-format files, so you
25 could access one file in an OVA like this:
31 $ nbdkit -r tar tar=rhel.ova file=rhel-disk1.vmdk
32 $ guestfish --ro --format=vmdk -a nbd://localhost
36 C<nbdkit-tar-plugin> is a plugin which can read and writes files
37 inside an uncompressed tar file without unpacking the tar file.
39 The C<tar> and C<file> parameters are required, specifying the name of
40 the uncompressed tar file and the exact path of the file within the
41 tar file to access as a disk image.
43 This plugin will B<not> work on compressed tar files.
45 Use the nbdkit I<-r> flag to open the file readonly. This is the
46 safest option because it guarantees that the tar file will not be
47 modified. Without I<-r> writes will modify the tar file.
49 Also writing to the tar file does not change data checksums stored in
50 other files (the C<rhel.mf> file in the example above), and as these
51 will become incorrect you probably won't be able to open the file with
52 another tool afterwards.
54 The disk image cannot be resized.
58 C<nbdkit-tar-plugin> first appeared in nbdkit 1.2.
62 L<https://github.com/libguestfs/nbdkit/blob/master/plugins/tar/tar.pl>,
65 L<nbdkit-perl-plugin(3)>.
71 Based on the virt-v2v OVA importer written by Tomáš Golembiovský.
75 Copyright (C) 2017 Red Hat Inc.
82 my $file; # File within the tar file.
83 my $offset; # Offset within tar file.
84 my $size; # Size of disk image within tar file.
94 elsif ($k eq "file") {
98 die "unknown parameter $k";
102 # When all config parameters have been seen, find the extent of the
103 # file within the tar file.
106 die "tar or file parameter was not set\n"
107 unless defined $tar && defined $file;
109 die "$tar: file not found\n"
112 open (my $pipe, "-|", "tar", "--no-auto-compress", "-tRvf", $tar, $file)
113 or die "$tar: could not open or parse tar file, see errors above";
115 if (/^block\s(\d+):\s\S+\s\S+\s(\d+)/) {
116 # Add one for the tar header, and multiply by the block size.
117 $offset = ($1 + 1) * 512;
119 #print STDERR "offset = $offset, size = $size\n";
124 die "offset or size could not be parsed. Probably the tar file is not a tar file or the file does not exist in the tar file. See any errors above.\n"
125 unless defined $offset && defined $size;
128 # Accept a connection from a client, create and return the handle
129 # which is passed back to other calls.
132 my $readonly = shift;
134 $mode = "+<" unless $readonly;
135 open (my $fh, $mode, $tar) or die "$tar: open: $!";
137 my $h = { fh
=> $fh, readonly
=> $readonly };
141 # Close the connection.
161 seek ($h->{fh
}, $offset + $offs, 0) or die "seek: $!";
163 read ($h->{fh
}, $r, $count) or die "read: $!";
173 my $count = length ($buf);
175 seek ($fh, $offset + $offs, 0) or die "seek: $!";