File-At
view release on metacpan or search on metacpan
lib/File/At.pm view on Meta::CPAN
#!/usr/bin/env perl
package File::At;
use common::sense;
use FFI::Platypus 2.00;
use Fcntl qw(:DEFAULT :mode);
use Exporter 'import';
use vars qw(@EXPORT @EXPORT_OK);
our $VERSION = '0.01';
BEGIN {
# constants
push(@EXPORT_OK, qw(
AT_FDCWD AT_SYMLINK_NOFOLLOW AT_SYMLINK_FOLLOW
AT_EACCESS AT_REMOVEDIR AT_EMPTY_PATH
RENAME_NOREPLACE RENAME_EXCHANGE RENAME_WHITEOUT
)
);
# helpers
push(@EXPORT_OK,qw( dir open_fd_at open_fh_at ));
# raw bindings (callable directly if you want)
push(@EXPORT_OK,qw(
openat fstatat unlinkat mkdirat mknodat
mkfifoat fchmodat fchownat utimensat linkat
symlinkat readlinkat renameat renameat2 faccessat
futimesat
)
);
};
#----------------------------------------------------------------------
# Constants (from linux/fcntl.h and friends)
#----------------------------------------------------------------------
use constant {
AT_FDCWD => -100,
AT_SYMLINK_NOFOLLOW => 0x100,
AT_EACCESS => 0x200,
AT_REMOVEDIR => 0x200, # overlaps on purpose
AT_SYMLINK_FOLLOW => 0x400,
AT_EMPTY_PATH => 0x1000,
RENAME_NOREPLACE => 0x1,
RENAME_EXCHANGE => 0x2,
RENAME_WHITEOUT => 0x4,
};
#----------------------------------------------------------------------
# FFI bootstrap
#----------------------------------------------------------------------
my $ffi = FFI::Platypus->new( api => 1 );
$ffi->lib(undef); # libc
# Map common C typedefs so we can use their names in signatures
eval { $ffi->type('uint' => 'mode_t');};
eval { $ffi->type('uint' => 'uid_t'); };
eval { $ffi->type('uint' => 'gid_t'); };
eval { $ffi->type('ulong' => 'dev_t'); };
#----------------------------------------------------------------------
# Raw *at() bindings
# These are direct libc calls; they follow the C prototypes.
#----------------------------------------------------------------------
# int openat(int dirfd, const char *pathname, int flags, mode_t mode);
$ffi->attach( openat => ['int','string','int','mode_t'] => 'int' );
# int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags);
$ffi->attach( fstatat => ['int','string','opaque','int'] => 'int' );
# int unlinkat(int dirfd, const char *pathname, int flags);
$ffi->attach( unlinkat => ['int','string','int'] => 'int' );
# int mkdirat(int dirfd, const char *pathname, mode_t mode);
$ffi->attach( mkdirat => ['int','string','mode_t'] => 'int' );
# int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
$ffi->attach( mknodat => ['int','string','mode_t','dev_t'] => 'int' );
# int mkfifoat(int dirfd, const char *pathname, mode_t mode);
$ffi->attach( mkfifoat => ['int','string','mode_t'] => 'int' );
# int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
$ffi->attach( fchmodat => ['int','string','mode_t','int'] => 'int' );
# int fchownat(int dirfd, const char *pathname,
# uid_t owner, gid_t group, int flags);
$ffi->attach( fchownat => ['int','string','uid_t','gid_t','int'] => 'int' );
# int utimensat(int dirfd, const char *pathname,
# const struct timespec times[2], int flags);
$ffi->attach( utimensat => ['int','string','opaque','int'] => 'int' );
# int linkat(int olddirfd, const char *oldpath,
# int newdirfd, const char *newpath, int flags);
$ffi->attach( linkat => ['int','string','int','string','int'] => 'int' );
# int symlinkat(const char *target, int newdirfd, const char *linkpath);
$ffi->attach( symlinkat => ['string','int','string'] => 'int' );
# ssize_t readlinkat(int dirfd, const char *pathname,
# char *buf, size_t bufsiz);
$ffi->attach( readlinkat => ['int','string','opaque','size_t'] => 'ssize_t' );
# int renameat(int olddirfd, const char *oldpath,
# int newdirfd, const char *newpath);
$ffi->attach( renameat => ['int','string','int','string'] => 'int' );
# int renameat2(int olddirfd, const char *oldpath,
# int newdirfd, const char *newpath,
# unsigned int flags);
eval {
$ffi->attach( renameat2 => ['int','string','int','string','uint'] => 'int' );
1;
} or do {
# Older libcs may not have renameat2; leave symbol undefined in that case.
};
# int faccessat(int dirfd, const char *pathname, int mode, int flags);
$ffi->attach( faccessat => ['int','string','int','int'] => 'int' );
# int futimesat(int dirfd, const char *pathname,
# const struct timeval times[2]);
eval {
$ffi->attach( futimesat => ['int','string','opaque'] => 'int' );
1;
} or do {
# May be missing on some platforms; ignore.
};
#----------------------------------------------------------------------
# Directory handle helper object
#----------------------------------------------------------------------
{
package File::At::Dir;
use common::sense;
sub new {
my ($class, $path) = @_;
opendir(my $dh, $path) or die "opendir($path): $!";
my $fd = fileno($dh);
die "File::At::Dir: no fd for $path" unless defined $fd;
bless { path => $path, dh => $dh, fd => $fd }, $class;
}
sub fd { $_[0]{fd} }
sub path { $_[0]{path} }
( run in 0.568 second using v1.01-cache-2.11-cpan-71847e10f99 )