summaryrefslogtreecommitdiff
path: root/src/dd.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1999-07-15 12:06:18 +0000
committerJim Meyering <jim@meyering.net>1999-07-15 12:06:18 +0000
commit5db7818497df203d51f9f17e2fa8d6d189ff1321 (patch)
treedb978c606b99b7339eafae5230f1c8efdfe681c5 /src/dd.c
parent1950561a91675a2502b866e36bc4a25c8fae2d01 (diff)
downloadcoreutils-5db7818497df203d51f9f17e2fa8d6d189ff1321.tar.xz
Include getpagesize.h.
(ROUND_UP_TO_MODULUS): Define. (dd_copy): Page-align the input buffer. Based on a patch from Scott Lurndal.
Diffstat (limited to 'src/dd.c')
-rw-r--r--src/dd.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/src/dd.c b/src/dd.c
index 3aa856448..1ad925356 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -31,6 +31,7 @@
#include "system.h"
#include "error.h"
+#include "getpagesize.h"
#include "human.h"
#include "long-options.h"
#include "safe-read.h"
@@ -45,6 +46,8 @@
# define SIGINFO SIGUSR1
#endif
+#define ROUND_UP_TO_MODULUS(X, M) (X + M - 1 - ((X + M - 1) % M))
+
#define max(a, b) ((a) > (b) ? (a) : (b))
#define output_char(c) \
do { \
@@ -844,16 +847,34 @@ static int
dd_copy (void)
{
unsigned char *ibuf, *bufstart; /* Input buffer. */
+ unsigned char *real_buf; /* real buffer address before alignment */
int nread; /* Bytes read in the current block. */
int exit_status = 0;
+ size_t page_size = getpagesize ();
/* Leave at least one extra byte at the beginning and end of `ibuf'
for conv=swab, but keep the buffer address even. But some peculiar
device drivers work only with word-aligned buffers, so leave an
extra two bytes. */
- ibuf = (unsigned char *) xmalloc (input_blocksize + 2 * SWAB_ALIGN_OFFSET);
- ibuf += SWAB_ALIGN_OFFSET;
+ /* Some devices require alignment on a sector or page boundary
+ (e.g. character disk devices). Align the input buffer to a
+ page boundary to cover all bases. Note that due to the swab
+ algorithm, we must have at least one byte in the page before
+ the input buffer; thus we allocate 2 pages of slop in the
+ real buffer. 8k above the blocksize shouldn't bother anyone. */
+
+
+ real_buf = (unsigned char *) xmalloc (input_blocksize
+ + 2 * SWAB_ALIGN_OFFSET
+ + 2 * page_size - 1);
+ ibuf = real_buf;
+ ibuf += SWAB_ALIGN_OFFSET; /* allow space for swab */
+
+ /* FIXME: Rather than using uintmax_t here (uintmax_t is necessary on systems
+ where (sizeof void* > sizeof unsigned long), write a configure-time test
+ to determine the smallest unsigned integer type that can hold a pointer. */
+ ibuf = (unsigned char *) ROUND_UP_TO_MODULUS ((uintmax_t) ibuf, page_size);
if (conversions_mask & C_TWOBUFS)
obuf = (unsigned char *) xmalloc (output_blocksize);
@@ -867,7 +888,7 @@ dd_copy (void)
{
/* FIXME: this loses for
% ./dd if=dd seek=1 |:
- ./dd: a1 standard output: Bad file number
+ ./dd: standard output: Bad file number
0+0 records in
0+0 records out
*/
@@ -1003,7 +1024,7 @@ dd_copy (void)
}
}
- free (ibuf - SWAB_ALIGN_OFFSET);
+ free (real_buf);
if (obuf != ibuf)
free (obuf);