summaryrefslogtreecommitdiffstats
path: root/sbin/dump
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2003-05-07 18:27:09 +0000
committermckusick <mckusick@FreeBSD.org>2003-05-07 18:27:09 +0000
commit2e1c393dfc9eb11b05e093718baa11cd6a695a7d (patch)
treea7524c265464698a3f6530ac94f5bfd5c18248e7 /sbin/dump
parent1d8f58ae39f8fac245c251478decd0c1cae5c402 (diff)
downloadFreeBSD-src-2e1c393dfc9eb11b05e093718baa11cd6a695a7d.zip
FreeBSD-src-2e1c393dfc9eb11b05e093718baa11cd6a695a7d.tar.gz
Dump is hard-wired to believe that it can read disks on
1024-byte boundaries. For many years this was a reasonable assumption. However, in recent years we have begun seeing devices with 2048-byte sectors. These devices return errors when dump tries to read starting in the middle of a sector or when it tries to read only the first half of a sector. Rather than change the native block size used by dump (and thus create an incompatible dump format), this fix checks for transfer requests that start and/or end on a non-sector boundary. When such a read is detected, the new code reads the entire sector and copies out just the part that dump needs. Reviewed by: Poul-Henning Kamp <phk@critter.freebsd.dk> Approved by: re (John Baldwin <jhb@FreeBSD.org>) Sponsored by: DARPA & NAI Labs.
Diffstat (limited to 'sbin/dump')
-rw-r--r--sbin/dump/main.c1
-rw-r--r--sbin/dump/traverse.c51
2 files changed, 48 insertions, 4 deletions
diff --git a/sbin/dump/main.c b/sbin/dump/main.c
index 6866eb7..54ac7f0 100644
--- a/sbin/dump/main.c
+++ b/sbin/dump/main.c
@@ -388,6 +388,7 @@ main(int argc, char *argv[])
sync();
sblock = (struct fs *)sblock_buf;
for (i = 0; sblock_try[i] != -1; i++) {
+ sblock->fs_fsize = SBLOCKSIZE; /* needed in bread */
bread(sblock_try[i] >> dev_bshift, (char *) sblock, SBLOCKSIZE);
if ((sblock->fs_magic == FS_UFS1_MAGIC ||
(sblock->fs_magic == FS_UFS2_MAGIC &&
diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c
index ec0d56e..0fd10c4 100644
--- a/sbin/dump/traverse.c
+++ b/sbin/dump/traverse.c
@@ -736,12 +736,55 @@ int breaderrors = 0;
void
bread(ufs2_daddr_t blkno, char *buf, int size)
{
- int cnt, i;
+ int secsize, bytes, resid, xfer, base, cnt, i;
+ static char *tmpbuf;
+ off_t offset;
loop:
- cnt = cread(diskfd, buf, size, ((off_t)blkno << dev_bshift));
- if (cnt == size)
- return;
+ offset = blkno << dev_bshift;
+ secsize = sblock->fs_fsize;
+ base = offset % secsize;
+ resid = size % secsize;
+ /*
+ * If the transfer request starts or ends on a non-sector
+ * boundary, we must read the entire sector and copy out
+ * just the part that we need.
+ */
+ if (base == 0 && resid == 0) {
+ cnt = cread(diskfd, buf, size, offset);
+ if (cnt == size)
+ return;
+ } else {
+ if (tmpbuf == NULL && (tmpbuf = malloc(secsize)) == 0)
+ quit("buffer malloc failed\n");
+ xfer = 0;
+ bytes = size;
+ if (base != 0) {
+ cnt = cread(diskfd, tmpbuf, secsize, offset - base);
+ if (cnt != secsize)
+ goto bad;
+ xfer = secsize - base;
+ offset += xfer;
+ bytes -= xfer;
+ resid = bytes % secsize;
+ memcpy(buf, &tmpbuf[base], xfer);
+ }
+ if (bytes >= secsize) {
+ cnt = cread(diskfd, &buf[xfer], bytes - resid, offset);
+ if (cnt != bytes - resid)
+ goto bad;
+ xfer += cnt;
+ offset += cnt;
+ }
+ if (resid == 0)
+ return;
+ cnt = cread(diskfd, tmpbuf, secsize, offset);
+ if (cnt == secsize) {
+ memcpy(&buf[xfer], tmpbuf, resid);
+ return;
+ }
+ }
+bad:
if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
/*
* Trying to read the final fragment.
OpenPOWER on IntegriCloud