+# initializes the global %snapshot_field_ranges hash, based on the "-a"
+# command-line option if given, otherwise based on the "archname" of
+# the current system.
+#
+# Each value in the hash is a two-element array containing the minimum
+# and maximum allowed values, respectively, for that field in the snapshot
+# file. GNU tar's allowed values for each architecture are determined
+# in the incremen.c source file, where the TYPE_MIN and TYPE_MAX
+# pre-processor expressions are used to determine the range that can be
+# expressed by the C data type used for each field; the values in the
+# array defined below should match those calculations. (For tar v1.27
+# and later, the valid ranges for a particular tar binary can easily
+# be determined using the "tar --show-snapshot-field-ranges" command.)
+
+sub choose_architecture ($) {
+ my $opt_a = shift;
+
+ my $arch = $opt_a ? $opt_a : $Config{'archname'};
+
+ # These ranges apply to Linux 2.4/2.6 on iX86 systems, but are used
+ # by default on unrecognized/unsupported systems, too.
+ %iX86_linux_field_ranges = (
+ timestamp_sec => [ -2147483648, 2147483647 ], # min/max of time_t
+ timestamp_nsec => [ 0, 999999999 ], # 0 to BILLION-1
+ nfs => [ 0, 1 ],
+ dev => [ 0, 18446744073709551615 ], # min/max of dev_t
+ ino => [ 0, 4294967295 ], # min/max of ino_t
+ );
+
+
+ if ( $arch =~ m/^i[\dxX]86-linux/i ) {
+ %snapshot_field_ranges = %iX86_linux_field_ranges;
+ print "Checking snapshot field values using \"iX86-linux\" ranges.\n\n";
+ } elsif ( $arch =~ m/^x86_64-linux/i ) {
+ %snapshot_field_ranges = (
+ timestamp_sec => [ -9223372036854775808, 9223372036854775807 ],
+ timestamp_nsec => [ 0, 999999999 ],
+ nfs => [ 0, 1 ],
+ dev => [ 0, 18446744073709551615 ],
+ ino => [ 0, 18446744073709551615 ],
+ );
+ print "Checking snapshot field values using \"x86_64-linux\" ranges.\n\n";
+ } elsif ( $arch =~ m/^IA64.ARCHREV_0/i ) {
+ # HP/UX running on Itanium/ia64 architecture
+ %snapshot_field_ranges = (
+ timestamp_sec => [ -2147483648, 2147483647 ],
+ timestamp_nsec => [ 0, 999999999 ],
+ nfs => [ 0, 1 ],
+ dev => [ -2147483648, 2147483647 ],
+ ino => [ 0, 4294967295 ],
+ );
+ print "Checking snapshot field values using \"IA64.ARCHREV_0\" (HP/UX) ranges.\n\n";
+ } else {
+ %snapshot_field_ranges = %iX86_linux_field_ranges;
+ print "Unrecognized architecture \"$arch\"; defaulting to \"iX86-linux\".\n";
+ print "(Use -a option to override.)\n" unless $opt_a;
+ print "\n";
+ }
+
+ if ( ref(1) ne "" ) {
+ print "(\"bignum\" mode is in effect; skipping 64-bit-integer check.)\n\n"
+ } else {
+ # find the largest max value in the current set of ranges
+ my $maxmax = 0;
+ for $v (values %snapshot_field_ranges ) {
+ $maxmax = $v->[1] if ($v->[1] > $maxmax);
+ }
+
+ # "~0" translates into a platform-native integer with all bits turned
+ # on -- that is, the largest value that can be represented as
+ # an integer. We print a warning if our $maxmax value is greater
+ # than that largest integer, since in that case Perl will switch
+ # to using floats for those large max values. The wording of
+ # the message assumes that the only way this situation can exist
+ # is that the platform uses 32-bit integers but some of the
+ # snapshot-file fields have 64-bit values.
+ if ( ~0 < $maxmax ) {
+ print <<EOF
+Note: this version of Perl uses 32-bit integers, which means that it
+ will switch to using floating-point numbers when checking the ranges
+ for 64-bit snapshot-file fields. This normally will work fine, but
+ might fail to detect cases where the value in the input field value is
+ only slightly out of range. (For example, a "9223372036854775808"
+ might not be recognized as being larger than 9223372036854775807.)
+ If you suspect you are experiencing this problem, you can try running
+ the program using the "-Mbignum" option, as in
+ \$ perl $0 -Mbignum -c [FILES]
+ (but doing so will make the program run *much* slower).
+
+EOF
+ }
+ }
+
+
+}
+
+# returns a warning message if $field_value isn't a valid string
+# representation of an integer, or if the resulting integer is out of range
+# defined by the two-element array retrieved using up the $field_name key in
+# the global %snapshot_field_ranges hash.
+sub validate_integer_field ($$) {
+ my $field_value = shift;