vos: Check end of dump magic when file is seekable

When restoring a volume with the -file argument, vos verifies the last
four bytes of the file are the dump end magic before sending the dump to
the volume server. Currently, this check is skipped when reading a dump
from stdin because it is assumed the data is being read from a pipe.

However, this assumption is not correct.  The file handle created from
stdin may be seekable when redirection is used, and the file handle
created from a file name may or may not be seekable, depending on the
file type.

For example, when redirecting a regular file to stdin, the file handle
is seekable, since the shell opens the given file name and associates
stdin with the opened file:

   $ vos restore ... < myfile

In addition, the file handle is not seekable when specifying a named
pipe (fifo) with the -file option:

   $ mkfifo mypipe
   $ vos restore ... -file mypipe

Instead of assuming file handles opened from file names are always
seekable and file handles opened from stdin are never seekable, use
USD_IOCTL() to determine when file handles are seekable, and when
seekable, verify the file ends with the dump end magic number.

While here, be sure to check the return codes from seek and reads while
checking for the dump end magic.

Change-Id: I9d16b13682365b82cb9d0b3673c4ed7c3ab4dc2e
Reviewed-on: https://gerrit.openafs.org/14758
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
This commit is contained in:
Michael Meffie 2021-08-17 20:54:23 -04:00
parent ba27ac6f04
commit 4e7b6ffc8f

View File

@ -372,9 +372,7 @@ WriteData(struct rx_call *call, void *rock)
usd_handle_t ufd = NULL;
afs_int32 error = 0;
afs_int32 code;
afs_int64 currOffset;
afs_uint32 buffer;
afs_uint32 got;
int is_seekable = 0;
if (!filename || !*filename) {
usd_StandardInput(&ufd);
@ -386,16 +384,55 @@ WriteData(struct rx_call *call, void *rock)
error = VOLSERBADOP;
goto wfail;
}
/* test if we have a valid dump */
USD_SEEK(ufd, 0, SEEK_END, &currOffset);
USD_SEEK(ufd, currOffset - sizeof(afs_uint32), SEEK_SET, &currOffset);
USD_READ(ufd, (char *)&buffer, sizeof(afs_uint32), &got);
if ((got != sizeof(afs_uint32)) || (ntohl(buffer) != DUMPENDMAGIC)) {
fprintf(STDERR, "Signature missing from end of file '%s'\n", filename);
}
/* Test if we have a valid dump. */
code = USD_IOCTL(ufd, USD_IOCTL_ISSEEKABLE, &is_seekable);
if (code != 0) {
fprintf(STDERR, "Failed to determine if '%s' is seekable; code=%d\n",
ufd->fullPathName, code);
error = code;
goto wfail;
}
if (is_seekable) {
afs_int64 offset = 0;
afs_uint32 magic = 0;
afs_uint32 got = 0;
code = USD_SEEK(ufd, 0, SEEK_END, &offset);
if (code != 0) {
fprintf(STDERR, "Failed seek to end of '%s'; code=%d\n",
ufd->fullPathName, code);
error = code;
goto wfail;
}
if (offset < sizeof(magic)) {
fprintf(STDERR, "End of dump signature not found in '%s'.\n",
ufd->fullPathName);
error = VOLSERBADOP;
goto wfail;
}
USD_SEEK(ufd, 0, SEEK_SET, &currOffset);
code = USD_SEEK(ufd, offset - sizeof(magic), SEEK_SET, &offset);
if (code != 0) {
fprintf(STDERR, "Failed seek to dump end signature in '%s'; code=%d\n",
ufd->fullPathName, code);
error = code;
goto wfail;
}
code = USD_READ(ufd, (char *)&magic, sizeof(magic), &got);
if (code != 0 || got != sizeof(magic) || ntohl(magic) != DUMPENDMAGIC) {
fprintf(STDERR, "End of dump signature not found in '%s'.\n",
ufd->fullPathName);
error = VOLSERBADOP;
goto wfail;
}
code = USD_SEEK(ufd, 0, SEEK_SET, &offset);
if (code != 0) {
fprintf(STDERR, "Failed seek to start of '%s'; code=%d\n",
ufd->fullPathName, code);
error = code;
goto wfail;
}
}
code = SendFile(ufd, call);
if (code) {