From b6baea64d103ee59950ac8f779ba2c307aeb71f1 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Thu, 20 Sep 2001 08:44:12 +0000 Subject: (MAX_ADDRESS_LENGTH, pseudo_offset, format_address, n_bytes_to_skip, skip, format_address_none, format_address_std, format_address_paren, format_address_label, write_block, parse_old_offset, dump, dump_strings, main): Use uintmax_t, not off_t, for file addresses, so that we can handle multiple large files even if the sum of their sizes exceeds off_t limits. (print_s_char, print_char, print_s_short, print_short, print_int, print_long, print_long_long, print_float, print_double, print_long_double, dump_hexl_mode_trailer, print_named_ascii, print_ascii, decode_one_format): Use size_t, not off_t, for in-memory byte counts. (end_offset): New var. (dump, dump_strings): Use it. (main): Set it, but check for overflow while doing so. (skip): Report an error if an in-range lseek fails on a regular file, as something's seriously wrong. Check for negative regular file sizes (possible with some broken NFS implementations). (parse_old_offset): Now all offsets are valid, so return a success boolean and take a pointer to an offset as an argument. All callers changed. (dump_strings): Check for overflow when computing end_offset - string_min. (main): Remove OFF_T_MAX checks that are no longer needed. Don't bother assigning through temporary when there's no size limit to check. --- src/od.c | 186 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 90 insertions(+), 96 deletions(-) (limited to 'src/od.c') diff --git a/src/od.c b/src/od.c index 1bb0a720e..fdcbd143b 100644 --- a/src/od.c +++ b/src/od.c @@ -153,9 +153,10 @@ static const char *const charname[33] = /* Address base (8, 10 or 16). */ static int address_base; -/* The number of octal digits required to represent the largest off_t value. */ +/* The number of octal digits required to represent the largest + address value. */ #define MAX_ADDRESS_LENGTH \ - ((sizeof (off_t) * CHAR_BIT + CHAR_BIT - 1) / 3) + ((sizeof (uintmax_t) * CHAR_BIT + CHAR_BIT - 1) / 3) /* Width of a normal address. */ static int address_pad_len; @@ -173,22 +174,24 @@ static int flag_pseudo_start; /* The difference between the old-style pseudo starting address and the number of bytes to skip. */ -static off_t pseudo_offset; +static uintmax_t pseudo_offset; /* Function that accepts an address and an optional following char, and prints the address and char to stdout. */ -static void (*format_address) PARAMS ((off_t, char)); +static void (*format_address) PARAMS ((uintmax_t, char)); /* The number of input bytes to skip before formatting and writing. */ -static off_t n_bytes_to_skip = 0; +static uintmax_t n_bytes_to_skip = 0; -/* When nonzero, MAX_BYTES_TO_FORMAT is the maximum number of bytes - to be read and formatted. Otherwise all input is formatted. */ +/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all + input is formatted. */ static int limit_bytes_to_format = 0; -/* The maximum number of bytes that will be formatted. This - value is used only when LIMIT_BYTES_TO_FORMAT is nonzero. */ -static off_t max_bytes_to_format; +/* The maximum number of bytes that will be formatted. */ +static uintmax_t max_bytes_to_format; + +/* The offset of the first byte after the last byte to be formatted. */ +static uintmax_t end_offset; /* When nonzero and two or more consecutive blocks are equal, format only the first block and output an asterisk alone on the following @@ -364,9 +367,9 @@ lcm (unsigned int u, unsigned int v) } static void -print_s_char (off_t n_bytes, const char *block, const char *fmt_string) +print_s_char (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes; i > 0; i--) { int tmp = (unsigned) *(const unsigned char *) block; @@ -379,9 +382,9 @@ print_s_char (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_char (off_t n_bytes, const char *block, const char *fmt_string) +print_char (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes; i > 0; i--) { unsigned int tmp = *(const unsigned char *) block; @@ -391,9 +394,9 @@ print_char (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_s_short (off_t n_bytes, const char *block, const char *fmt_string) +print_s_short (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (unsigned short); i > 0; i--) { int tmp = (unsigned) *(const unsigned short *) block; @@ -406,9 +409,9 @@ print_s_short (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_short (off_t n_bytes, const char *block, const char *fmt_string) +print_short (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (unsigned short); i > 0; i--) { unsigned int tmp = *(const unsigned short *) block; @@ -418,9 +421,9 @@ print_short (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_int (off_t n_bytes, const char *block, const char *fmt_string) +print_int (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (unsigned int); i > 0; i--) { unsigned int tmp = *(const unsigned int *) block; @@ -430,9 +433,9 @@ print_int (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_long (off_t n_bytes, const char *block, const char *fmt_string) +print_long (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (unsigned long); i > 0; i--) { unsigned long tmp = *(const unsigned long *) block; @@ -442,9 +445,9 @@ print_long (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_long_long (off_t n_bytes, const char *block, const char *fmt_string) +print_long_long (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (ulonglong_t); i > 0; i--) { ulonglong_t tmp = *(const ulonglong_t *) block; @@ -454,9 +457,9 @@ print_long_long (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_float (off_t n_bytes, const char *block, const char *fmt_string) +print_float (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (float); i > 0; i--) { float tmp = *(const float *) block; @@ -466,9 +469,9 @@ print_float (off_t n_bytes, const char *block, const char *fmt_string) } static void -print_double (off_t n_bytes, const char *block, const char *fmt_string) +print_double (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (double); i > 0; i--) { double tmp = *(const double *) block; @@ -479,9 +482,9 @@ print_double (off_t n_bytes, const char *block, const char *fmt_string) #ifdef HAVE_LONG_DOUBLE static void -print_long_double (off_t n_bytes, const char *block, const char *fmt_string) +print_long_double (size_t n_bytes, const char *block, const char *fmt_string) { - off_t i; + size_t i; for (i = n_bytes / sizeof (LONG_DOUBLE); i > 0; i--) { LONG_DOUBLE tmp = *(const LONG_DOUBLE *) block; @@ -493,9 +496,9 @@ print_long_double (off_t n_bytes, const char *block, const char *fmt_string) #endif static void -dump_hexl_mode_trailer (off_t n_bytes, const char *block) +dump_hexl_mode_trailer (size_t n_bytes, const char *block) { - off_t i; + size_t i; fputs (" >", stdout); for (i = n_bytes; i > 0; i--) { @@ -508,10 +511,10 @@ dump_hexl_mode_trailer (off_t n_bytes, const char *block) } static void -print_named_ascii (off_t n_bytes, const char *block, +print_named_ascii (size_t n_bytes, const char *block, const char *unused_fmt_string ATTRIBUTE_UNUSED) { - off_t i; + size_t i; for (i = n_bytes; i > 0; i--) { unsigned int c = *(const unsigned char *) block; @@ -535,10 +538,10 @@ print_named_ascii (off_t n_bytes, const char *block, } static void -print_ascii (off_t n_bytes, const char *block, +print_ascii (size_t n_bytes, const char *block, const char *unused_fmt_string ATTRIBUTE_UNUSED) { - off_t i; + size_t i; for (i = n_bytes; i > 0; i--) { unsigned int c = *(const unsigned char *) block; @@ -640,7 +643,7 @@ decode_one_format (const char *s_orig, const char *s, const char **next, enum output_format fmt; const char *pre_fmt_string; char *fmt_string; - void (*print_function) PARAMS ((off_t, const char *, const char *)); + void (*print_function) PARAMS ((size_t, const char *, const char *)); const char *p; unsigned int c; unsigned int field_width = 0; @@ -1023,7 +1026,7 @@ decode_format_string (const char *s) advance IN_STREAM. */ static int -skip (off_t n_skip) +skip (uintmax_t n_skip) { int err = 0; @@ -1052,21 +1055,22 @@ skip (off_t n_skip) as large as the size of the current file, we can decrement n_skip and go on to the next file. */ - if (S_ISREG (file_stats.st_mode) && file_stats.st_size <= n_skip) + if (S_ISREG (file_stats.st_mode) && 0 <= file_stats.st_size) { - n_skip -= file_stats.st_size; - } - - /* If the number of bytes left to skip is less than the size - of the current file, try seeking to the correct offset. */ - - else if (S_ISREG (file_stats.st_mode) - && 0 <= lseek (fileno (in_stream), n_skip, SEEK_CUR)) - { - n_skip = 0; + if (file_stats.st_size <= n_skip) + n_skip -= file_stats.st_size; + else + { + if (lseek (fileno (in_stream), n_skip, SEEK_CUR) < 0) + { + error (0, errno, "%s", input_filename); + err = 1; + } + n_skip = 0; + } } - /* If seek didn't work or wasn't attempted, + /* If it's not a regular file with nonnegative size, position the file pointer by reading. */ else @@ -1107,12 +1111,12 @@ skip (off_t n_skip) } static void -format_address_none (off_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED) +format_address_none (uintmax_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED) { } static void -format_address_std (off_t address, char c) +format_address_std (uintmax_t address, char c) { char buf[MAX_ADDRESS_LENGTH + 2]; char *p = buf + sizeof buf; @@ -1152,7 +1156,7 @@ format_address_std (off_t address, char c) } static void -format_address_paren (off_t address, char c) +format_address_paren (uintmax_t address, char c) { putchar ('('); format_address_std (address, ')'); @@ -1160,7 +1164,7 @@ format_address_paren (off_t address, char c) } static void -format_address_label (off_t address, char c) +format_address_label (uintmax_t address, char c) { format_address_std (address, ' '); format_address_paren (address + pseudo_offset, c); @@ -1178,7 +1182,7 @@ format_address_label (off_t address, char c) only when it has not been padded to length BYTES_PER_BLOCK. */ static void -write_block (off_t current_offset, off_t n_bytes, +write_block (uintmax_t current_offset, size_t n_bytes, const char *prev_block, const char *curr_block) { static int first = 1; @@ -1323,18 +1327,16 @@ get_lcm (void) } /* If S is a valid pre-POSIX offset specification with an optional leading '+' - return the offset it denotes. Otherwise, return -1. */ + return nonzero and set *OFFSET to the offset it denotes. */ -off_t -parse_old_offset (const char *s) +int +parse_old_offset (const char *s, uintmax_t *offset) { int radix; - off_t offset; enum strtol_error s_err; - uintmax_t tmp; if (*s == '\0') - return -1; + return 0; /* Skip over any leading '+'. */ if (s[0] == '+') @@ -1353,17 +1355,13 @@ parse_old_offset (const char *s) radix = 8; } - s_err = xstrtoumax (s, NULL, radix, &tmp, "Bb"); + s_err = xstrtoumax (s, NULL, radix, offset, "Bb"); if (s_err != LONGINT_OK) { STRTOL_FAIL_WARN (s, _("old-style offset"), s_err); - return -1; + return 0; } - if (OFF_T_MAX < tmp) - error (EXIT_FAILURE, 0, - _("%s is larger than the maximum file size on this system"), s); - offset = tmp; - return offset; + return 1; } /* Read a chunk of size BYTES_PER_BLOCK from the input files, write the @@ -1382,8 +1380,7 @@ static int dump (void) { char *block[2]; - off_t current_offset; - off_t end_offset IF_LINT (= 0); + uintmax_t current_offset; int idx; int err; size_t n_bytes_read; @@ -1397,8 +1394,6 @@ dump (void) err = 0; if (limit_bytes_to_format) { - end_offset = n_bytes_to_skip + max_bytes_to_format; - while (1) { size_t n_needed; @@ -1408,7 +1403,7 @@ dump (void) break; } n_needed = MIN (end_offset - current_offset, - (off_t) bytes_per_block); + (uintmax_t) bytes_per_block); err |= read_block (n_needed, block[idx], &n_bytes_read); if (n_bytes_read < bytes_per_block) break; @@ -1471,7 +1466,7 @@ dump_strings (void) { size_t bufsize = MAX (100, string_min); char *buf = xmalloc (bufsize); - off_t address = n_bytes_to_skip; + uintmax_t address = n_bytes_to_skip; int err; err = 0; @@ -1484,7 +1479,7 @@ dump_strings (void) tryline: if (limit_bytes_to_format - && address >= (n_bytes_to_skip + max_bytes_to_format - string_min)) + && (end_offset < string_min || end_offset - string_min <= address)) break; for (i = 0; i < string_min; i++) @@ -1504,8 +1499,7 @@ dump_strings (void) /* We found a run of `string_min' printable characters. Now see if it is terminated with a null byte. */ - while (!limit_bytes_to_format - || address < n_bytes_to_skip + max_bytes_to_format) + while (!limit_bytes_to_format || address < end_offset) { if (i == bufsize) { @@ -1593,7 +1587,7 @@ main (int argc, char **argv) /* The old-style `pseudo starting address' to be printed in parentheses after any true address. */ - off_t pseudo_start IF_LINT (= 0); + uintmax_t pseudo_start IF_LINT (= 0); program_name = argv[0]; setlocale (LC_ALL, ""); @@ -1677,8 +1671,7 @@ it must be one character from [doxn]"), break; case 'j': - s_err = xstrtoumax (optarg, NULL, 0, &tmp, "bkm"); - n_bytes_to_skip = tmp; + s_err = xstrtoumax (optarg, NULL, 0, &n_bytes_to_skip, "bkm"); if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("skip argument"), s_err); break; @@ -1686,15 +1679,9 @@ it must be one character from [doxn]"), case 'N': limit_bytes_to_format = 1; - s_err = xstrtoumax (optarg, NULL, 0, &tmp, "bkm"); - max_bytes_to_format = tmp; + s_err = xstrtoumax (optarg, NULL, 0, &max_bytes_to_format, "bkm"); if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("limit argument"), s_err); - - if (OFF_T_MAX < tmp) - error (EXIT_FAILURE, 0, - _("%s is larger than the maximum file size on this system"), - optarg); break; case 's': @@ -1800,11 +1787,11 @@ it must be one character from [doxn]"), if (traditional) { - off_t offset; + uintmax_t offset; if (n_files == 1) { - if ((offset = parse_old_offset (argv[optind])) >= 0) + if (parse_old_offset (argv[optind], &offset)) { n_bytes_to_skip = offset; --n_files; @@ -1813,9 +1800,9 @@ it must be one character from [doxn]"), } else if (n_files == 2) { - off_t o1, o2; - if ((o1 = parse_old_offset (argv[optind])) >= 0 - && (o2 = parse_old_offset (argv[optind + 1])) >= 0) + uintmax_t o1, o2; + if (parse_old_offset (argv[optind], &o1) + && parse_old_offset (argv[optind + 1], &o2)) { n_bytes_to_skip = o1; flag_pseudo_start = 1; @@ -1823,7 +1810,7 @@ it must be one character from [doxn]"), argv += 2; n_files -= 2; } - else if ((o2 = parse_old_offset (argv[optind + 1])) >= 0) + else if (parse_old_offset (argv[optind + 1], &o2)) { n_bytes_to_skip = o2; --n_files; @@ -1840,9 +1827,9 @@ it must be one character from [doxn]"), } else if (n_files == 3) { - off_t o1, o2; - if ((o1 = parse_old_offset (argv[optind + 1])) >= 0 - && (o2 = parse_old_offset (argv[optind + 2])) >= 0) + uintmax_t o1, o2; + if (parse_old_offset (argv[optind + 1], &o1) + && parse_old_offset (argv[optind + 2], &o2)) { n_bytes_to_skip = o1; flag_pseudo_start = 1; @@ -1878,6 +1865,13 @@ it must be one character from [doxn]"), } } + if (limit_bytes_to_format) + { + end_offset = n_bytes_to_skip + max_bytes_to_format; + if (end_offset < n_bytes_to_skip) + error (EXIT_FAILURE, 0, "skip-bytes + read-bytes is too large"); + } + if (n_specs == 0) { if (decode_one_format ("o2", "o2", NULL, &(spec[0]))) -- cgit v1.2.3-54-g00ecf