2 package IkiWiki
::Plugin
::filecheck
;
8 my %units=( # size in bytes
37 # ikiwiki, if you find you need larger data quantities, either modify
38 # yourself to add them, or travel back in time to 2008 and kill me.
43 hook
(type
=> "getsetup", id
=> "filecheck", call
=> \
&getsetup
);
59 my $base=$size+0; # force to number
61 foreach my $unit (sort keys %units) {
62 if ($size=~/[0-9\s]\Q$unit\E$/i) {
63 return $base * $units{$unit};
69 # This is provided for other plugins that want to convert back the other way.
73 foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
74 if ($size / $units{$unit} > 0.25) {
75 return (int($size / $units{$unit} * 10)/10).$unit;
78 return $size; # near zero, or negative
81 package IkiWiki
::PageSpec
;
83 sub match_maxsize
($$;@
) {
85 my $maxsize=eval{IkiWiki
::Plugin
::filecheck
::parsesize
(shift)};
87 return IkiWiki
::ErrorReason
->new("unable to parse maxsize (or number too large)");
91 my $file=exists $params{file
} ?
$params{file
} : IkiWiki
::srcfile
($IkiWiki::pagesources
{$page});
92 if (! defined $file) {
93 return IkiWiki
::ErrorReason
->new("file does not exist");
96 if (-s
$file > $maxsize) {
97 return IkiWiki
::FailReason
->new("file too large (".(-s
$file)." > $maxsize)");
100 return IkiWiki
::SuccessReason
->new("file not too large");
104 sub match_minsize
($$;@
) {
106 my $minsize=eval{IkiWiki
::Plugin
::filecheck
::parsesize
(shift)};
108 return IkiWiki
::ErrorReason
->new("unable to parse minsize (or number too large)");
112 my $file=exists $params{file
} ?
$params{file
} : IkiWiki
::srcfile
($IkiWiki::pagesources
{$page});
113 if (! defined $file) {
114 return IkiWiki
::ErrorReason
->new("file does not exist");
117 if (-s
$file < $minsize) {
118 return IkiWiki
::FailReason
->new("file too small");
121 return IkiWiki
::SuccessReason
->new("file not too small");
125 sub match_mimetype
($$;@
) {
130 my $file=exists $params{file
} ?
$params{file
} : IkiWiki
::srcfile
($IkiWiki::pagesources
{$page});
131 if (! defined $file) {
132 return IkiWiki
::ErrorReason
->new("file does not exist");
137 # First, try File::Mimeinfo. This is fast, but doesn't recognise
139 eval q{use File::MimeInfo::Magic};
140 my $mimeinfo_ok=! $@
;
143 my $mimetype=File
::MimeInfo
::Magic
::magic
($file);
146 # Fall back to using file, which has a more complete
148 if (! defined $mimetype) {
149 open(my $file_h, "-|", "file", "-bi", $file);
154 if (! defined $mimetype || $mimetype !~s
/;.*//) {
155 # Fall back to default value.
156 $mimetype=File
::MimeInfo
::Magic
::default($file)
158 if (! defined $mimetype) {
163 my $regexp=IkiWiki
::glob2re
($wanted);
164 if ($mimetype!~$regexp) {
165 return IkiWiki
::FailReason
->new("file MIME type is $mimetype, not $wanted");
168 return IkiWiki
::SuccessReason
->new("file MIME type is $mimetype");
172 sub match_virusfree
($$;@
) {
177 my $file=exists $params{file
} ?
$params{file
} : IkiWiki
::srcfile
($IkiWiki::pagesources
{$page});
178 if (! defined $file) {
179 return IkiWiki
::ErrorReason
->new("file does not exist");
182 if (! exists $IkiWiki::config
{virus_checker
} ||
183 ! length $IkiWiki::config
{virus_checker
}) {
184 return IkiWiki
::ErrorReason
->new("no virus_checker configured");
187 # The file needs to be fed into the virus checker on stdin,
188 # because the file is not world-readable, and if clamdscan is
189 # used, clamd would fail to read it.
190 eval q{use IPC::Open2};
192 open (IN
, "<", $file) || return IkiWiki
::ErrorReason
->new("failed to read file");
195 $SIG{PIPE
} = sub { $sigpipe=1 };
196 my $pid=open2
(\
*CHECKER_OUT
, "<&IN", $IkiWiki::config
{virus_checker
});
197 my $reason=<CHECKER_OUT
>;
199 1 while (<CHECKER_OUT
>);
202 $SIG{PIPE
}="DEFAULT";
203 if ($sigpipe || $?
) {
204 if (! length $reason) {
205 $reason="virus checker $IkiWiki::config{virus_checker}; failed with no output";
207 return IkiWiki
::FailReason
->new("file seems to contain a virus ($reason)");
210 return IkiWiki
::SuccessReason
->new("file seems virusfree ($reason)");
214 sub match_ispage
($$;@
) {
217 if (defined IkiWiki
::pagetype
($filename)) {
218 return IkiWiki
::SuccessReason
->new("file is a wiki page");
221 return IkiWiki
::FailReason
->new("file is not a wiki page");