From 460ebb078ed7bf249af745d8725d6c37e7f15b57 Mon Sep 17 00:00:00 2001
From: Pádraig Brady
Date: Thu, 20 Nov 2008 10:28:31 +0000
Subject: dd: Better handle user specified offsets that are too big
Following are the before and after operations for seekable files,
for the various erroneous offsets handled by this patch:
skip beyond end of file
before: immediately exit(0);
after : immediately printf("cannot skip to specified offset"); exit(0);
skip > max file size
before: read whole file and exit(0);
after : immediately printf("cannot skip: Invalid argument"); exit(1);
seek > max file size
before: immediately printf("truncate error: EFBIG"); exit(1);
after : immediately printf("truncate error: EFBIG"); exit(1);
skip > OFF_T_MAX
before: read whole device/file and exit(0);
after : immediately printf("cannot skip:"); exit(1);
seek > OFF_T_MAX
before: immediately printf("truncate error: offset too large"); exit(1);
after : immediately printf("truncate error: offset too large"); exit(1);
skip > device size
before: read whole device and exit(0);
after : immediately printf("cannot skip: Invalid argument"); exit(1);
seek > device size
before: read whole device and printf("write error: ENOSPC"); exit(1);
after : immediately printf("cannot seek: Invalid argument"); exit(1);
* NEWS: Summarize this change in behavior.
* src/dd.c (skip): Add error checking for large seek/skip offsets on
seekable files, rather than deferring to using read() to advance offset.
(dd_copy): Print a warning if skip past EOF, as per FIXME comment.
* test/Makefile.am: Add 2 new tests.
* tests/dd/seek-skip-past-file: Add tests for first 3 cases above.
* tests/dd/seek-skip-past-dev: Add root only test for last case above.
---
tests/dd/skip-seek-past-dev | 63 ++++++++++++++++++++++++++++++
tests/dd/skip-seek-past-file | 91 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 154 insertions(+)
create mode 100755 tests/dd/skip-seek-past-dev
create mode 100755 tests/dd/skip-seek-past-file
(limited to 'tests/dd')
diff --git a/tests/dd/skip-seek-past-dev b/tests/dd/skip-seek-past-dev
new file mode 100755
index 000000000..04101d222
--- /dev/null
+++ b/tests/dd/skip-seek-past-dev
@@ -0,0 +1,63 @@
+#!/bin/sh
+# test diagnostics are printed immediately when seeking beyond device.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+if test "$VERBOSE" = yes; then
+ set -x
+ dd --version
+fi
+
+. $srcdir/test-lib.sh
+
+# need write access to device
+# (even though we don't actually write anything)
+require_root_
+
+get_device_size() {
+ BLOCKDEV=blockdev
+ $BLOCKDEV -V >/dev/null 2>&1 || BLOCKDEV=/sbin/blockdev
+ $BLOCKDEV --getsize64 "$1"
+}
+
+fail=0
+
+# Get path to device the current dir is on.
+# Note df can only get fs size, not device size.
+device=$(df -P --local . | tail -n1 | cut -d' ' -f1) ||
+ skip_test_ 'this test runs only on local file systems'
+
+dev_size=$(get_device_size "$device") ||
+ skip_test_ "failed to determine size of $device"
+
+# Don't use shell arithimetic as older version of dash use longs
+DEV_OFLOW=$(expr $dev_size + 1)
+
+timeout 1 dd bs=1 skip=$DEV_OFLOW count=0 status=noxfer < "$device" 2> err
+test "$?" = "1" || fail=1
+echo "dd: \`standard input': cannot skip: Invalid argument
+0+0 records in
+0+0 records out" > err_ok || framework_failure
+compare err_ok err || fail=1
+
+timeout 1 dd bs=1 seek=$DEV_OFLOW count=0 status=noxfer > "$device" 2> err
+test "$?" = "1" || fail=1
+echo "dd: \`standard output': cannot seek: Invalid argument
+0+0 records in
+0+0 records out" > err_ok || framework_failure
+compare err_ok err || fail=1
+
+Exit $fail
diff --git a/tests/dd/skip-seek-past-file b/tests/dd/skip-seek-past-file
new file mode 100755
index 000000000..cfc143963
--- /dev/null
+++ b/tests/dd/skip-seek-past-file
@@ -0,0 +1,91 @@
+#!/bin/sh
+# test diagnostics are printed when seeking too far in seekable files.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+if test "$VERBOSE" = yes; then
+ set -x
+ dd --version
+fi
+
+. $srcdir/test-lib.sh
+eval $(getlimits) #for OFF_T limits
+
+fail=0
+
+printf "1234" > file || framework_failure
+
+echo "\
+dd: \`standard input': cannot skip to specified offset
+0+0 records in
+0+0 records out" > skip_err || framework_failure
+
+# skipping beyond number of blocks in file should issue a warning
+dd bs=1 skip=5 count=0 status=noxfer < file 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of bytes in file should issue a warning
+dd bs=3 skip=2 count=0 status=noxfer < file 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of blocks in pipe should issue a warning
+cat file | dd bs=1 skip=5 count=0 status=noxfer 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of bytes in pipe should issue a warning
+cat file | dd bs=3 skip=2 count=0 status=noxfer 2> err || fail=1
+compare skip_err err || fail=1
+
+# Check seeking beyond file already offset into
+# skipping beyond number of blocks in file should issue a warning
+(dd bs=1 skip=1 count=0 2>/dev/null &&
+ dd bs=1 skip=4 status=noxfer 2> err) < file || fail=1
+compare skip_err err || fail=1
+
+# Check seeking beyond file already offset into
+# skipping beyond number of bytes in file should issue a warning
+(dd bs=1 skip=1 count=0 2>/dev/null &&
+ dd bs=2 skip=2 status=noxfer 2> err) < file || fail=1
+compare skip_err err || fail=1
+
+# seeking beyond end of file is OK
+dd bs=1 seek=5 count=0 status=noxfer > file 2> err || fail=1
+echo "0+0 records in
+0+0 records out" > err_ok || framework_failure
+compare err_ok err || fail=1
+
+# skipping > OFF_T_MAX should fail immediately
+dd bs=1 skip=$OFF_T_OFLOW count=0 status=noxfer < file 2> err && fail=1
+echo "dd: \`standard input': cannot skip: Value too large for defined data type
+0+0 records in
+0+0 records out" > err_ok || framework_failure
+compare err_ok err || fail=1
+
+# skipping > max file size should fail immediately
+# Note I'm guessing there is a small chance that an lseek() could actually work
+# and only a write() would fail (with EFBIG) when offset > max file size.
+# So this test will both test for that, and ensure that dd
+# exits immediately with an appropriate error when lseek() does error.
+if ! truncate --size=$OFF_T_MAX in 2>/dev/null; then
+ # truncate is to ensure file system doesn't actually support OFF_T_MAX files
+ dd bs=1 skip=$OFF_T_MAX count=0 status=noxfer < file 2> err && fail=1
+ echo "dd: \`standard input': cannot skip: Invalid argument
+0+0 records in
+0+0 records out" > err_ok || framework_failure
+ compare err_ok err || fail=1
+fi
+
+Exit $fail
--
cgit v1.2.3-70-g09d2