Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 May 1998 08:10:21 -0400 (EDT)
From:      Luoqi Chen <luoqi@chen.ml.org>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   bin/6509: 64bit offset support in dd
Message-ID:  <199805041210.IAA06341@chen.ml.org>

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


>Number:         6509
>Category:       bin
>Synopsis:       Allow dd to seek/skip to offset beyond the 2G limit
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon May  4 05:10:01 PDT 1998
>Last-Modified:
>Originator:     Luoqi Chen
>Organization:
>Release:        FreeBSD 3.0-CURRENT i386
>Environment:


>Description:

	Currently dd doesn't allow offset to be greater than INT_MAX
	(2G for i386). This means on disks larger than 2G (which by the
	way are true for almost all new disks sold nowadays) a substantial
	portaion of the disk blocks are unreachable through dd. This patch
	raises the limit to QUAD_MAX (2^63).

>How-To-Repeat:


>Fix:
	

Index: args.c
===================================================================
RCS file: /fun/cvs/src/bin/dd/args.c,v
retrieving revision 1.11
diff -u -r1.11 args.c
--- args.c	1997/11/11 20:35:29	1.11
+++ args.c	1998/05/04 11:55:58
@@ -67,6 +67,7 @@
 static void	f_seek __P((char *));
 static void	f_skip __P((char *));
 static u_long	get_bsz __P((char *));
+static u_int64_t get_bsz64 __P((char *));
 
 static struct arg {
 	char *name;
@@ -165,15 +166,10 @@
 	if (in.dbsz == 0 || out.dbsz == 0)
 		errx(1, "buffer sizes cannot be zero");
 
-	/*
-	 * Read, write and seek calls take ints as arguments.  Seek sizes
-	 * could be larger if we wanted to do it in stages or check only
-	 * regular files, but it's probably not worth it.
-	 */
 	if (in.dbsz > INT_MAX || out.dbsz > INT_MAX)
 		errx(1, "buffer sizes cannot be greater than %d", INT_MAX);
-	if (in.offset > INT_MAX / in.dbsz || out.offset > INT_MAX / out.dbsz)
-		errx(1, "seek offsets cannot be larger than %d", INT_MAX);
+	if (in.offset > QUAD_MAX / in.dbsz || out.offset > QUAD_MAX / out.dbsz)
+		errx(1, "seek offsets cannot be larger than %d", QUAD_MAX);
 }
 
 static int
@@ -257,7 +253,7 @@
 	char *arg;
 {
 
-	out.offset = (u_int)get_bsz(arg);
+	out.offset = (u_int64_t)get_bsz64(arg);
 }
 
 static void
@@ -265,7 +261,7 @@
 	char *arg;
 {
 
-	in.offset = (u_int)get_bsz(arg);
+	in.offset = (u_int64_t)get_bsz64(arg);
 }
 
 static struct conv {
@@ -324,9 +320,9 @@
  * 	1) A positive decimal number.
  *	2) A positive decimal number followed by a b (mult by 512).
  *	3) A positive decimal number followed by a k (mult by 1024).
- *	4) A positive decimal number followed by a m (mult by 512).
+ *	4) A positive decimal number followed by a m (mult by 1048576).
  *	5) A positive decimal number followed by a w (mult by sizeof int)
- *	6) Two or more positive decimal numbers (with/without k,b or w).
+ *	6) Two or more positive decimal numbers (with/without k,b,m or w).
  *	   seperated by x (also * for backwards compatibility), specifying
  *	   the product of the indicated values.
  */
@@ -381,6 +377,85 @@
 		case 'x':
 			t = num;
 			num *= get_bsz(expr + 1);
+			if (t > num)
+erange:				errx(1, "%s: %s", oper, strerror(ERANGE));
+			break;
+		default:
+			errx(1, "%s: illegal numeric value", oper);
+	}
+	return (num);
+}
+
+/*
+ * Convert an expression of the following forms to a 64bit unsigned int.
+ * 	1) A positive decimal number.
+ *	2) A positive decimal number followed by a b (mult by 512).
+ *	3) A positive decimal number followed by a k (mult by 1024).
+ *	4) A positive decimal number followed by a m (mult by 1048576).
+ *	5) A positive decimal number followed by a g (mult by 1073741824).
+ *	6) A positive decimal number followed by a w (mult by sizeof int)
+ *	7) Two or more positive decimal numbers (with/without k,b,m,g or w).
+ *	   seperated by x (also * for backwards compatibility), specifying
+ *	   the product of the indicated values.
+ */
+static u_int64_t
+get_bsz64(val)
+	char *val;
+{
+	u_int64_t num, t;
+	char *expr;
+
+	num = strtouq(val, &expr, 0);
+	if (num == UQUAD_MAX)			/* Overflow. */
+		err(1, "%s", oper);
+	if (expr == val)			/* No digits. */
+		errx(1, "%s: illegal numeric value", oper);
+
+	switch(*expr) {
+	case 'b':
+		t = num;
+		num *= 512;
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'k':
+		t = num;
+		num *= 1024;
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'm':
+		t = num;
+		num *= 1048576;
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'g':
+		t = num;
+		num *= 1073741824;
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'w':
+		t = num;
+		num *= sizeof(int);
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	}
+
+	switch(*expr) {
+		case '\0':
+			break;
+		case '*':			/* Backward compatible. */
+		case 'x':
+			t = num;
+			num *= get_bsz64(expr + 1);
 			if (t > num)
 erange:				errx(1, "%s: %s", oper, strerror(ERANGE));
 			break;
Index: dd.h
===================================================================
RCS file: /fun/cvs/src/bin/dd/dd.h,v
retrieving revision 1.8
diff -u -r1.8 dd.h
--- dd.h	1998/02/11 02:23:31	1.8
+++ dd.h	1998/05/04 10:05:29
@@ -54,7 +54,7 @@
 
 	char 	*name;			/* name */
 	int	fd;			/* file descriptor */
-	u_long	offset;			/* # of blocks to skip */
+	u_int64_t	offset;		/* # of blocks to skip */
 
 	u_long	f_stats;		/* # of full blocks processed */
 	u_long	p_stats;		/* # of partial blocks processed */
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



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