+## check field values
+
+# returns a warning message if $field isn't a valid string representation
+# of an integer, or if the resulting integer is out of the specified range
+sub validate_integer_field ($$$$) {
+ my $field = shift;
+ my $field_name = shift;
+ my $min = shift;
+ my $max = shift;
+
+ my $msg = "";
+
+ if ( not $field =~ /^-?\d+$/ ) {
+ $msg = " $field_name value contains invalid characters: \"$field\"\n";
+ } else {
+ if ( $field < $min ) {
+ $msg = " $field_name value too low: \"$field\" < $min \n";
+ } elsif ( $field > $max ) {
+ $msg = " $field_name value too high: \"$field\" > $max \n";
+ }
+ }
+ return $msg;
+}
+
+
+# This routine loops through each directory entry in the $info data
+# structure and prints a warning message if tar would abort with an
+# "Unexpected field value in snapshot file" error upon reading this
+# snapshot file.
+#
+# (Note that this specific error message was introduced along with the
+# change to snapshot file format "2", starting with tar v1.16 [or,
+# more precisely, v1.15.91].)
+#
+# The checks here are intended to match those found in the incremen.c
+# source file (as of tar v1.16.1).
+#
+# In that code, the checks are done against pre-processor expressions,
+# as defined in the C header files at compile time. In the routine
+# below, a Perl variable is created for each expression used as part of
+# one of these checks, assigned the value of the related pre-processor
+# expression as found on a Linux 2.6.8/i386 system.
+#
+# It seems likely that these settings will catch most invalid
+# field values found in actual snapshot files on all systems. However,
+# if "tar" is erroring out on a snapshot file that this check routine
+# does not complain about, that probably indicates that the values
+# below need to be adjusted to match those used by "tar" in that
+# particular environment.
+#
+# (Note: the checks here are taken from the code that processes
+# version 2 snapshot files, but to keep things simple we apply those
+# same checks to files having earlier versions -- but only for
+# the fields that actually exist in those input files.)
+
+sub check_field_values ($) {
+ my $info = shift;
+
+ # set up a variable with the value of each pre-processor
+ # expression used for field-value checks in incremen.c
+ # (these values here are from a Linux 2.6.8/i386 system)
+ my $BILLION = 1000000000; # BILLION
+ my $MIN_TIME_T = -2147483648; # TYPE_MINIMUM(time_t)
+ my $MAX_TIME_T = 2147483647; # TYPE_MAXIUMUM(time_t)
+ my $MAX_DEV_T = 4294967295; # TYPE_MAXIUMUM(dev_t)
+ my $MAX_INO_T = 4294967295; # TYPE_MAXIUMUM(ino_t)
+
+
+ my $msg;
+ my $error_found = 0;
+
+ print " Checking field values in snapshot file...\n";
+
+ $snapver = $info->[0];
+
+ $msg = "";
+ $msg .= validate_integer_field($info->[1],
+ 'timestamp_sec', $MIN_TIME_T, $MAX_TIME_T);
+ if ($snapver >= 1) {
+ $msg .= validate_integer_field($info->[2],
+ 'timestamp_nsec', 0, $BILLION-1);
+ }
+ if ( $msg ne "" ) {
+ $error_found = 1;
+ print "\n shapshot file header:\n";
+ print $msg;
+ }
+
+
+ foreach my $dir (@{$info->[3]}) {
+
+ $msg = "";
+
+ $msg .= validate_integer_field($dir->{'nfs'}, 'nfs', 0, 1);
+ if ($snapver >= 1) {
+ $msg .= validate_integer_field($dir->{'timestamp_sec'},
+ 'timestamp_sec', $MIN_TIME_T, $MAX_TIME_T);
+ $msg .= validate_integer_field($dir->{'timestamp_nsec'},
+ 'timestamp_nsec', 0, $BILLION-1);
+ }
+ $msg .= validate_integer_field($dir->{'dev'}, 'dev', 0, $MAX_DEV_T);
+ $msg .= validate_integer_field($dir->{'ino'}, 'ino', 0, $MAX_INO_T);
+
+ if ( $msg ne "" ) {
+ $error_found = 1;
+ print "\n directory: $dir->{'name'}\n";
+ print $msg;
+ }
+ }
+
+ print "\n Snapshot field value check complete" ,
+ $error_found ? "" : ", no errors found" ,
+ ".\n";
+}
+