sub
new {
return
bless
{
'mounts'
=> [],
'devices'
=> {},
'vnodes'
=> {}
},
shift
;
}
sub
statfs {
my
(
$self
,
$start
,
%opts
) =
@_
;
my
$inode
=
$start
;
my
$ret
;
while
(
$inode
->{
'vnode'
} ) {
$inode
=
$inode
->{
'vnode'
};
}
if
(
$opts
{
'exact'
} ) {
$ret
=
$self
->{
'vnodes'
}->{
$inode
};
}
else
{
$ret
=
$self
->{
'devices'
}->{
$inode
->{
'dev'
} };
}
unless
(
$ret
) {
confess(
'Not mounted'
)
unless
$opts
{
'silent'
};
}
return
$ret
;
}
sub
mountlist {
my
(
$self
) =
@_
;
return
@{
$self
->{
'mounts'
} };
}
sub
mount {
my
(
$self
,
$dev
,
$path
,
$mountpoint
,
%data
) =
@_
;
if
(
grep
{
$_
->{
'dev'
} eq
$dev
} @{
$self
->{
'mounts'
} } ) {
confess(
'Already mounted'
);
}
$data
{
'special'
} ||=
scalar
$dev
;
my
$type
=
lc
ref
$dev
;
$type
=~ s/^([a-z_][a-z0-9_]*::)*//;
my
$vnode
= Filesys::POSIX::VFS::Inode->new(
$mountpoint
,
$dev
->{
'root'
} );
$mountpoint
->{
'vnode'
} =
$vnode
;
$dev
->{
'root'
}->{
'vnode'
} =
$vnode
;
my
$mount
= {
'mountpoint'
=>
$mountpoint
,
'root'
=>
$dev
->{
'root'
},
'special'
=>
$data
{
'special'
},
'dev'
=>
$dev
,
'type'
=>
$type
,
'path'
=>
$path
,
'vnode'
=>
$vnode
,
'flags'
=> {
map
{
$_
=>
$data
{
$_
} }
grep
{
$_
ne
'special'
}
keys
%data
}
};
push
@{
$self
->{
'mounts'
} },
$mount
;
$self
->{
'vnodes'
}->{
$vnode
} =
$mount
;
$self
->{
'devices'
}->{
$dev
} =
$mount
;
return
$self
;
}
sub
vnode {
my
(
$self
,
$start
) =
@_
;
my
$inode
=
$start
;
return
undef
unless
$inode
;
while
(
$inode
->{
'vnode'
} ) {
$inode
=
$inode
->{
'vnode'
};
}
my
$mount
=
$self
->{
'devices'
}->{
$inode
->{
'dev'
} };
if
(
$mount
->{
'flags'
}->{
'noexec'
} ) {
$inode
->{
'mode'
} &= ~
$S_IX
;
}
if
(
$mount
->{
'flags'
}->{
'nosuid'
} ) {
$inode
->{
'mode'
} &= ~
$S_ISUID
;
}
foreach
(
qw/uid gid/
) {
if
(
defined
$mount
->{
'flags'
}->{
$_
} ) {
$inode
->{
$_
} =
$mount
->{
'flags'
}->{
$_
};
}
}
return
$inode
;
}
sub
unmount {
my
(
$self
,
$mount
) =
@_
;
foreach
( @{
$self
->{
'mounts'
} } ) {
next
if
$_
==
$mount
;
confess(
'Device or resource busy'
)
if
$_
->{
'mountpoint'
}->{
'dev'
} ==
$mount
->{
'dev'
};
}
for
(
my
$i
= 0;
$self
->{
'mounts'
}->[
$i
];
$i
++ ) {
next
unless
$self
->{
'mounts'
}->[
$i
] eq
$mount
;
splice
@{
$self
->{
'mounts'
} },
$i
;
last
;
}
delete
$mount
->{
'mountpoint'
}->{
'vnode'
};
delete
$mount
->{
'root'
}->{
'vnode'
};
delete
$self
->{
'vnodes'
}->{
$mount
->{
'vnode'
} };
delete
$self
->{
'devices'
}->{
$mount
->{
'dev'
} };
return
$self
;
}
1;