File Coverage

blib/lib/GnuPG/Tie.pm
Criterion Covered Total %
statement 123 143 86.0
branch 42 72 58.3
condition 1 3 33.3
subroutine 16 18 88.8
pod 0 5 0.0
total 182 241 75.5


line stmt bran cond sub pod time code
1             #
2             # GnuPG.pm - Abstract tied interface to the GnuPG.
3             #
4             # This file is part of GnuPG.pm.
5             #
6             # Author: Francis J. Lacoste <francis.lacoste@Contre.COM>
7             #
8             # Copyright (C) 1999, 2000 iNsu Innovations Inc.
9             # Copyright (C) 2001 Francis J. Lacoste
10             #
11             # This program is free software; you can redistribute it and/or modify
12             # it under the terms of the GNU General Public License as published by
13             # the Free Software Foundation; either version 2 of the License, or
14             # (at your option) any later version.
15             #
16             # This program is distributed in the hope that it will be useful,
17             # but WITHOUT ANY WARRANTY; without even the implied warranty of
18             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19             # GNU General Public License for more details.
20             #
21             # You should have received a copy of the GNU General Public License
22             # along with this program; if not, write to the Free Software
23             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24             #
25             package GnuPG::Tie;
26              
27 28     28   140 use GnuPG;
  28         56  
  28         896  
28 28     28   112 use Symbol;
  28         56  
  28         1148  
29              
30 28     28   140 use Carp;
  28         28  
  28         1092  
31              
32 28     28   112 use Fcntl;
  28         84  
  28         4340  
33              
34 28     28   140 use strict;
  28         56  
  28         34076  
35              
36             sub TIEHANDLE {
37 18     18   10211 my $class = shift;
38 18   33     129 $class = ref $class || $class;
39              
40 18         122 my ($gpg_in, $gpg_out) = ( gensym, gensym );
41 18         644 my ($tie_in,$tie_out) = ( gensym, gensym );
42 18 50       564 pipe $gpg_in, $tie_out
43             or croak "error while creating pipe: $!";
44 18 50       165 pipe $tie_in, $gpg_out
45             or croak "error while creating pipe: $!";
46              
47             # Unbuffer writer pipes
48 18         111 for my $fd ( ($gpg_out, $tie_out) ) {
49 36         123 my $old = select $fd;
50 36         130 $| = 1;
51 36         138 select $old;
52             }
53              
54             # Keep pipes open after exec
55             # Removed close on exec from all file descriptor
56 18         69 for my $fd ( ( $gpg_in, $gpg_out, $tie_in, $tie_out ) ) {
57 72 50       234 fcntl( $fd, F_SETFD, 0 )
58             or croak "error removing close on exec flag: $!\n" ;
59             }
60              
61             # Operate in non blocking mode
62 18         52 for my $fd ( $tie_in, $tie_out ) {
63 36 50       118 my $flags = fcntl $fd, F_GETFL, 0
64             or croak "error getting flags on pipe: $!\n";
65 36 50       158 fcntl $fd, F_SETFL, $flags | O_NONBLOCK
66             or croak "error setting non-blocking IO on pipe: $!\n";
67             }
68              
69 18         192 my $self = bless { reader => $tie_in,
70             writer => $tie_out,
71             done_writing => 0,
72             buffer => "",
73             len => 0,
74             offset => 0,
75             line_buffer => "",
76             eof => 0,
77             gnupg => new GnuPG( @_ ),
78             }, $class;
79              
80             # Let subclass call the appropriate method and set
81             # up the GnuPG object.
82 18         156 $self->run_gnupg( @_,
83             input => $gpg_in,
84             output => $gpg_out,
85             tie_mode => 1,
86             );
87 14         129 close $gpg_in;
88 14         60 close $gpg_out;
89              
90 14         310 return $self;
91             }
92              
93             sub WRITE {
94 50     50   135 my ( $self, $buf, $len, $offset ) = @_;
95              
96             croak "attempt to read on a closed file handle\n"
97 50 50       147 unless defined $self->{writer};
98              
99 50 50       121 croak ( "can't write after having read" ) if $self->{done_writing};
100              
101 50         121 my ( $r_in, $w_in ) = ( '', '' );
102 50         196 vec( $r_in, fileno $self->{reader}, 1) = 1;
103 50         142 vec( $w_in, fileno $self->{writer}, 1) = 1;
104              
105 50         77 my $left = $len;
106 50         146 while ( $left ) {
107 50         135 my ($r_out, $w_out) = ($r_in, $w_in);
108 50         210 my $nfound = select $r_out, $w_out, undef, undef;
109 50 50       117 croak "error in select: $!\n" unless defined $nfound;
110              
111             # Check if we can write
112 50 50       126 if ( vec $w_out, fileno $self->{writer}, 1 ) {
113 50         244 my $n = syswrite $self->{writer}, $buf, $len, $offset;
114 50 50       113 croak "error on write: $!\n" unless defined $n;
115 50         80 $left -= $n;
116 50         78 $offset += $n;
117             }
118             # Check if we can read
119 50 50       182 if ( vec $r_out, fileno $self->{reader}, 1 ) {
120             my $n = sysread $self->{reader}, $self->{buffer}, 1024,
121 0         0 $self->{len};
122 0 0       0 croak "error on read: $!\n" unless defined $n;
123 0         0 $self->{len} += $n;
124             }
125             }
126              
127 50         197 return $len;
128             }
129              
130             sub done_writing() {
131 28     28 0 53 my $self = shift;
132              
133             # Once we start reading, no other writing can be place
134             # on the pipe. So we close the writer file descriptor
135 28 100       87 unless ( $self->{done_writing} ) {
136 14         28 $self->{done_writing} = 1;
137             close $self->{writer}
138 14 50       119 or croak "error closing writer pipe: $\n";
139              
140 14         77 $self->postwrite_hook();
141             }
142             }
143              
144             sub READ {
145 28     28   65 my $self = shift;
146 28         63 my $bufref = \$_[0];
147 28         77 my ( undef, $len, $offset ) = @_;
148              
149             croak "attempt to read on a closed file handle\n"
150 28 50       89 unless defined $self->{reader};
151              
152 28 50       94 if ( $self->{eof}) {
153 0         0 $self->{eof} = 0;
154 0         0 return 0;
155             }
156              
157             # Start reading the input
158 28 100       251 $self->done_writing unless ( $self->{done_writing} );
159              
160             # Check if we have something in our buffer
161 28 50       128 if ( $self->{len} - $self->{offset} ) {
162 0         0 my $left = $self->{len} - $self->{offset};
163 0 0       0 my $n = $left > $len ? $len : $left;
164             substr( $$bufref, $offset, $len) =
165 0         0 substr $self->{buffer}, $self->{offset}, $n;
166 0         0 $self->{offset} += $n;
167              
168             # Return only if we have read the requested length.
169 0 0       0 return $n if $n == $len;
170              
171 0         0 $offset += $n;
172 0         0 $len -= $n;
173             }
174              
175             # Wait for the reader fd to come ready
176 28         71 my ( $r_in ) = '';
177 28         159 vec( $r_in, fileno $self->{reader}, 1 ) = 1;
178 28         21385 my $nfound = select $r_in, undef, undef, undef;
179 28 50       171 croak "error in select: $!\n" unless defined $nfound;
180              
181 28         278 my $n = sysread $self->{reader}, $$bufref, $len, $offset;
182 28 50       89 croak "error in read: $!\n" unless defined $n;
183              
184 28         105 $n;
185             }
186              
187             sub PRINT {
188 50     50   692 my $self = shift;
189              
190 50 50       168 my $sep = defined $, ? $, : "";
191 50         147 my $buf = join $sep, @_;
192              
193 50         190 $self->WRITE( $buf, length $buf, 0 );
194             }
195              
196             sub PRINTF {
197 0     0   0 my $self = shift;
198              
199 0         0 my $buf = sprintf @_;
200              
201 0         0 $self->WRITE( $buf, length $buf, 0 );
202             }
203              
204             sub GETC {
205 0     0   0 my $self = shift;
206              
207 0         0 my $c = undef;
208 0         0 my $n = $self->READ( $c, 1, 0 );
209              
210 0 0       0 return undef unless $n;
211 0         0 $c;
212             }
213              
214             sub READLINE {
215 68 100   68   714 wantarray ? $_[0]->getlines() : $_[0]->getline();
216             }
217              
218             sub CLOSE {
219 14     14   173 my $self = shift;
220              
221 14         46 $self->done_writing;
222              
223             close $self->{reader}
224 14 50       479 or croak "error closing reader pipe: $!\n";
225              
226 14         97 $self->postread_hook();
227              
228 14         97 $self->{gnupg}->end_gnupg();
229              
230 14         45 $self->{reader} = undef;
231 14         66 $self->{writer} = undef;
232              
233 14         162 ! $?;
234             }
235              
236             sub getlines {
237 2     2 0 22 my $self = shift;
238              
239 2         10 my @lines = ();
240 2         10 my $line;
241 2         10 while ( defined( $line = $self->getline ) ) {
242 6         38 push @lines, $line;
243             }
244              
245 2         28 @lines;
246             }
247              
248             sub getline {
249 74     74 0 133 my $self = shift;
250              
251 74 100       187 if ( $self->{eof} ) {
252             # Clear EOF
253 2         6 $self->{eof} = 0;
254 2         12 return undef;
255             }
256              
257             # Handle slurp mode
258 72 100       188 if ( not defined $/ ) {
259 3         24 my $buf = $self->{line_buffer};
260 3         18 my $offset = length $buf;
261 3         27 while ( my $n = $self->READ( $buf, 4096, $offset ) ) {
262 3         21 $offset += $n
263             }
264 3         18 return $buf;
265             }
266              
267             # Handle explicit RS
268 69 100       235 if ( $/ ne "" ) {
269 63         132 my $buf = $self->{line_buffer};
270 63         200 while ( not $self->{eof} ) {
271              
272 72 100       255 if ( length $buf != 0 ) {
273 54         88 my $i;
274 54 50       145 if ( ( $i = index $buf, $/ ) != -1 ) {
275             # Found end of line
276 54         148 $self->{line_buffer} = substr $buf, $i + length $/;
277              
278 54         203 return substr $buf, 0, $i + length $/;
279             }
280             }
281              
282             # Read more data in our buffer
283 18         97 my $n = $self->READ( $buf, 4096, length $buf );
284 18 100       89 if ( $n == 0 ) {
285             # Set EOF
286 9         18 $self->{eof} = 1;
287 9 50       46 return length $buf == 0 ? undef : $buf ;
288             }
289             }
290             } else {
291 6         24 my $buf = $self->{line_buffer};
292 6         42 while ( not $self->{eof} ) {
293              
294 8 100       100 if ( $buf =~ m/(\r\n\r\n+|\n\n+)/s ) {
295 4         46 my ($para, $rest) = split /\r\n\r\n+|\n\n+/, $buf, 2;
296 4         20 $self->{line_buffer} = $rest;
297 4         70 return $para . $1;
298             }
299              
300             # Read more data in our buffer
301 4         36 my $n = $self->READ( $buf, 4096, length $buf );
302 4 100       44 if ( $n == 0 ) {
303             # Set EOF
304 2         8 $self->{eof} = 1;
305 2 50       24 return length $buf == 0 ? undef : $buf ;
306             }
307             }
308             }
309             }
310              
311             # Hook called after reading is done
312       8 0   sub postread_hook {
313              
314             }
315              
316             # Hook called when writing is done.
317       8 0   sub postwrite_hook {
318              
319             }
320              
321             1;
322              
323             __END__
324              
325             =pod
326              
327             =head1 NAME
328              
329             GnuPG::Tie::Encrypt - Tied filehandle interface to encryption with the GNU Privacy Guard.
330              
331             GnuPG::Tie::Decrypt - Tied filehandle interface to decryption with the GNU Privacy Guard.
332              
333             =head1 SYNOPSIS
334              
335             use GnuPG::Tie::Encrypt;
336             use GnuPG::Tie::Decrypt;
337              
338             tie *CIPHER, 'GnuPG::Tie::Encrypt', armor => 1, recipient => 'User';
339             print CIPHER <<EOF;
340             This is a secret
341             EOF
342             local $/ = undef;
343             my $ciphertext = <CIPHER>;
344             close CIPHER;
345             untie *CIPHER;
346              
347             tie *PLAINTEXT, 'GnuPG::Tie::Decrypt', passphrase => 'secret';
348             print PLAINTEXT $ciphertext;
349             my $plaintext = <PLAINTEXT>;
350              
351             # $plaintext should now contains 'This is a secret'
352             close PLAINTEXT;
353             untie *PLAINTEXT;
354              
355             =head1 DESCRIPTION
356              
357             GnuPG::Tie::Encrypt and GnuPG::Tie::Decrypt provides a tied file handle
358             interface to encryption/decryption facilities of the GNU Privacy guard.
359              
360             With GnuPG::Tie::Encrypt everyting you write to the file handle will be
361             encrypted. You can read the ciphertext from the same file handle.
362              
363             With GnuPG::Tie::Decrypt you may read the plaintext equivalent of a
364             ciphertext. This is one can have been written to file handle.
365              
366             All options given to the tie constructor will be passed on to the underlying
367             GnuPG object. You can use a mix of options to output directly to a file or
368             to read directly from a file, only remember than once you start reading
369             from the file handle you can't write to it anymore.
370              
371             =head1 AUTHOR
372              
373             Francis J. Lacoste <francis.lacoste@Contre.COM>
374              
375             =head1 COPYRIGHT
376              
377             Copyright (c) 1999, 2000 iNsu Innovations Inc.
378             Copyright (c) 2001 Francis J. Lacoste
379              
380             This program is free software; you can redistribute it and/or modify
381             it under the terms of the GNU General Public License as published by
382             the Free Software Foundation; either version 2 of the License, or
383             (at your option) any later version.
384              
385             =head1 SEE ALSO
386              
387             gpg(1) GnuPG(3)
388              
389             =cut