X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Frmt.c;h=30d665f8746f17581c99423a9ebc2339b97393ca;hb=2eaf29f3fb63f1214b260f2e72d22447a5ae419b;hp=bf2e0a128640a6fd5850104f331a85ad47c5ff22;hpb=6290150c47daea1d034f2293756b623169ad1b9b;p=chaz%2Ftar diff --git a/src/rmt.c b/src/rmt.c index bf2e0a1..30d665f 100644 --- a/src/rmt.c +++ b/src/rmt.c @@ -30,6 +30,7 @@ MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "system.h" +#include "safe-read.h" #include @@ -128,7 +129,7 @@ get_string (char *string) for (counter = 0; counter < STRING_SIZE; counter++) { - if (full_read (STDIN_FILENO, string + counter, 1) != 1) + if (safe_read (STDIN_FILENO, string + counter, 1) != 1) exit (EXIT_SUCCESS); if (string[counter] == '\n') @@ -174,6 +175,83 @@ prepare_record_buffer (size_t size) #endif } +/* Decode OFLAG_STRING, which represents the 2nd argument to `open'. + OFLAG_STRING should contain an optional integer, followed by an optional + symbolic representation of an open flag using only '|' to separate its + components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic + representation if available, falling back on the numeric + representation, or to zero if both formats are absent. + + This function should be the inverse of encode_oflag. The numeric + representation is not portable from one host to another, but it is + for backward compatibility with old-fashioned clients that do not + emit symbolic open flags. */ + +static int +decode_oflag (char const *oflag_string) +{ + char *oflag_num_end; + int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10); + int symbolic_oflag = 0; + + oflag_string = oflag_num_end; + while (ISSPACE ((unsigned char) *oflag_string)) + oflag_string++; + + do + { + struct name_value_pair { char const *name; int value; }; + static struct name_value_pair const table[] = + { + {"APPEND", O_APPEND}, + {"CREAT", O_CREAT}, +#ifdef O_DSYNC + {"DSYNC", O_DSYNC}, +#endif + {"EXCL", O_EXCL}, +#ifdef O_LARGEFILE + {"LARGEFILE", O_LARGEFILE}, /* LFS extension for opening large files */ +#endif +#ifdef O_NOCTTY + {"NOCTTY", O_NOCTTY}, +#endif +#ifdef O_NONBLOCK + {"NONBLOCK", O_NONBLOCK}, +#endif + {"RDONLY", O_RDONLY}, + {"RDWR", O_RDWR}, +#ifdef O_RSYNC + {"RSYNC", O_RSYNC}, +#endif +#ifdef O_SYNC + {"SYNC", O_SYNC}, +#endif + {"TRUNC", O_TRUNC}, + {"WRONLY", O_WRONLY} + }; + struct name_value_pair const *t; + size_t s; + + if (*oflag_string++ != 'O' || *oflag_string++ != '_') + return numeric_oflag; + + for (t = table; + (strncmp (oflag_string, t->name, s = strlen (t->name)) != 0 + || (oflag_string[s] + && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789", + oflag_string[s]))); + t++) + if (t == table + sizeof table / sizeof *table - 1) + return numeric_oflag; + + symbolic_oflag |= t->value; + oflag_string += s; + } + while (*oflag_string++ == '|'); + + return symbolic_oflag; +} + /*---. | ? | `---*/ @@ -210,7 +288,7 @@ main (int argc, char *const *argv) top: errno = 0; /* FIXME: errno should be read-only */ status = 0; - if (full_read (STDIN_FILENO, &command, 1) != 1) + if (safe_read (STDIN_FILENO, &command, 1) != 1) exit (EXIT_SUCCESS); switch (command) @@ -220,16 +298,16 @@ top: case 'O': { char device_string[STRING_SIZE]; - char mode_string[STRING_SIZE]; + char oflag_string[STRING_SIZE]; get_string (device_string); - get_string (mode_string); - DEBUG2 ("rmtd: O %s %s\n", device_string, mode_string); + get_string (oflag_string); + DEBUG2 ("rmtd: O %s %s\n", device_string, oflag_string); if (tape >= 0) close (tape); - tape = open (device_string, atoi (mode_string), 0666); + tape = open (device_string, decode_oflag (oflag_string), MODE_RW); if (tape < 0) goto ioerror; goto respond; @@ -254,6 +332,7 @@ top: char position_string[STRING_SIZE]; off_t count = 0; int negative; + int whence; char *p; get_string (count_string); @@ -288,7 +367,16 @@ top: } } - count = lseek (tape, count, atoi (position_string)); + switch (atoi (position_string)) + { + case 0: whence = SEEK_SET; break; + case 1: whence = SEEK_CUR; break; + case 2: whence = SEEK_END; break; + default: + report_error_message (N_("Seek direction out of range")); + exit (EXIT_FAILURE); + } + count = lseek (tape, count, whence); if (count < 0) goto ioerror; @@ -320,8 +408,8 @@ top: prepare_record_buffer (size); for (counter = 0; counter < size; counter += status) { - status = full_read (STDIN_FILENO, &record_buffer[counter], - size - counter); + status = safe_read (STDIN_FILENO, &record_buffer[counter], + size - counter); if (status <= 0) { DEBUG (_("rmtd: Premature eof\n")); @@ -346,7 +434,7 @@ top: size = atol (count_string); prepare_record_buffer (size); - status = full_read (tape, record_buffer, size); + status = safe_read (tape, record_buffer, size); if (status < 0) goto ioerror; sprintf (reply_buffer, "A%ld\n", status);