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