X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/78e34fbdc255fd3f71f5b43ce1acd1fa0678e1ce..c47839389abb8e21a94606a2c105e5c1ecf6ed32:/IkiWiki/Plugin/filecheck.pm?ds=inline

diff --git a/IkiWiki/Plugin/filecheck.pm b/IkiWiki/Plugin/filecheck.pm
index 6f71be301..9992f2c26 100644
--- a/IkiWiki/Plugin/filecheck.pm
+++ b/IkiWiki/Plugin/filecheck.pm
@@ -3,9 +3,9 @@ package IkiWiki::Plugin::filecheck;
 
 use warnings;
 use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
 
-my %units=( #{{{	# size in bytes
+my %units=(		# size in bytes
 	B		=> 1,
 	byte		=> 1,
 	KB		=> 2 ** 10,
@@ -37,9 +37,21 @@ my %units=( #{{{	# size in bytes
 	# ikiwiki, if you find you need larger data quantities, either modify
 	# yourself to add them, or travel back in time to 2008 and kill me.
 	#   -- Joey
-); #}}}
+);
 
-sub parsesize ($) { #{{{
+sub import {
+	hook(type => "getsetup", id => "filecheck",  call => \&getsetup);
+}
+
+sub getsetup () {
+	return
+		plugin => {
+			safe => 1,
+			rebuild => undef,
+		},
+}
+
+sub parsesize ($) {
 	my $size=shift;
 
 	no warnings;
@@ -51,9 +63,10 @@ sub parsesize ($) { #{{{
 		}
 	}
 	return $base;
-} #}}}
+}
 
-sub humansize ($) { #{{{
+# This is provided for other plugins that want to convert back the other way.
+sub humansize ($) {
 	my $size=shift;
 
 	foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
@@ -62,21 +75,21 @@ sub humansize ($) { #{{{
 		}
 	}
 	return $size; # near zero, or negative
-} #}}}
+}
 
 package IkiWiki::PageSpec;
 
-sub match_maxsize ($$;@) { #{{{
+sub match_maxsize ($$;@) {
 	my $page=shift;
-	my $maxsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
+	my $maxsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)};
 	if ($@) {
-		return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
+		return IkiWiki::ErrorReason->new("unable to parse maxsize (or number too large)");
 	}
 
 	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
 	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
+		return IkiWiki::ErrorReason->new("file does not exist");
 	}
 
 	if (-s $file > $maxsize) {
@@ -85,19 +98,19 @@ sub match_maxsize ($$;@) { #{{{
 	else {
 		return IkiWiki::SuccessReason->new("file not too large");
 	}
-} #}}}
+}
 
-sub match_minsize ($$;@) { #{{{
+sub match_minsize ($$;@) {
 	my $page=shift;
-	my $minsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
+	my $minsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)};
 	if ($@) {
-		return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
+		return IkiWiki::ErrorReason->new("unable to parse minsize (or number too large)");
 	}
 
 	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
 	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
+		return IkiWiki::ErrorReason->new("file does not exist");
 	}
 
 	if (-s $file < $minsize) {
@@ -106,51 +119,68 @@ sub match_minsize ($$;@) { #{{{
 	else {
 		return IkiWiki::SuccessReason->new("file not too small");
 	}
-} #}}}
+}
 
-sub match_mimetype ($$;@) { #{{{
+sub match_mimetype ($$;@) {
 	my $page=shift;
 	my $wanted=shift;
 
 	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
 	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
+		return IkiWiki::ErrorReason->new("file does not exist");
 	}
 
-	# Use ::magic to get the mime type, the idea is to only trust
-	# data obtained by examining the actual file contents.
+	# Get the mime type.
+	#
+	# First, try File::Mimeinfo. This is fast, but doesn't recognise
+	# all files.
 	eval q{use File::MimeInfo::Magic};
-	if ($@) {
-		return IkiWiki::FailReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
+	my $mimeinfo_ok=! $@;
+	my $mimetype;
+	if ($mimeinfo_ok) {
+		my $mimetype=File::MimeInfo::Magic::magic($file);
 	}
-	my $mimetype=File::MimeInfo::Magic::magic($file);
+
+	# Fall back to using file, which has a more complete
+	# magic database.
 	if (! defined $mimetype) {
-		$mimetype="unknown";
+		open(my $file_h, "-|", "file", "-bi", $file);
+		$mimetype=<$file_h>;
+		chomp $mimetype;
+		close $file_h;
+	}
+	if (! defined $mimetype || $mimetype !~s /;.*//) {
+		# Fall back to default value.
+		$mimetype=File::MimeInfo::Magic::default($file)
+			if $mimeinfo_ok;
+		if (! defined $mimetype) {
+			$mimetype="unknown";
+		}
 	}
 
 	my $regexp=IkiWiki::glob2re($wanted);
-	if ($mimetype!~/^$regexp$/i) {
+	if ($mimetype!~$regexp) {
 		return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
 	}
 	else {
 		return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
 	}
-} #}}}
+}
 
-sub match_virusfree ($$;@) { #{{{
+sub match_virusfree ($$;@) {
 	my $page=shift;
 	my $wanted=shift;
 
 	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page});
 	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
+		return IkiWiki::ErrorReason->new("file does not exist");
 	}
 
 	if (! exists $IkiWiki::config{virus_checker} ||
 	    ! length $IkiWiki::config{virus_checker}) {
-		return IkiWiki::FailReason->new("no virus_checker configured");
+		return IkiWiki::ErrorReason->new("no virus_checker configured");
 	}
 
 	# The file needs to be fed into the virus checker on stdin,
@@ -158,7 +188,7 @@ sub match_virusfree ($$;@) { #{{{
 	# used, clamd would fail to read it.
 	eval q{use IPC::Open2};
 	error($@) if $@;
-	open (IN, "<", $file) || return IkiWiki::FailReason->new("failed to read file");
+	open (IN, "<", $file) || return IkiWiki::ErrorReason->new("failed to read file");
 	binmode(IN);
 	my $sigpipe=0;
 	$SIG{PIPE} = sub { $sigpipe=1 };
@@ -178,9 +208,9 @@ sub match_virusfree ($$;@) { #{{{
 	else {
 		return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
 	}
-} #}}}
+}
 
-sub match_ispage ($$;@) { #{{{
+sub match_ispage ($$;@) {
 	my $filename=shift;
 
 	if (defined IkiWiki::pagetype($filename)) {
@@ -189,4 +219,4 @@ sub match_ispage ($$;@) { #{{{
 	else {
 		return IkiWiki::FailReason->new("file is not a wiki page");
 	}
-} #}}}
+}