File Coverage

blib/lib/Paranoid/IO.pm
Criterion Covered Total %
statement 293 314 93.3
branch 104 156 66.6
condition 21 36 58.3
subroutine 32 33 96.9
pod 14 14 100.0
total 464 553 83.9


line stmt bran cond sub pod time code
1             # Paranoid::IO -- Paranoid IO support
2             #
3             # $Id: lib/Paranoid/IO.pm, 2.08 2020/12/31 12:10:06 acorliss Exp $
4             #
5             # This software is free software. Similar to Perl, you can redistribute it
6             # and/or modify it under the terms of either:
7             #
8             # a) the GNU General Public License
9             # as published by the
10             # Free Software Foundation ; either version 1
11             # , or any later version
12             # , or
13             # b) the Artistic License 2.0
14             # ,
15             #
16             # subject to the following additional term: No trademark rights to
17             # "Paranoid" have been or are conveyed under any of the above licenses.
18             # However, "Paranoid" may be used fairly to describe this unmodified
19             # software, in good faith, but not as a trademark.
20             #
21             # (c) 2005 - 2020, Arthur Corliss (corliss@digitalmages.com)
22             # (tm) 2008 - 2020, Paranoid Inc. (www.paranoid.com)
23             #
24             #####################################################################
25              
26             #####################################################################
27             #
28             # Environment definitions
29             #
30             #####################################################################
31              
32             package Paranoid::IO;
33              
34 36     36   15515 use 5.008;
  36         119  
35              
36 36     36   205 use strict;
  36         53  
  36         1006  
37 36     36   207 use warnings;
  36         68  
  36         1172  
38 36     36   184 use vars qw($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS);
  36         73  
  36         2455  
39 36     36   230 use base qw(Exporter);
  36         70  
  36         2557  
40 36     36   218 use Cwd qw(realpath);
  36         69  
  36         2086  
41 36     36   223 use Fcntl qw(:DEFAULT :flock :mode :seek);
  36         85  
  36         18489  
42 36     36   275 use Paranoid;
  36         69  
  36         2203  
43 36     36   754 use Paranoid::Debug qw(:all);
  36         82  
  36         5433  
44 36     36   11311 use Paranoid::Input;
  36         73  
  36         2108  
45 36     36   21571 use IO::Handle;
  36         232291  
  36         3730  
46              
47             ($VERSION) = ( q$Revision: 2.08 $ =~ /(\d+(?:\.\d+)+)/sm );
48              
49             @EXPORT = qw(pclose pcloseAll popen preopen ptell pseek pflock pread
50             pnlread pwrite pappend ptruncate);
51             @EXPORT_OK = ( @EXPORT, qw(PIOBLKSIZE PIOMAXFSIZE) );
52             %EXPORT_TAGS = ( all => [@EXPORT_OK] );
53              
54 36     36   285 use constant PDEFPERM => 0666;
  36         72  
  36         2505  
55 36     36   226 use constant PDEFMODE => O_CREAT | O_RDWR;
  36         109  
  36         1978  
56 36     36   235 use constant PDEFBLKSZ => 4096;
  36         73  
  36         1863  
57 36     36   282 use constant PDEFFILESZ => 65536;
  36         85  
  36         105711  
58              
59             #####################################################################
60             #
61             # Module code follows
62             #
63             #####################################################################
64              
65             {
66              
67             my $mblksz = PDEFBLKSZ;
68              
69             sub PIOBLKSIZE : lvalue {
70              
71             # Purpose: Gets/sets default block size for I/O
72             # Returns: $mblksz
73             # Usage: PIOBLKSIZE
74              
75 457     457 1 1168 $mblksz;
76             }
77              
78             my $mfsz = PDEFFILESZ;
79              
80             sub PIOMAXFSIZE : lvalue {
81              
82             # Purpose: Gets/sets default max file size for I/O
83             # Returns: $mfsz
84             # Usage: PIOBLKSIZE
85              
86 306     306 1 893 $mfsz;
87             }
88              
89             # %files: {name} => {
90             # pid => $pid,
91             # mode => $mode,
92             # perms => $perms,
93             # fh => $fh,
94             # real => $realpath,
95             # ltype => $lock,
96             # }
97             my %files;
98              
99             sub _pfFhind ($) {
100              
101             # Purpose: Searches for a filename based on the
102             # current file handle
103             # Returns: String/undefined
104             # Usage: $rv = _pfFhind($fh);
105              
106 114     114   168 my $fh = shift;
107 114         157 my $rv;
108              
109 114         327 pdebug( 'entering w/%s', PDLEVEL2, $fh );
110 114         338 pIn();
111              
112 114 50 33     495 if ( defined $fh and ref $fh eq 'GLOB' ) {
113 114         357 foreach ( keys %files ) {
114 83 50       294 if ( $files{$_}{fh} eq $fh ) {
115 83 50       470 $rv = $_ and last;
116             }
117             }
118             }
119              
120 114         357 pOut();
121 114         296 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
122              
123 114         258 return $rv;
124             }
125              
126             sub pclose {
127              
128             # Purpose: Closes a cached file handle
129             # Returns: Boolean
130             # Usage: $rv = plcose($filename)
131             # Usage: $rv = plcose($fh)
132              
133 82     82 1 2112 my $filename = shift;
134 82         266 my $rv = 1;
135 82         206 my $fh;
136              
137 82         316 pdebug( 'entering w/%s', PDLEVEL2, $filename );
138 82         328 pIn();
139              
140 82 50       208 if ( defined $filename ) {
141              
142             # Get the missing variable
143 82 100       479 if ( ref $filename eq 'GLOB' ) {
144 5         15 $fh = $filename;
145 5         15 $filename = _pfFhind($fh);
146             } else {
147 77 100       401 $fh = $files{$filename}{fh} if exists $files{$filename};
148             }
149              
150             # Close the filehandle
151 82 100 100     605 if ( defined $fh and fileno $fh ) {
152 75         922 flock $fh, LOCK_UN;
153 75         1115 $rv = close $fh;
154             }
155              
156             # Clean up internal data structures
157 82 100       601 delete $files{$filename} if defined $filename;
158              
159 82 50       248 Paranoid::ERROR =
160             pdebug( 'error closing file handle: %s', PDLEVEL1, $! )
161             unless $rv;
162             }
163              
164 82         319 pOut();
165 82         260 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
166              
167 82         427 return $rv;
168             }
169              
170             sub pcloseAll {
171              
172             # Purpose: Closes all filehandles
173             # Returns: Boolean
174             # Usage: $rv = pcloseAll();
175              
176 36     36 1 293 my @files = @_;
177 36         295 my $rv = 1;
178              
179 36         617 pdebug( 'entering', PDLEVEL3 );
180 36         439 pIn();
181              
182 36 50       728 @files = keys %files unless @files;
183 36         382 foreach (@files) {
184 8 50       38 $rv = 0 unless pclose($_);
185             }
186              
187 36         464 pOut();
188 36         226 pdebug( 'leaving w/rv: %s', PDLEVEL3, $rv );
189              
190 36         1484 return $rv;
191             }
192              
193             sub _open {
194              
195             # Purpose: Performs the sysopen call
196             # Returns: rv of sysopen
197             # Usage: $rv = _open($filename);
198             # Usage: $rv = _open($filename, $mode);
199             # Usage: $rv = _open($filename, $mode, $perms);
200              
201 85     85   211 my $filename = shift;
202 85         360 my $mode = shift;
203 85         212 my $perms = shift;
204 85         308 my ( %tmp, $f, $fh, $rv );
205              
206 85         308 pdebug( 'entering w/(%s)(%s)(%s)',
207             PDLEVEL3, $filename, $mode, $perms );
208 85         267 pIn();
209              
210 85 50       210 if ( defined $filename ) {
211              
212             # Detaint mode/perms
213 85         159 $rv = 1;
214 85 100       213 $mode = PDEFMODE unless defined $mode;
215 85 100       215 $perms = PDEFPERM unless defined $perms;
216 85 50       844 unless ( detaint( $mode, 'int' ) ) {
217 0         0 $rv = 0;
218 0         0 Paranoid::ERROR =
219             pdebug( 'invalid mode passed: %s', PDLEVEL1, $mode );
220             }
221 85 50       319 unless ( detaint( $perms, 'int' ) ) {
222 0         0 $rv = 0;
223 0         0 Paranoid::ERROR =
224             pdebug( 'invalid perm passed: %s', PDLEVEL1, $perms );
225             }
226              
227             # Prep file record
228             %tmp = (
229 85         708 mode => $mode,
230             perms => $perms,
231             pid => $$,
232             ltype => LOCK_UN,
233             );
234              
235             # Detaint filename
236 85 50       239 if ($rv) {
237 85 50       272 if ( detaint( $filename, 'filename', $f ) ) {
238              
239             # Attempt to open the fila
240             $rv =
241             ( $tmp{mode} & O_CREAT )
242             ? sysopen $fh, $f, $tmp{mode}, $tmp{perms}
243             : sysopen $fh,
244 85 100       5264 $f, $tmp{mode};
245 85 100       462 if ($rv) {
246 74         240 $tmp{fh} = $fh;
247 74         2497 $tmp{real} = realpath($filename);
248 74         699 $files{$filename} = {%tmp};
249             } else {
250 11         47 Paranoid::ERROR = pdebug( 'failed to open %s: %s',
251             PDLEVEL1, $filename, $! );
252             }
253              
254             } else {
255 0         0 Paranoid::ERROR =
256             pdebug( 'failed to detaint %s', PDLEVEL1, $filename );
257             }
258             }
259             }
260              
261 85         441 pOut();
262 85         250 pdebug( 'leaving w/rv: %s', PDLEVEL3, $rv );
263              
264 85         468 return $rv;
265             }
266              
267             sub _reopen {
268              
269             # Purpose: Reopens an open file handle
270             # Returns: rv of _open
271             # Usage: $rv = _reopen($filename);
272             # Usage: $rv = _reopen($fh);
273              
274 6     6   64 my $filename = shift;
275 6         31 my ( %tmp, $fh, $pos, $rv, $af );
276              
277 6         44 pdebug( 'entering w/(%s)', PDLEVEL3, $filename );
278 6         458 pIn();
279              
280 6 50 33     258 if ( defined $filename and exists $files{$filename} ) {
281              
282             # Get a copy of the file record
283 6         67 %tmp = %{ $files{$filename} };
  6         403  
284 6         64 $fh = $tmp{fh};
285              
286             # Get the current cursor position
287 6 50       161 $pos = fileno $fh ? sysseek $fh, 0, SEEK_CUR : 0;
288 6         564 $af = $fh->autoflush;
289              
290             # Close the old file handle
291 6         1414 $tmp{fh} = $fh = undef;
292 6 50       198 if ( pclose($filename) ) {
293              
294             # Remove O_TRUNC
295 6 100       36 $tmp{mode} ^= O_TRUNC if $tmp{mode} & O_TRUNC;
296              
297             # Open the file and move the cursor back where it was
298 6         91 $rv = _open( @tmp{qw(real mode perms)} );
299 6 50       60 if ($rv) {
300              
301             # Move the cursor back to where it was
302 6         33 $fh = $files{ $tmp{real} }{fh};
303 6         33 $fh->autoflush($af);
304 6         406 $rv = sysseek $fh, $pos, SEEK_SET;
305              
306             # Move the record over to the original file name
307 6         31 $files{$filename} = { %{ $files{ $tmp{real} } } };
  6         59  
308 6 50       123 delete $files{ $tmp{real} } if $filename ne $tmp{real};
309             }
310             }
311             }
312              
313 6         125 pOut();
314 6         25 pdebug( 'leaving w/rv: %s', PDLEVEL3, $rv );
315              
316 6         39 return $rv;
317             }
318              
319             sub popen {
320              
321             # Purpose: Performs a sysopen with file descriptor caching
322             # Returns: file handle
323             # Usage: $fh = popen($filename, $mode, $perms);
324              
325 716     716 1 1527 my $filename = shift;
326 716         973 my $mode = shift;
327 716         985 my $perms = shift;
328 716         1096 my ( %tmp, $fh, $f, $pos, $rv );
329              
330 716         1835 pdebug( 'entering w/(%s)(%s)(%s)',
331             PDLEVEL2, $filename, $mode, $perms );
332 716         1753 pIn();
333              
334             # Make sure we weren't passed a file handle, but if we
335             # were attempt to find the actual filename
336 716 50       1498 if ( defined $filename ) {
337 716 100       1480 if ( ref $filename eq 'GLOB' ) {
338 89         151 $fh = $filename;
339 89         194 $filename = _pfFhind($filename);
340             } else {
341 627 100       2256 $fh = $files{$filename}{fh} if exists $files{$filename};
342             }
343             }
344              
345 716 100 100     3001 if ( defined $filename and exists $files{$filename} ) {
    100 33        
    50          
346              
347             # Make sure pid is the same
348 625 100       1856 if ( $files{$filename}{pid} == $$ ) {
349              
350 619 50       1675 if ( fileno $fh ) {
351              
352             # Return existing filehandle
353 619         2324 pdebug( 'returning cached file handle', PDLEVEL2 );
354 619         1131 $rv = $fh;
355              
356             } else {
357              
358             # Reopen a filehandle that was closed outside
359             # of this module
360 0         0 pdebug( 'reopening closed file handle', PDLEVEL2 );
361 0 0       0 $rv = $files{$filename}{fh} if _reopen($filename);
362             }
363              
364             } else {
365              
366 6         194 pdebug( 'reopening inherited file handle in child',
367             PDLEVEL2 );
368 6 50       98 $rv = $files{$filename}{fh} if _reopen($filename);
369              
370             }
371              
372             } elsif ( defined $filename ) {
373              
374 79         288 pdebug( 'opening new file handle', PDLEVEL2 );
375 79 100       303 $rv = $files{$filename}{fh} if _open( $filename, $mode, $perms );
376              
377             } elsif ( !defined $filename and defined $fh ) {
378 12         29 Paranoid::ERROR =
379             pdebug( 'popen called with an unmanaged file handle',
380             PDLEVEL1 );
381 12 100       37 $rv = fileno $fh ? $fh : undef;
382             } else {
383 0         0 Paranoid::ERROR =
384             pdebug( 'attempted to open a file with an undefined name',
385             PDLEVEL1 );
386             }
387              
388 716         1774 pOut();
389 716         1755 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
390              
391 716         2088 return $rv;
392             }
393              
394             sub preopen {
395              
396             # Purpose: Reopens either the named files or all
397             # Returns: Boolean
398             # Usage: $rv = preopen();
399             # Usage: $rv = preopen(@filenames);
400              
401 0     0 1 0 my @files = @_;
402 0         0 my $rv = 1;
403              
404 0         0 pdebug( 'entering w/%s', PDLEVEL2, @files );
405 0         0 pIn();
406              
407 0 0       0 @files = keys %files unless @files;
408 0 0       0 foreach (@files) { $rv = 0 unless _reopen($_) }
  0         0  
409              
410 0         0 pOut();
411 0         0 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
412              
413 0         0 return $rv;
414             }
415              
416             sub pflock {
417              
418             # Purpose: Performs file-locking operations on the passed filename
419             # Returns: Boolean
420             # Usage: $rv = pflock($filename, LOCK_EX);
421              
422 1036     1036 1 2106 my $filename = shift;
423 1036         1458 my $lock = shift;
424 1036         1655 my ( $rv, $fh );
425 1036         4411 local $!;
426              
427 1036         3391 pdebug( 'entering w/(%s)(%s)', PDLEVEL2, $filename, $lock );
428 1036         2818 pIn();
429              
430 1036 50       2078 if ( defined $filename ) {
431              
432             # Get the missing variable
433 1036 100       2176 if ( ref $filename eq 'GLOB' ) {
434 20         33 $fh = $filename;
435 20         40 $filename = _pfFhind($fh);
436             } else {
437 1016 100       2835 $fh = $files{$filename}{fh} if exists $files{$filename};
438             }
439              
440 1036 100       2106 if ( defined $fh ) {
441              
442             # Apply the lock
443 1034         89084 $rv = flock $fh, $lock;
444              
445             # Record change to internal state if we're tracking this file
446             $files{$filename}{ltype} = $lock
447             if defined $filename
448 1034 50 66     6478 and exists $files{$filename};
449              
450 1034 50       2251 Paranoid::ERROR =
451             pdebug( 'error attempting to pflock: %s', PDLEVEL1, $! )
452             unless $rv;
453             }
454             }
455              
456 1036         3659 pOut();
457 1036         2692 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
458              
459 1036         4050 return $rv;
460             }
461             }
462              
463             sub ptell {
464              
465             # Purpose: Returns the cursor position in the file handle
466             # Returns: Integer
467             # Usage: $pos = ptell($filename);
468              
469 77     77 1 2462 my $filename = shift;
470 77         218 my ( $rv, $fh );
471 77         636 local $!;
472              
473 77         284 pdebug( 'entering w/%s', PDLEVEL2, $filename );
474 77         207 pIn();
475              
476 77 50       191 if ( defined $filename ) {
477              
478 77         185 $fh = popen( $filename, O_RDWR );
479 77 100       221 if ( defined $fh ) {
480 75         691 $rv = sysseek $fh, 0, SEEK_CUR;
481 75 50       317 Paranoid::ERROR =
482             pdebug( 'error attempting to ptell: %s', PDLEVEL1, $! )
483             unless $rv;
484             }
485             }
486              
487 77         276 pOut();
488 77         238 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
489              
490 77         365 return $rv;
491             }
492              
493             sub pseek {
494              
495             # Purpose: Performs a sysseek
496             # Returns: Integer/undef
497             # Usage: $cur = pseek($filename, $curpos, $whence);
498              
499 17     17 1 601589 my $filename = shift;
500 17         35 my $setpos = shift;
501 17         29 my $whence = shift;
502 17         33 my ( $rv, $fh );
503 17         140 local $!;
504              
505 17         116 pdebug( 'entering w/(%s)(%s)(%s)', PDLEVEL2, $filename, $setpos,
506             $whence );
507 17         61 pIn();
508              
509 17 50       46 if ( defined $filename ) {
510              
511 17         56 $fh = popen( $filename, O_RDWR );
512 17 100       54 if ( defined $fh ) {
513 15         167 $rv = sysseek $fh, $setpos, $whence;
514 15 100       78 Paranoid::ERROR =
515             pdebug( 'error attempting to pseek: %s', PDLEVEL1, $! )
516             unless $rv;
517             }
518             }
519              
520 17         72 pOut();
521 17         50 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
522              
523 17         180 return $rv;
524             }
525              
526             sub pwrite {
527              
528             # Purpose: Performs a syswrite w/locking
529             # Returns: Integer/undef
530             # Usage: $bytes = pwrite($filename, $text);
531             # Usage: $bytes = pwrite($filename, $text, $length);
532             # Usage: $bytes = pwrite($filename, $text, $length, $offset);
533              
534 16     16 1 5430 my $filename = shift;
535 16         53 my $out = shift;
536 16         51 my $wlen = shift;
537 16         22 my $offset = shift;
538 16         30 my ( $fh, $rv );
539              
540 16         96 pdebug( 'entering w/(%s)(%s)(%s)(%s)',
541             PDLEVEL2, $filename, $out, $wlen, $offset );
542 16         53 pIn();
543              
544 16 100 66     147 if ( defined $filename and defined $out and length $out ) {
      100        
545              
546             # Opportunistically open a file handle if needed,
547             # otherwise, just retrieve the existing file handle
548 12         55 $fh = popen( $filename, O_WRONLY | O_CREAT | O_TRUNC );
549              
550             # Smoke 'em if you got'em...
551 12 50       31 if ( defined $fh ) {
552 12 50       38 if ( pflock( $filename, LOCK_EX ) ) {
553 12 100       35 $wlen = length $out unless defined $wlen;
554 12 100       22 $offset = 0 unless defined $offset;
555 12         330 $rv = syswrite $fh, $out, $wlen, $offset;
556 12 50       52 if ( defined $rv ) {
557 12         43 pdebug( 'wrote %d bytes', PDLEVEL2, $rv );
558             } else {
559 0         0 Paranoid::ERROR =
560             pdebug( 'failed to write to file handle: %s',
561             PDLEVEL1, $! );
562             }
563 12         31 pflock( $filename, LOCK_UN );
564             }
565             }
566             }
567              
568 16         52 pOut();
569 16         38 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
570              
571 16         48 return $rv;
572             }
573              
574             sub pappend ($$;$$) {
575              
576             # Purpose: Appends the data to the end of the file,
577             # but does not move the file cursor
578             # Returns: Integer/undef
579             # Usage: $rv = pappend($filename, $content);
580             # Usage: $rv = pappend($filename, $content, $length);
581             # Usage: $rv = pappend($filename, $content, $length, $offset);
582              
583 260     260 1 633 my $filename = shift;
584 260         552 my $out = shift;
585 260         436 my $wlen = shift;
586 260         368 my $offset = shift;
587 260         826 my ( $fh, $pos, $rv );
588              
589 260         980 pdebug( 'entering w/(%s)(%s)(%s)(%s)',
590             PDLEVEL2, $filename, $out, $wlen, $offset );
591 260         715 pIn();
592              
593 260 50 33     2082 if ( defined $filename and defined $out and length $out ) {
      33        
594              
595             # Opportunistically opena file handle in append mode
596 260         749 $fh = popen( $filename, O_WRONLY | O_CREAT | O_APPEND );
597              
598             # Smoke 'em if you got'em...
599 260 50       620 if ( defined $fh ) {
600              
601             # Lock the file
602 260 50       773 if ( pflock( $filename, LOCK_EX ) ) {
603              
604             # Save the current position
605 260         2416 $pos = sysseek $fh, 0, SEEK_CUR;
606              
607             # Seek to the end of the file
608 260 50 33     2187 if ( $pos and sysseek $fh, 0, SEEK_END ) {
609              
610             # write the content
611 260 50       1832 $wlen = length $out unless defined $wlen;
612 260 50       623 $offset = 0 unless defined $offset;
613 260         4949 $rv = syswrite $fh, $out, $wlen, $offset;
614 260 50       988 if ( defined $rv ) {
615 260         1053 pdebug( 'wrote %d bytes', PDLEVEL2, $rv );
616             } else {
617 0         0 Paranoid::ERROR =
618             pdebug( 'failed to write to file handle: %s',
619             PDLEVEL1, $! );
620             }
621             }
622              
623             # Seek back to original position
624 260         2281 sysseek $fh, $pos, SEEK_SET;
625              
626             # Unlock the file handle
627 260         999 pflock( $filename, LOCK_UN );
628             }
629             }
630             }
631              
632 260         816 pOut();
633 260         661 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
634              
635 260         1122 return $rv;
636             }
637              
638             sub pread ($\$;@) {
639              
640             # Purpose: Performs a sysread w/locking
641             # Returns: Integer/undef
642             # Usage: $bytes = pread($filename, $text, $length);
643             # Usage: $bytes = pread($filename, $text, $length, $offset);
644              
645 244     244 1 1579 my $filename = shift;
646 244         334 my $sref = shift;
647 244         311 my $rlen = shift;
648 244         326 my $offset = shift;
649 244         430 my $nolock = shift;
650 244         451 my ( $fh, $rv );
651              
652 244         647 pdebug( 'entering w/(%s)(%s)(%s)(%s)',
653             PDLEVEL2, $filename, $sref, $rlen, $offset );
654 244         625 pIn();
655              
656 244 50       517 if ( defined $filename ) {
657              
658             # Opportunistically open a file handle if needed,
659             # otherwise, just retrieve the existing file handle
660 244         501 $fh = popen( $filename, O_RDONLY );
661              
662             # Smoke 'em if you got'em...
663 244 100       552 if ( defined $fh ) {
664 241 50 66     751 if ( $nolock or pflock( $filename, LOCK_SH ) ) {
665 241 100       678 $rlen = PIOBLKSIZE unless defined $rlen;
666 241 50       470 $offset = 0 unless defined $offset;
667 241         3195 $rv = sysread $fh, $$sref, $rlen, $offset;
668 241 100       853 if ( defined $rv ) {
669 239         806 pdebug( 'read %d bytes', PDLEVEL2, $rv );
670             } else {
671 2         10 Paranoid::ERROR =
672             pdebug( 'failed to read from file handle: %s',
673             PDLEVEL1, $! );
674             }
675 241 100       853 pflock( $filename, LOCK_UN ) unless $nolock;
676             }
677             }
678             }
679              
680 244         651 pOut();
681 244         589 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
682              
683 244         753 return $rv;
684             }
685              
686             sub pnlread ($\$;@) {
687              
688             # Purpose: Wrapper for pread
689             # Returns: RV of pread
690             # Usage: $bytes = pnlread($filename, $text, $length);
691             # Usage: $bytes = pnlread($filename, $text, $length, $offset);
692              
693 1     1 1 4 my $filename = shift;
694 1         2 my $sref = shift;
695 1         2 my $rlen = shift;
696 1         2 my $offset = shift;
697              
698 1         5 return pread( $filename, $$sref, $rlen, $offset, 1 );
699             }
700              
701             sub ptruncate {
702              
703             # Purpose: Truncates the specified file
704             # Returns: RV of truncate
705             # Usage: $rv = ptruncate($filename);
706             # Usage: $rv = ptruncate($filename, $pos);
707              
708 1     1 1 4 my $filename = shift;
709 1         4 my $pos = shift;
710 1         3 my ( $rv, $fh, $cpos );
711              
712 1         5 pdebug( 'entering w/(%s)(%s)', PDLEVEL2, $filename, $pos );
713 1         10 pIn();
714              
715 1 50       5 if ( defined $filename ) {
716 1 50       4 $pos = 0 unless defined $pos;
717 1         4 $fh = popen( $filename, O_RDWR | O_CREAT );
718              
719             # Smoke 'em if you got'em...
720 1 50       5 if ( defined $fh ) {
721 1 50       4 if ( pflock( $filename, LOCK_EX ) ) {
722 1         10 $cpos = sysseek $fh, 0, SEEK_CUR;
723 1         64 $rv = truncate $fh, $pos;
724 1 50       6 if ($rv) {
725 1 50       6 sysseek $fh, $pos, SEEK_SET if $cpos > $pos;
726             } else {
727 0         0 Paranoid::ERROR =
728             pdebug( 'failed to truncate file: %s', PDLEVEL1, $! );
729             }
730 1         3 pflock( $filename, LOCK_UN );
731             }
732             }
733             }
734              
735 1         12 pOut();
736 1         9 pdebug( 'leaving w/rv: %s', PDLEVEL2, $rv );
737              
738 1         12 return $rv;
739             }
740              
741             END {
742              
743             # Attempt to clean close all filehandles
744 36     36   56107855 pcloseAll();
745             }
746              
747             1;
748              
749             __END__