Perl x Open Food Facts Hackathon: Paris, France - May 24-25 Learn more

use strict;
use Carp qw/confess/;
=head1 NAME
Filesys::POSIX::Userland
=head1 DESCRIPTION
This module is a mixin imported by Filesys::POSIX into its own namespace, and
provides a variety of higher-level calls to supplement the normal suite of
system calls provided in Filesys::POSIX itself.
=head1 METHODS
=over
=cut
sub _find_inode_path {
my ( $self, $start ) = @_;
my $inode = $self->{'vfs'}->vnode($start);
my @ret;
while ( my $dir = $self->{'vfs'}->vnode($inode)->{'parent'} ) {
my $directory = $dir->directory;
foreach ( $directory->list ) {
next if $_ eq '.' || $_ eq '..';
next unless $self->{'vfs'}->vnode( $directory->get($_) ) == $self->{'vfs'}->vnode($inode);
push @ret, $_;
$inode = $dir;
}
}
return '/' . join( '/', reverse @ret );
}
=item $fs->mkpath($path)
=item $fs->mkpath($path, $mode)
Similar to the C<-p> flag that can be passed to mkdir(1), this method attempts
to create a hierarchy of directories specified in $path. Each path component
created will be made with the mode specified by $mode, if any, if a directory
in that location does not already exist. Exceptions will be thrown if one of
the items along the path hierarchy exists but is not a directory.
A default mode of 0777 is assumed; only the permissions field of $mode is used
when it is specified. In both cases, the mode specified is modified with
exclusive OR by the current umask value.
=cut
sub mkpath {
my ( $self, $path, $mode ) = @_;
my $perm = $mode ? $mode & ( $S_IPERM | $S_IPROT ) : $S_IPERM ^ $self->{'umask'};
my $hier = Filesys::POSIX::Path->new($path);
my $dir = $self->{'cwd'};
while ( $hier->count ) {
my $item = $hier->shift;
unless ($item) {
$dir = $self->{'root'};
next;
}
my $directory = $dir->directory;
my $inode = $self->{'vfs'}->vnode( $directory->get($item) );
if ($inode) {
$dir = $inode;
}
else {
$dir = $dir->child( $item, $perm | $S_IFDIR );
}
}
}
=item $fs->getcwd()
Returns a string representation of the current working directory.
=cut
sub getcwd {
my ($self) = @_;
return $self->_find_inode_path( $self->{'cwd'} );
}
=item $fs->realpath($path)
Returns a string representation of the full, true and original path of the
inode specified by $path.
Using $fs->stat(), the inode of $path is resolved, then starting at that inode,
each subsequent inode's name is found from its parent and appended to a list of
path components.
=cut
sub realpath {
my ( $self, $path ) = @_;
my $inode = $self->stat($path);
return $self->_find_inode_path($inode);
}
=item $fs->opendir($path)
Returns a newly opened directory handle for the item pointed to by $path.
Using other methods in this module, the directory can be read and closed.
=cut
sub opendir {
my ( $self, $path ) = @_;
my $directory = $self->stat($path)->directory;
$directory->open;
return $directory;
}
=item $fs->readdir($directory)
Read the next member of the directory passed. Returns undef if there are no
more entries to be read.
=cut
sub readdir {
my ( $self, $directory ) = @_;
return $directory->read unless wantarray;
my @ret;
while ( my $item = $directory->read ) {
push @ret, $item;
}
return @ret;
}
=item $fs->closedir($directory)
Closes the directory handle for reading.
=cut
sub closedir {
my ( $self, $directory ) = @_;
return $directory->close;
}
=item $fs->touch($path)
Acts like the userland utility touch(1). Uses $fs->open() with the $O_CREAT
flag to open the file specified by $path, and immediately closes the file
descriptor returned. This causes an update of the inode modification time for
existing files, and the creation of new, empty files otherwise.
=cut
sub touch {
my ( $self, $path ) = @_;
my $fd = $self->open( $path, $O_CREAT );
$self->close($fd);
}
=back
=cut
1;