sub
new {
my
$class
=
shift
;
my
$self
=
bless
({
@_
},
$class
);
return
$self
;
}
sub
cwd {
return
Cwd::cwd();
}
sub
fileparse {
shift
(
@_
);
return
File::Basename::fileparse(
@_
);
}
sub
catfile {
shift
(
@_
);
return
File::Spec->catfile(
@_
);
}
sub
available_properties {
my
(
$self
,
$path
,
$args
) =
@_
;
$path
= decode(
'UTF-8'
,
$path
);
utf8::upgrade(
$path
);
my
@keys
;
if
(
$path
){
my
%properties
;
for
(@{
$self
->list(
$path
) }){
for
my
$key
(
keys
%$_
){
$properties
{
$key
} = 1;
}
}
@keys
=
keys
%properties
;
return
\
@keys
;
}
return
[
'MIME::mediaType'
,
'MIME::subType'
,
'MIME::Type'
,
'MIME::Description'
,
'Filesystem::dev'
,
'Filesystem::inode'
,
'Filesystem::mode'
,
'Filesystem::nlink'
,
'Filesystem::uid'
,
'Filesystem::gid'
,
'Filesystem::rdef'
,
'Filesystem::Size'
,
'Filesystem::Accessed'
,
'Filesystem::Modified'
,
'Filesystem::Changed'
,
'Filesystem::Blocksize'
,
'Filesystem::Blocks'
,
'Filesystem::Type'
,
'Filesystem::Directory'
,
'Filesystem::Path'
,
'Filesystem::Filename'
,
'Filesystem::Basename'
,
'Filesystem::Suffix'
,
'Filesystem::Hidden'
,
'Filesystem::Xattr'
,
];
}
my
$regex_dotfile
=
qr/^\./
;
my
$regex_updir
=
qr/\/
\.\.$/;
my
$regex_filesystem
=
qr/^Filesystem::/
;
my
$regex_filesystem_contains
=
qr/\bFilesystem::/
;
my
$regex_mime_contains
=
qr/\bMIME::/
;
my
$regex_xattr
=
qr/^Extended Attributes::/
;
my
$regex_xattr_contains
=
qr/\bExtended Attributes::/
;
sub
properties {
my
(
$self
,
$path
,
$wishlist
) =
@_
;
$wishlist
=
undef
if
$wishlist
&&
@$wishlist
== 0;
my
(
@filesystem
,
@stat
,
@fileparse
,
$type
,
$type_human
);
if
(!
$wishlist
||
'Filesystem'
~~
@$wishlist
||
"@$wishlist"
=~
$regex_filesystem_contains
||
'MIME'
~~
@$wishlist
){
@stat
= CORE::
lstat
(
$path
);
if
(-l _){
@filesystem
= (
'Filesystem::Link'
=>
'Symlink'
,
'Filesystem::LinkTarget'
=> CORE::
readlink
(
$path
),
);
@stat
= CORE::
stat
(
$path
);
}
(
$type
,
$type_human
) = inode_type_from_mode(
$stat
[2]);
@fileparse
= File::Basename::fileparse(
$path
,
qr/\.[^.]*/
);
my
$filename
= (
$fileparse
[2] ?
$fileparse
[0].
$fileparse
[2] :
$fileparse
[0]);
@filesystem
= (
'Filesystem::dev'
=>
$stat
[0],
'Filesystem::inode'
=>
$stat
[1],
'Filesystem::mode'
=>
$stat
[2],
'Filesystem::nlink'
=>
$stat
[3],
'Filesystem::uid'
=>
$stat
[4],
'Filesystem::gid'
=>
$stat
[5],
'Filesystem::rdef'
=>
$stat
[6],
'Filesystem::Size'
=>
$stat
[7],
'Filesystem::Accessed'
=>
$stat
[8],
'Filesystem::Modified'
=>
$stat
[9],
'Filesystem::Changed'
=>
$stat
[10],
'Filesystem::Blocksize'
=>
$stat
[11],
'Filesystem::Blocks'
=>
$stat
[12],
'Filesystem::Type'
=>
$type_human
,
'Filesystem::Path'
=>
$path
,
'Filesystem::Directory'
=>
$fileparse
[1],
'Filesystem::Filename'
=>
$filename
,
'Filesystem::Basename'
=>
$fileparse
[0],
'Filesystem::Suffix'
=> (
$fileparse
[2] ?
substr
(
$fileparse
[2],1) :
''
),
'Filesystem::Hidden'
=>
$filename
ne
'..'
&&
$filename
=~
$regex_dotfile
? 1 : 0,
@filesystem
);
}
my
@mime
;
if
(!
$wishlist
||
'MIME'
~~
@$wishlist
||
"@$wishlist"
=~
$regex_mime_contains
){
if
(
$type
eq
'-'
&&
$fileparse
[2] &&
$stat
[7] != 0){
my
(
$mediaType
,
$subType
,
$mimeDesc
) = type_from_ext(
$fileparse
[2]);
@mime
= (
'MIME::mediaType'
=>
$mediaType
,
'MIME::subType'
=>
$subType
,
'MIME::Type'
=>
$mediaType
.
'/'
.
$subType
);
push
(
@mime
,
'MIME::Description'
=>
$mimeDesc
||
'File'
);
}
elsif
(
$type
eq
'd'
){
@mime
= (
'MIME::mediaType'
=>
'inode'
,
'MIME::subType'
=>
'directory'
,
'MIME::Type'
=>
'inode/directory'
,
'MIME::Description'
=>
'Directory'
);
}
}
my
(
@xattr
,
@xattr_summary
);
if
(!
$wishlist
||
'Extended Attributes'
~~
@$wishlist
||
'Filesystem::Xattr'
~~
@$wishlist
){
my
@keys
=
$self
->listfattr(
$path
);
for
my
$key
(
@keys
){
next
unless
$key
;
push
(
@xattr
,
'Extended Attributes::'
.
$key
=>
$self
->getfattr(
$path
,
$key
) );
}
@xattr_summary
= (
'Filesystem::Xattr'
=>
scalar
(
@keys
) );
}
elsif
(
"@$wishlist"
=~
$regex_xattr_contains
){
my
@keys
=
grep
{ /
$regex_xattr
/ }
@$wishlist
;
s/
$regex_xattr
//
for
@keys
;
for
(
@keys
){
next
unless
$_
;
my
$value
=
$self
->getfattr(
$path
,
$_
) or
next
;
push
(
@xattr
,
'Extended Attributes::'
.
$_
=>
$value
);
}
}
$path
=
$self
->parent(
$path
)
if
$path
=~
$regex_updir
;
my
%properties
= (
@filesystem
,
@xattr_summary
,
@mime
,
@xattr
);
return
\
%properties
;
}
sub
list {
my
(
$self
,
$path
,
$wishlist
) =
@_
;
$path
= decode(
'UTF-8'
,
$path
);
utf8::upgrade(
$path
);
$wishlist
=
undef
if
$wishlist
&&
@$wishlist
== 0;
my
$ok
=
opendir
(
my
$dh
, Cwd::abs_path(
$path
) );
return
bless
([],
'error'
)
unless
$ok
;
my
@items
=
readdir
(
$dh
);
closedir
(
$dh
);
for
(
@items
){
$_
= decode(
'UTF-8'
,
$_
);
utf8::upgrade(
$_
);
}
my
@richlist
;
if
(
$wishlist
&&
"@$wishlist"
eq
'Plain'
){
for
(
@items
){
my
@fileparse
= File::Basename::fileparse(
$path
,
qr/\.[^.]*/
);
my
$filename
= (
$fileparse
[2] ?
$fileparse
[0].
$fileparse
[2] :
$fileparse
[0]);
push
(
@richlist
, {
'Filesystem::Type'
=>
'inode'
,
'Filesystem::Path'
=> File::Spec->catfile(
$path
,
$_
),
'Filesystem::Directory'
=>
$fileparse
[1],
'Filesystem::Filename'
=>
$filename
,
'Filesystem::Basename'
=>
$fileparse
[0],
'Filesystem::Suffix'
=> (
$fileparse
[2] ?
substr
(
$fileparse
[2],1) :
''
),
'Filesystem::Hidden'
=>
$filename
ne
'..'
&&
$filename
=~
$regex_dotfile
? 1 : 0,
});
}
}
else
{
for
(
@items
){
push
(
@richlist
,
$self
->properties( File::Spec->catfile(
$path
,
$_
),
$wishlist
) );
}
}
return
\
@richlist
;
}
sub
inode_type_from_mode {
my
$mode
=
shift
;
my
@ftype
=
qw(. p c ? d ? b ? - ? l ? s ? ? ?)
;
$ftype
[0] =
''
;
if
(
wantarray
){
my
$type
=
$ftype
[(
$mode
& 0170000)>>12];
my
$type_human
;
if
(
$type
eq
'-'
){
$type_human
=
'File'
;
}
elsif
(
$type
eq
'd'
){
$type_human
=
'Directory'
;
}
elsif
(
$type
eq
'l'
){
$type_human
=
'Link'
;
}
elsif
(
$type
eq
'p'
){
$type_human
=
'FIFO'
;
}
elsif
(
$type
eq
'l'
){
$type_human
=
'Character Device'
;
}
elsif
(
$type
eq
'b'
){
$type_human
=
'Block Device'
;
}
elsif
(
$type
eq
'-'
){
$type_human
=
'File'
;
}
elsif
(
$type
eq
's'
){
$type_human
=
'Socket'
;
}
else
{
$type_human
=
'?'
;
}
return
(
$type
,
$type_human
);
}
else
{
return
$ftype
[(
$mode
& 0170000)>>12];
}
}
my
$videosuffixes
=
qr/\.avi$|\.mpeg$|\.mpg$|\.m2v$|\.asf$|\.wmv$|\.mov$|\.rm$|\.flv$|\.ogg$|\.mkv$|\.mp4$|\.h264|\.webm|\.on2|\.3gp$|\.3g2$|\.mxf$|\.m2t$|\.vob$/
i;
my
$imagesuffixes
=
qr/\.ani$|\.cr2$|\.gif$|\.jls$|\.jpeg$|\.jpg$|\.thm$|\.jp2$|\.jpe$|\.jpx$|\.png$|\.pcx$|\.pnm$|\.tif$|\.pbm$|\.pgm$|\.pnm$|\.psd$|\.ppd$|\.ppm$|\.bmp$|\.xbm$|\.xpm$|\.rle$|\.tga$|\.tif$|\.iff$|\.ico$|\.cur$|\.raw$|\.dcr$/
i;
my
$audiosuffixes
=
qr/\.wav$|\.aiff$|\.mp3$|\.ogg$|\.mka$|\.flac$|\.aac$|\.mid$|\.mpa$|\.au$|\.ram$|\.smp$|\.ape$|\.gsm$/
i;
my
$textsuffixes
=
qr/\.txt$|\.py$|\.pl$|\.mk$|\.pod$/
i;
my
$mt
= MIME::Types->new;
my
$regex_dot_first
=
qr/^\./
;
sub
type_from_ext {
my
$suffix
=
shift
;
my
$ext
=
$suffix
=~
$regex_dot_first
?
substr
(
$suffix
,1) :
$suffix
;
my
(
$mediaType
,
$subType
,
$mimeDesc
) = (
'unknown'
,
'unknown'
,
''
);
if
(
$mediaType
=
$mt
->mimeTypeOf(
$suffix
)){
(
$mediaType
,
$subType
) =
split
(/\//,
$mediaType
,2);
}
else
{
if
(
$suffix
=~
$videosuffixes
){
$mediaType
=
'video'
;
}
elsif
(
$suffix
=~
$imagesuffixes
){
$mediaType
=
'image'
;
}
elsif
(
$suffix
=~
$audiosuffixes
){
$mediaType
=
'audio'
;
}
elsif
(
$suffix
=~
$textsuffixes
){
$mediaType
=
'text'
;
}
else
{
$mediaType
=
'unknown'
;
}
}
$ext
=
lc
(
$ext
);
if
(
defined
(
$Wrangler::FileSystem::Layers::exts
{
$ext
})){
if
(
ref
(
$Wrangler::FileSystem::Layers::exts
{
$ext
}) ){
$mimeDesc
=
$Wrangler::FileSystem::Layers::exts
{
$ext
}->[0];
(
$mediaType
,
$subType
) =
split
(/\//,
$Wrangler::FileSystem::Layers::exts
{
$ext
}->[1],2);
}
else
{
$mimeDesc
=
$Wrangler::FileSystem::Layers::exts
{
$ext
};
}
}
else
{
if
(
$mediaType
eq
'audio'
){
$mimeDesc
=
uc
(
$ext
) .
'-'
.
'Audiofile'
;
}
elsif
(
$mediaType
eq
'image'
){
$mimeDesc
=
uc
(
$ext
) .
'-'
.
'Imagefile'
;
}
elsif
(
$mediaType
eq
'video'
){
$mimeDesc
=
uc
(
$ext
) .
'-'
.
'Videofile'
;
}
else
{
$mimeDesc
=
uc
(
$ext
) .
'-'
.
'File'
;
}
}
return
(
$mediaType
,
$subType
,
$mimeDesc
);
}
sub
mount {
my
(
$self
,
%cfg
) =
@_
;
$self
->{driveletter} =
undef
;
$self
->{username} =
$cfg
{username};
$self
->{password} =
$cfg
{password};
}
sub
parent {
shift
(
@_
);
return
Cwd::abs_path(
$_
[0] )
if
$_
[0] =~
$regex_updir
;
return
Cwd::abs_path( File::Spec->catfile(
$_
[0],
'..'
) );
}
sub
test {
my
(
$self
,
$test
,
$path
) =
@_
;
my
$ret
=
eval
(
"-$test '$path'"
);
return
($@) ?
undef
:
$ret
;
}
sub
stat
{
my
(
$self
,
$path
) =
@_
;
return
CORE::
stat
(
$path
);
}
sub
lstat
{
my
(
$self
,
$path
) =
@_
;
return
CORE::
lstat
(
$path
);
}
sub
symlink
{
my
(
$self
,
$old
,
$new
) =
@_
;
return
CORE::
symlink
(
$old
,
$new
);
}
sub
mknod {
my
$self
=
shift
;
return
0
if
-e
$_
[0];
my
$result
=
system
(
'touch'
,
@_
);
return
$result
== 0 ? 1 : 0;
}
sub
delete
{
my
(
$self
,
$path
) =
@_
;
return
((-e
$path
) && (!-d
$path
) && (CORE::
unlink
(
$path
))) ? 1 : 0;
}
sub
mkdir
{
my
(
$self
,
$dir
) =
@_
;
return
2
if
(-d
$dir
);
return
CORE::
mkdir
(
$dir
);
}
sub
rmdir
{
my
(
$self
,
$path
,
$recursive
) =
@_
;
if
(-e
$path
) {
if
(-d
$path
) {
if
(
$recursive
){
return
1
if
(File::Path::rmtree(
$path
));
}
else
{
return
1
if
(CORE::
rmdir
(
$path
));
}
}
}
return
0;
}
sub
trash {
my
$self
=
shift
;
for
(
@_
){
return
0
if
$_
eq
''
; }
my
$result
=
system
(
'gvfs-trash'
,
@_
);
return
$result
== 0 ? 1 : 0;
}
sub
rename
{
my
(
$self
,
$path
,
$new
) =
@_
;
return
CORE::
rename
(
$path
,
$new
);
}
sub
move {
my
$self
=
shift
;
return
0
if
!-e
$_
[0];
my
$result
=
system
(
'mv'
,
@_
);
return
$result
== 0 ? 1 : 0;
}
sub
copy {
my
$self
=
shift
;
return
0
if
!-e
$_
[0];
my
$result
=
system
(
'cp'
,
'-R'
,
@_
);
return
$result
== 0 ? 1 : 0;
}
sub
utime
{
my
(
$self
,
$atime
,
$mtime
,
@path
) =
@_
;
return
CORE::
utime
(
$atime
,
$mtime
,
@path
);
}
sub
listfattr {
my
(
$self
,
$path
) =
@_
;
my
@attr_list
= File::ExtAttr::listfattr(
$path
);
for
(
@attr_list
){
utf8::upgrade(
$_
);
}
return
@attr_list
;
}
sub
getfattr {
my
(
$self
,
$path
,
$key
) =
@_
;
my
$value
= File::ExtAttr::getfattr(
$path
,
$key
, {
namespace
=>
'user'
});
if
(
defined
(
$value
) ){
$value
= decode(
'utf-8'
,
$value
);
utf8::upgrade(
$value
);
}
return
$value
;
}
sub
setfattr {
my
(
$self
,
$path
,
$key
,
$value
) =
@_
;
File::ExtAttr::setfattr(
$path
, encode(
'utf-8'
,
$key
), encode(
'utf-8'
,
$value
), {
namespace
=>
'user'
});
}
sub
delfattr {
my
(
$self
,
$path
,
$key
) =
@_
;
File::ExtAttr::delfattr(
$path
, encode(
'utf-8'
,
$key
), {
namespace
=>
'user'
});
}
1;