Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Apr 2006 14:14:22 +0200
From:      Ulrich Spoerlein <uspoerlein@gmail.com>
To:        phk@freebsd.org
Cc:        current@freebsd.org
Subject:   Improvements to src/tools/tools/recoverdisk
Message-ID:  <20060425121421.GB1105@roadrunner.q.local>

next in thread | raw e-mail | index | archive | help

--xXmbgvnjoT4axfJE
Content-Type: multipart/mixed; boundary="cWoXeonUoKmBZSoM"
Content-Disposition: inline


--cWoXeonUoKmBZSoM
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Dear Poul-Henning, current@,

I made two, what I call, improvements to recoverdisk. It only tries to
read in multiples of 512 bytes OR the sectorsize. This sucks for CD/DVD
with 2352 bytes sectorsize. My patch takes the native sectorsize into
account, when dimensioning BIG and MEDIUMSIZE.

Second feature is the saving and loading of the worklist. Again, not
very helpful for reading hard disks, but very useful for CDs. This way,
you can first try a scratched CD in drive A, then drive B and drive C.
You don't have to start all over again, but instead can profit from the
different error recovery mechanisms.

Previously, I did this with dd(1) and paper and pencil. Not funny.

Please try the attached patch, thanks!

Ulrich Spoerlein
--=20
 PGP Key ID: 20FEE9DD				Encrypted mail welcome!
Fingerprint: AEC9 AF5E 01AC 4EE1 8F70  6CBD E76E 2227 20FE E9DD
Which is worse: ignorance or apathy?
Don't know. Don't care.

--cWoXeonUoKmBZSoM
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=patch
Content-Transfer-Encoding: quoted-printable

--- recoverdisk.orig.c	Mon Apr 24 19:34:57 2006
+++ recoverdisk.c	Tue Apr 25 14:11:44 2006
@@ -14,15 +14,20 @@
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <sysexits.h>
 #include <time.h>
 #include <unistd.h>
 #include <sys/queue.h>
 #include <sys/disk.h>
 #include <sys/stat.h>
=20
-#define BIGSIZE		(1046640)
-#define MEDIUMSIZE	(63504)
-#define MINSIZE		(512)
+#define	MIN(a,b) (((a)<(b))?(a):(b))
+
+static off_t bigsize =3D 1024 * 1024;
+static off_t medsize =3D 64 * 1024;
+static off_t minsize =3D 512;
=20
 struct lump {
 	off_t			start;
@@ -48,29 +53,119 @@
 	TAILQ_INSERT_TAIL(&lumps, lp, list);
 }
=20
+static struct lump *lp;
+static char *wworklist =3D NULL;
+static char *rworklist =3D NULL;
+
+/* Save the worklist, if -w was given */
+static void
+save_worklist(__unused int sig)
+{
+	FILE *file;
+
+	if (wworklist !=3D NULL) {
+		fprintf(stderr, "\nSaving worklist ...");
+		fflush(stderr);
+
+		file =3D fopen(wworklist, "w");
+		if (file =3D=3D NULL)
+			err(1, "Error opening file %s", wworklist);
+
+		for (;;) {
+			lp =3D TAILQ_FIRST(&lumps);
+			if (lp =3D=3D NULL)
+				break;
+			fprintf(file, "%jd %jd %d\n",
+			    (intmax_t)lp->start, (intmax_t)lp->len, lp->state);
+			TAILQ_REMOVE(&lumps, lp, list);
+		}
+		fprintf(stderr, " done.\n");
+	}
+	exit(0);
+}
+
+static off_t
+read_worklist(off_t t)
+{
+	off_t s, l, d;
+	int state, lines;
+	FILE *file;
+=09
+	fprintf(stderr, "Reading worklist ...");
+	fflush(stderr);
+	file =3D fopen(rworklist, "r");
+	if (file =3D=3D NULL)
+		err(1, "Error opening file %s", rworklist);
+
+	lines =3D 0;
+	d =3D t;
+	for (;;) {
+		++lines;
+		if (3 !=3D fscanf(file, "%jd %jd %d\n", &s, &l, &state)) {
+			if (!feof(file))
+				err(1, "Error parsing file %s at line %d",
+				    rworklist, lines);
+			else
+				break;
+		}
+
+		new_lump(s, l, state);
+		d -=3D l;
+	}
+	fprintf(stderr, " done.\n");
+
+	/*=20
+	 * Return the number of bytes already read (at least not in
+	 * worklist).
+	 */
+	return (d);
+}
+
+static void
+usage(void)
+{
+	fprintf(stderr, "Usage: %s [-r worklist] [-w worklist] source-drive [dest=
ination]", "recoverdisk");
+	exit(EX_USAGE);
+}
+
 int
-main(int argc, const char **argv)
+main(int argc, char * const argv[])
 {
+	int ch;
 	int fdr, fdw;
-	struct lump *lp;
 	off_t 	t, d;
 	size_t i, j;
 	int error, flags;
 	u_char *buf;
-	u_int sectorsize, minsize;
+	u_int sectorsize;
 	time_t t1, t2;
 	struct stat sb;
=20
+	while ((ch =3D getopt(argc, argv, "r:w:")) !=3D -1) {
+		switch (ch) {
+			case 'w':
+				wworklist =3D strdup(optarg);
+				if (wworklist =3D=3D NULL)
+					err(1, "Cannot allocate enough memory");
+				break;
+			case 'r':
+				rworklist =3D strdup(optarg);
+				if (rworklist =3D=3D NULL)
+					err(1, "Cannot allocate enough memory");
+				break;
+			default:
+				usage();
+		}
+	}
+	argc -=3D optind;
+	argv +=3D optind;
=20
-	if (argc < 2)
-		errx(1, "Usage: %s source-drive [destination]", argv[0]);
+	if (argc < 1)
+		usage();
=20
-	buf =3D malloc(BIGSIZE);
-	if (buf =3D=3D NULL)
-		err(1, "Cannot allocate %d bytes buffer", BIGSIZE);
-	fdr =3D open(argv[1], O_RDONLY);
+	fdr =3D open(argv[0], O_RDONLY);
 	if (fdr < 0)
-		err(1, "Cannot open read descriptor %s", argv[1]);
+		err(1, "Cannot open read descriptor %s", argv[0]);
=20
 	error =3D fstat(fdr, &sb);
 	if (error < 0)
@@ -80,46 +175,62 @@
 		error =3D ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
 		if (error < 0)
 			err(1, "DIOCGSECTORSIZE failed");
+
+		/*
+		 * Make medsize roughly 64kB, depending on native sector
+		 * size. bigsize has to be a multiple of medsize.
+		 * For media with 2352 sectors, this will
+		 * result in 2352, 63504, and 1016064 bytes.
+		 */
 		minsize =3D sectorsize;
+		medsize =3D (medsize / sectorsize) * sectorsize;
+		bigsize =3D medsize * 16;
=20
 		error =3D ioctl(fdr, DIOCGMEDIASIZE, &t);
 		if (error < 0)
 			err(1, "DIOCGMEDIASIZE failed");
 	} else {
-		sectorsize =3D 1;
 		t =3D sb.st_size;
-		minsize =3D MINSIZE;
 		flags |=3D O_CREAT | O_TRUNC;
 	}
=20
-	if (argc > 2) {
-		fdw =3D open(argv[2], flags, DEFFILEMODE);
+	buf =3D malloc(bigsize);
+	if (buf =3D=3D NULL)
+		err(1, "Cannot allocate %jd bytes buffer", (intmax_t)bigsize);
+
+	if (argc > 1) {
+		fdw =3D open(argv[1], flags, DEFFILEMODE);
 		if (fdw < 0)
-			err(1, "Cannot open write descriptor %s", argv[2]);
+			err(1, "Cannot open write descriptor %s", argv[1]);
 	} else {
 		fdw =3D -1;
 	}
=20
-	new_lump(0, t, 0);
-	d =3D 0;
+	if (rworklist !=3D NULL) {
+		d =3D read_worklist(t);
+	} else {
+		new_lump(0, t, 0);
+		d =3D 0;
+	}
+
+	signal(SIGINT, save_worklist);
=20
 	t1 =3D 0;
+	printf("%13s %7s %13s %5s %13s %13s %9s\n",
+	    "start", "size", "len", "state", "done", "remaining", "% done");
 	for (;;) {
 		lp =3D TAILQ_FIRST(&lumps);
 		if (lp =3D=3D NULL)
 			break;
-		TAILQ_REMOVE(&lumps, lp, list);
 		while (lp->len > 0) {
-			i =3D BIGSIZE;
-			if (lp->len < BIGSIZE)
-				i =3D lp->len;
+			i =3D MIN(lp->len, bigsize);
 			if (lp->state =3D=3D 1)
-				i =3D MEDIUMSIZE;
+				i =3D MIN(lp->len, medsize);
 			if (lp->state > 1)
-				i =3D minsize;
+				i =3D MIN(lp->len, minsize);
 			time(&t2);
-			if (t1 !=3D t2 || lp->len < BIGSIZE) {
-				printf("\r%13jd %7zu %13jd %3d %13jd %13jd %.8f",
+			if (t1 !=3D t2 || lp->len < bigsize) {
+				printf("\r%13jd %7zu %13jd %5d %13jd %13jd %.7f",
 				    (intmax_t)lp->start,
 				    i,=20
 				    (intmax_t)lp->len,
@@ -152,9 +263,10 @@
 			lp->start +=3D i;
 			lp->len -=3D i;
 		}
+		TAILQ_REMOVE(&lumps, lp, list);
 		free(lp);
 	}
 	printf("\nCompleted\n");
-	exit (0);
+	return (0);
 }
=20

--cWoXeonUoKmBZSoM--

--xXmbgvnjoT4axfJE
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (FreeBSD)

iD8DBQFEThKd524iJyD+6d0RAusvAKCUKUygQ5KDnyCD6n99t0IAYWvcKQCfTOQS
7fBlfjimLz3gj1R37zmFK00=
=bAwp
-----END PGP SIGNATURE-----

--xXmbgvnjoT4axfJE--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060425121421.GB1105>