—————————package
Filesys::POSIX;
use
strict;
use
warnings;
use
Filesys::POSIX::Bits;
use
Filesys::POSIX::Path ();
=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;