plugins: Wire up rust plugin support for NBD_INFO_INIT_STATE
[nbdkit/ericb.git] / plugins / tar / tar.pl
blob79e683b6333d20cece6cd1dd8c1529beb172bbe8
1 #!@sbindir@/nbdkit perl
2 # -*- perl -*-
4 =pod
6 =head1 NAME
8 nbdkit-tar-plugin - read and write files inside tar files without unpacking
10 =head1 SYNOPSIS
12 nbdkit tar tar=FILENAME.tar file=PATH_INSIDE_TAR
14 =head1 EXAMPLE
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:
27 $ tar tf rhel.ova
28 rhel.ovf
29 rhel-disk1.vmdk
30 rhel.mf
31 $ nbdkit -r tar tar=rhel.ova file=rhel-disk1.vmdk
32 $ guestfish --ro --format=vmdk -a nbd://localhost
34 =head1 DESCRIPTION
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.
56 =head1 VERSION
58 C<nbdkit-tar-plugin> first appeared in nbdkit 1.2.
60 =head1 SEE ALSO
62 L<https://github.com/libguestfs/nbdkit/blob/master/plugins/tar/tar.pl>,
63 L<nbdkit(1)>,
64 L<nbdkit-plugin(3)>,
65 L<nbdkit-perl-plugin(3)>.
67 =head1 AUTHORS
69 Richard W.M. Jones.
71 Based on the virt-v2v OVA importer written by Tomáš Golembiovský.
73 =head1 COPYRIGHT
75 Copyright (C) 2017 Red Hat Inc.
77 =cut
79 use strict;
81 my $tar; # Tar file.
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.
86 sub config
88 my $k = shift;
89 my $v = shift;
91 if ($k eq "tar") {
92 $tar = $v;
94 elsif ($k eq "file") {
95 $file = $v;
97 else {
98 die "unknown parameter $k";
102 # When all config parameters have been seen, find the extent of the
103 # file within the tar file.
104 sub config_complete
106 die "tar or file parameter was not set\n"
107 unless defined $tar && defined $file;
109 die "$tar: file not found\n"
110 unless -f $tar;
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";
114 while (<$pipe>) {
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;
118 $size = $2;
119 #print STDERR "offset = $offset, size = $size\n";
122 close ($pipe);
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.
130 sub open
132 my $readonly = shift;
133 my $mode = "<";
134 $mode = "+<" unless $readonly;
135 open (my $fh, $mode, $tar) or die "$tar: open: $!";
136 binmode $fh;
137 my $h = { fh => $fh, readonly => $readonly };
138 return $h;
141 # Close the connection.
142 sub close
144 my $h = shift;
145 close $h->{fh};
148 # Return the size.
149 sub get_size
151 my $h = shift;
152 return $size;
155 # Read.
156 sub pread
158 my $h = shift;
159 my $count = shift;
160 my $offs = shift;
161 seek ($h->{fh}, $offset + $offs, 0) or die "seek: $!";
162 my $r;
163 read ($h->{fh}, $r, $count) or die "read: $!";
164 return $r;
167 # Write.
168 sub pwrite
170 my $h = shift;
171 my $fh = $h->{fh};
172 my $buf = shift;
173 my $count = length ($buf);
174 my $offs = shift;
175 seek ($fh, $offset + $offs, 0) or die "seek: $!";
176 print $fh ($buf);