File Coverage

blib/lib/FFI/C/Stat.pm
Criterion Covered Total %
statement 24 25 96.0
branch 7 8 87.5
condition 2 3 66.6
subroutine 7 7 100.0
pod 1 1 100.0
total 41 44 93.1


line stmt bran cond sub pod time code
1             package FFI::C::Stat;
2              
3 1     1   150948 use strict;
  1         2  
  1         26  
4 1     1   9 use warnings;
  1         1  
  1         60  
5 1     1   18 use 5.008004;
  1         3  
6 1     1   410 use Ref::Util qw( is_ref is_globref is_blessed_ref );
  1         1953  
  1         73  
7 1     1   7 use Carp ();
  1         0  
  1         20  
8 1     1   638 use FFI::Platypus 1.00;
  1         6735  
  1         533  
9              
10             # ABSTRACT: Object-oriented FFI interface to native stat and lstat
11             our $VERSION = '0.03'; # VERSION
12              
13              
14             my $ffi = FFI::Platypus->new( api => 1 );
15             $ffi->bundle; # for accessors / constructor / destructor
16              
17             $ffi->type('object(FFI::C::Stat)', 'stat');
18             if($^O eq 'MSWin32')
19             {
20             $ffi->type('uint' => $_) for qw( uid_t gid_t nlink_t blksize_t blkcnt_t );
21             }
22              
23             $ffi->mangler(sub { "stat__$_[0]" });
24              
25             $ffi->attach( '_stat' => ['string'] => 'opaque' );
26             $ffi->attach( '_fstat' => ['int', ] => 'opaque' );
27             $ffi->attach( '_lstat' => ['string'] => 'opaque' );
28             $ffi->attach( '_new' => [] => 'opaque' );
29              
30              
31             sub new
32             {
33 6     6 1 305233 my($class, $file, %options) = @_;
34              
35 6         9 my $ptr;
36 6 100 66     37 if(is_globref $file)
    100          
    50          
37 1         31 { $ptr = _fstat(fileno($file)) }
38             elsif(!is_ref($file) && defined $file)
39 4 100       120 { $ptr = $options{symlink} ? _lstat($file) : _stat($file) }
40             elsif(!defined $file)
41 1         6 { $ptr = _new() }
42             else
43 0         0 { Carp::croak("Tried to stat something whch is neither a glob reference nor a plain string") }
44              
45 6         53 bless \$ptr, $class;
46             }
47              
48              
49             $ffi->attach( clone => ['opaque'] => 'opaque' => sub {
50             my($xsub, $class, $other) = @_;
51              
52             my $ptr;
53             if(is_blessed_ref $other)
54             {
55             if($other->isa('FFI::C::Stat'))
56             {
57             $ptr = $xsub->($$other);
58             }
59             else
60             {
61             Carp::croak("Not a FFI::C::Struct instance");
62             }
63             }
64             elsif(!is_ref $other)
65             {
66             $ptr = $xsub->($other);
67             }
68             else
69             {
70             Carp::croak("Not an FFI::C::Struct structure or opaque pointer");
71             }
72              
73             bless \$ptr, $class;
74             });
75              
76             $ffi->attach( DESTROY => ['stat'] );
77              
78              
79             $ffi->attach( dev => ['stat'] => 'dev_t' );
80             $ffi->attach( ino => ['stat'] => 'ino_t' );
81             $ffi->attach( mode => ['stat'] => 'mode_t' );
82             $ffi->attach( nlink => ['stat'] => 'nlink_t' );
83             $ffi->attach( uid => ['stat'] => 'uid_t' );
84             $ffi->attach( gid => ['stat'] => 'gid_t' );
85             $ffi->attach( rdev => ['stat'] => 'dev_t' );
86             $ffi->attach( size => ['stat'] => 'off_t' );
87             $ffi->attach( atime => ['stat'] => 'time_t' );
88             $ffi->attach( mtime => ['stat'] => 'time_t' );
89             $ffi->attach( ctime => ['stat'] => 'time_t' );
90              
91             if($^O ne 'MSWin32')
92             {
93             $ffi->attach( blksize => ['stat'] => 'blksize_t' );
94             $ffi->attach( blocks => ['stat'] => 'blkcnt_t' );
95             }
96             else
97             {
98             *blksize = sub { '' };
99             *blocks = sub { '' };
100             }
101              
102             1;
103              
104             __END__