sub
mkskelfs {
my
$fs
= Filesys::POSIX->new( Filesys::POSIX::Mem->new );
my
@DIRS
=
qw(
bin dev etc etc/init.d home lib mnt mnt/cdrom root tmp usr var
)
;
my
%DEVICES
= (
'null'
=> [
$S_IFCHR
, 0666, 1, 3 ],
'random'
=> [
$S_IFCHR
, 0666, 1, 8 ],
'urandom'
=> [
$S_IFCHR
, 0666, 1, 9 ],
'zero'
=> [
$S_IFCHR
, 0666, 1, 5 ],
'sda'
=> [
$S_IFBLK
, 0664, 8, 0 ],
'tty'
=> [
$S_IFCHR
, 0666, 5, 0 ],
'tty0'
=> [
$S_IFCHR
, 0600, 4, 0 ],
'tty1'
=> [
$S_IFCHR
, 0600, 4, 1 ],
'tty2'
=> [
$S_IFCHR
, 0600, 4, 2 ],
'tty3'
=> [
$S_IFCHR
, 0600, 4, 3 ],
);
my
%FILES
= (
'/bin/sh'
=> 0755,
'/etc/init.d/rc'
=> 0755
);
foreach
my
$dir
(
@DIRS
) {
$fs
->
mkdir
(
$dir
);
}
foreach
my
$file
(
keys
%FILES
) {
my
$mode
=
$FILES
{
$file
};
my
$fd
=
$fs
->
open
(
$file
,
$O_CREAT
|
$O_WRONLY
,
$mode
);
$fs
->fchmod(
$fd
,
$mode
);
$fs
->
close
(
$fd
);
}
$fs
->
symlink
(
'sh'
,
'/bin/ksh'
);
my
$fd
=
$fs
->
open
(
'/etc/hosts'
,
$O_CREAT
|
$O_WRONLY
);
$fs
->
print
(
$fd
,
"127.0.0.1 localhost\n"
);
$fs
->
print
(
$fd
,
"::1 ip6-localhost ip6-loopback\n"
);
$fs
->
close
(
$fd
);
foreach
my
$device
(
keys
%DEVICES
) {
my
(
$type
,
$mode
,
$major
,
$minor
) = @{
$DEVICES
{
$device
} };
$fs
->mknod(
"/dev/$device"
,
$type
|
$mode
, (
$major
<< 16 ) |
$minor
);
}
return
$fs
;
}
{
my
$fs
= mkskelfs();
throws_ok {
$fs
->mkpath(
'/snapshots/1'
);
$fs
->mount( Filesys::POSIX::Snapshot->new,
'/snapshots/1'
);
}
qr/^Invalid argument/
,
"Filesys::POSIX::Snapshot->new() emits 'Invalid argument' when no 'path' is specified"
;
lives_ok {
$fs
->mkpath(
'/snapshots/2'
);
$fs
->mount(
Filesys::POSIX::Snapshot->new,
'/snapshots/2'
,
'path'
=>
'/'
);
}
"Filesys::POSIX::Snapshot->new() succeeds when 'path' is specified"
;
throws_ok {
$fs
->mkpath(
'/snapshots/3'
);
$fs
->mount(
Filesys::POSIX::Snapshot->new,
'/snapshots/3'
,
'path'
=>
'/dev/null'
);
}
qr/^Not a directory/
,
"Filesys::POSIX::Snapshot->new() emits 'Not a directory' when non-directory 'path' specified"
;
}
{
my
$fs
= mkskelfs();
lives_ok {
$fs
->mkpath(
'/snapshots/1'
);
$fs
->mount(
Filesys::POSIX::Snapshot->new,
'/snapshots/1'
,
'path'
=>
'/'
,
'immediate_dir_copy'
=> 1
);
}
"Filesys::POSIX::Snapshot::Inode->new() lives when FS mounted with 'immediate_dir_copy'"
;
isa_ok(
$fs
->
stat
(
'/snapshots/1/dev'
)->{
'directory'
},
"Filesys::POSIX::Mem::Directory"
,
'/snapshots/1/dev'
);
is(
$fs
->
lstat
(
'/snapshots/1/bin/ksh'
)->
readlink
,
'sh'
,
"Symlinks are copied by Filesys::POSIX::Snapshot"
);
note(
'Preparing to test regular file copy-on-write; using /foo'
);
$fs
->touch(
'/file'
);
$fs
->
mkdir
(
'/dir'
);
$fs
->mkpath(
'/snapshots/2'
);
$fs
->mount(
Filesys::POSIX::Snapshot->new,
'/snapshots/2'
,
'path'
=>
'/'
);
note(
'Mounted snapshot of / in /snapshots/2'
);
my
$fd
=
$fs
->
open
(
'/snapshots/2/file'
,
$O_WRONLY
|
$O_APPEND
);
$fs
->
print
(
$fd
,
"foo\n"
);
$fs
->
close
(
$fd
);
note(
'Appended "foo" to /snapshots/2/file'
);
$fd
=
$fs
->
open
(
'/snapshots/2/file'
,
$O_WRONLY
|
$O_APPEND
);
$fs
->
print
(
$fd
,
"bar\n"
);
$fs
->
close
(
$fd
);
$fd
=
$fs
->
open
(
'/snapshots/2/file'
,
$O_RDONLY
);
note(
'Appended "bar" to /snapshots/2/file'
);
my
$len
=
$fs
->
read
(
$fd
,
my
$buf
, 8 );
is(
$len
, 8,
'Read 8 bytes from /snapshots/2/file'
);
is(
$buf
,
"foo\nbar\n"
,
'read() expected data from /snapshots/2/file'
);
$fs
->
close
(
$fd
);
my
$inode
=
$fs
->
stat
(
'/snapshots/2/file'
);
throws_ok {
$inode
->directory;
}
qr/^Not a directory/
,
'Filesys::POSIX::Snapshot::Inode->directory() throws "Not a directory" as appropriate'
;
$fd
=
$fs
->
open
(
'/snapshots/2/etc/hosts'
,
$O_RDONLY
);
ok( !
defined
$fs
->fstat(
$fd
)->{
'bucket'
},
'Filesys::POSIX::Snapshot::Inode->open() avoids copy-on-write in RO mode'
);
$fs
->
close
(
$fd
);
}