B<voldump> S<<< B<-part> <I<partition>> >>> S<<< B<-volumeid> <I<volume id>> >>>
S<<< [B<-file> <I<dump file>>] >>> [B<-time> <I<dump from time>>]
- [B<-verbose>] [B<-help>]
+ [B<-pad-errors>] [B<-verbose>] [B<-help>]
B<voldump> S<<< B<-p> <I<partition>> >>> S<<< B<-vo> <I<volume id>> >>>
S<<< [B<-f> <I<dump file>>] >>> [B<-time> <I<dump from time>>]
Specifies whether the dump is full or incremental. Omit this argument to create
a full dump, or provide one of the valid values listed in L<vos_dump(1)>.
+=item B<-pad-errors>
+
+When reading vnode data from disk, if B<voldump> encounters an I/O error or
+unexpected EOF, by default B<voldump> will print an error and exit. If
+B<-pad-errors> is given, instead B<voldump> will pad the unreadable region with
+NUL bytes, and continue with the dump.
+
+This option may be useful when trying to extract data from volumes where the
+underlying disk is failing, or the volume data is corrupted. Data may be
+missing from files in the volume in such cases (replaced by NUL bytes), but at
+least some data may be extracted.
+
=item B<-verbose>
Asks for a verbose trace of the dump process. This trace information will
DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
{
int code = 0, error = 0;
- afs_int32 pad = 0;
- afs_foff_t offset = 0;
afs_sfsize_t nbytes, howBig;
- ssize_t n;
+ ssize_t n = 0;
size_t howMany;
afs_foff_t howFar = 0;
byte *p;
return VOLSERDUMPERROR;
}
- for (nbytes = howBig; (nbytes && !error); nbytes -= howMany) {
+ for (nbytes = howBig; (nbytes && !error); ) {
if (nbytes < howMany)
howMany = nbytes;
/* Read the data */
n = FDH_PREAD(handleP, p, howMany, howFar);
- howFar += n;
+ if (n < 0) {
+ Log("1 Volser: DumpFile: Error reading inode %s for vnode %d: %s\n",
+ PrintInode(stmp, handleP->fd_ih->ih_ino), vnode,
+ afs_error_message(errno));
+ error = VOLSERDUMPERROR;
- /* If read any good data and we null padded previously, log the
- * amount that we had null padded.
- */
- if ((n > 0) && pad) {
- Log("1 Volser: DumpFile: Null padding file %d bytes at offset %lld\n", pad, (long long)offset);
- pad = 0;
+ } else if (n == 0) {
+ Log("1 Volser: DumpFile: Premature EOF reading inode %s for vnode %d\n",
+ PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
+ error = VOLSERDUMPERROR;
}
-
- /* If didn't read enough data, null padd the rest of the buffer. This
- * can happen if, for instance, the media has some bad spots. We don't
- * want to quit the dump, so we start null padding.
- */
- if (n < howMany) {
- /* Record the read error */
- if (n < 0) {
- n = 0;
- Log("1 Volser: DumpFile: Error reading inode %s for vnode %d: %s\n", PrintInode(stmp, handleP->fd_ih->ih_ino), vnode, afs_error_message(errno));
- } else if (!pad) {
- Log("1 Volser: DumpFile: Error reading inode %s for vnode %d\n", PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
- }
-
- /* Pad the rest of the buffer with zeros. Remember offset we started
- * padding. Keep total tally of padding.
- */
- memset(p + n, 0, howMany - n);
- if (!pad)
- offset = (howBig - nbytes) + n;
- pad += (howMany - n);
-
- /* Now seek over the data we could not get. An error here means we
- * can't do the next read.
- */
- howFar = (size_t)((howBig - nbytes) + howMany);
+ if (error != 0) {
+ break;
}
+ howFar += n;
+ nbytes -= n;
+
/* Now write the data out */
- if (iod_Write(iodp, (char *)p, howMany) != howMany)
+ if (iod_Write(iodp, (char *)p, n) != n)
error = VOLSERDUMPERROR;
#ifndef AFS_PTHREAD_ENV
IOMGR_Poll();
#endif
}
- if (pad) { /* Any padding we hadn't reported yet */
- Log("1 Volser: DumpFile: Null padding file: %d bytes at offset %lld\n",
- pad, (long long)offset);
- }
-
free(p);
return error;
}
int VolumeChanged; /* needed by physio - leave alone */
int verbose = 0;
+static int enable_padding; /* Pad errors with NUL bytes */
/* Forward Declarations */
static void HandleVolume(struct DiskPartition64 *partP, char *name,
return code;
}
}
+ if (as->parms[5].items != NULL) { /* -pad-errors */
+ enable_padding = 1;
+ }
DInit(10);
cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
"Trace dump progress (very verbose)");
cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
+ cmd_AddParm(ts, "-pad-errors", CMD_FLAG, CMD_OPTIONAL,
+ "pad i/o errors with NUL bytes");
code = cmd_Dispatch(argc, argv);
return code;
}
static int
DumpFile(int dumpfd, int vnode, FdHandle_t * handleP, struct VnodeDiskObject *v)
{
- int code = 0, failed_seek = 0, failed_write = 0;
+ int code = 0;
afs_int32 pad = 0;
afs_foff_t offset = 0;
afs_sfsize_t nbytes, howBig;
- ssize_t n;
+ ssize_t n = 0;
size_t howMany;
afs_foff_t howFar = 0;
byte *p;
}
/* loop through whole file, while we still have bytes left, and no errors, in chunks of howMany bytes */
- for (nbytes = size; (nbytes && !failed_write); nbytes -= howMany) {
+ for (nbytes = size; (nbytes && !code); ) {
if (nbytes < howMany)
howMany = nbytes;
- /* Read the data - unless we know we can't */
- n = (failed_seek ? 0 : FDH_PREAD(handleP, p, howMany, howFar));
- howFar += n;
+ n = FDH_PREAD(handleP, p, howMany, howFar);
/* If read any good data and we null padded previously, log the
* amount that we had null padded.
pad = 0;
}
- /* If didn't read enough data, null padd the rest of the buffer. This
- * can happen if, for instance, the media has some bad spots. We don't
- * want to quit the dump, so we start null padding.
- */
- if (n < howMany) {
-
- if (verbose) fprintf(stderr, " read %u instead of %u bytes.\n", (unsigned)n, (unsigned)howMany);
-
- /* Record the read error */
- if (n < 0) {
- n = 0;
- fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
- errno, PrintInode(stmp, handleP->fd_ih->ih_ino),
- vnode);
- } else if (!pad) {
- fprintf(stderr, "Error reading inode %s for vnode %d\n",
+ if (n < 0) {
+ fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
+ errno, PrintInode(stmp, handleP->fd_ih->ih_ino),
+ vnode);
+ code = VOLSERDUMPERROR;
+ }
+ if (n == 0) {
+ if (pad == 0) {
+ fprintf(stderr, "Unexpected EOF reading inode %s for vnode %d\n",
PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
}
+ code = VOLSERDUMPERROR;
+ }
- /* Pad the rest of the buffer with zeros. Remember offset we started
- * padding. Keep total tally of padding.
+ if (code != 0 && enable_padding) {
+ /*
+ * If our read failed, NUL-pad the rest of the buffer. This can
+ * happen if, for instance, the media has some bad spots. We don't
+ * want to quit the dump, so we start NUL padding.
*/
- memset(p + n, 0, howMany - n);
+ memset(p, 0, howMany);
+
+ /* Remember the offset where we started padding, and keep a total
+ * tally of how much padding we've done. */
if (!pad)
- offset = (howBig - nbytes) + n;
- pad += (howMany - n);
+ offset = howFar;
+ pad += howMany;
- /* Now seek over the data we could not get. An error here means we
- * can't do the next read.
- */
- howFar = ((size - nbytes) + howMany);
+ /* Pretend we read 'howMany' bytes. */
+ n = howMany;
+ code = 0;
+ }
+ if (code != 0) {
+ break;
}
+ howFar += n;
+ nbytes -= n;
+
/* Now write the data out */
- if (write(dumpfd, (char *)p, howMany) != howMany)
- failed_write = VOLSERDUMPERROR;
+ if (write(dumpfd, (char *)p, n) != n)
+ code = VOLSERDUMPERROR;
}
if (pad) { /* Any padding we hadn't reported yet */
}
free(p);
- return failed_write;
+ return code;
}