the only issue I've encountered with this so far is that 'dd' will fail some of its tests because it's not using of= but instead using the redir operator and then it assumes it's NOT open in append mode ;)) so then it tries to seek past EOF (which doesn't work in append mode) to make holes(of zeroes).
to illustrate: $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out 2+1 records in 2+1 records out 14 bytes copied, 0.0001584 s, 88.4 kB/s Actually written to disk: '14' bytes (100.00%). 14 the normal output should be(ie. file size 22 bytes not 14): $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out 2+1 records in 2+1 records out 14 bytes copied, 0.000112444 s, 125 kB/s Actually written to disk: '14' bytes (100.00%). 22 Not to worry though, I'm "sure" I pulled a Curly in Three Stooges episode titled "A Plumbing We Will Go." when I added a kernel patch for this (attached) which ensures `cannot seek: Illegal seek` when trying to go beyond EOF in O_APPEND mode. In a completely unrelated note, this cool Exolon theme/music, listening to it right now: https://www.youtube.com/watch?v=Gfw-CIEM6Zs ah memories:)
newer: now using kernel patch deny_lseek_past_EOF_when_O_APPEND.patch with this bash patch, testing to see how 'dd' reacts... better: $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out dd: 'standard output': cannot seek: Illegal seek 0+0 records in 0+0 records out 0 bytes copied, 0.000102177 s, 0.0 kB/s Actually written to disk: '0' bytes (-nan%). 0 new: ok this is bad: because it makes this fail: $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out 2+1 records in 2+1 records out 14 bytes copied, 0.0001584 s, 88.4 kB/s Actually written to disk: '14' bytes (100.00%). 14 the normal output should be(ie. file size 22 bytes not 14): $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out 2+1 records in 2+1 records out 14 bytes copied, 0.000112444 s, 125 kB/s Actually written to disk: '14' bytes (100.00%). 22 ok so because it's append only, dd cann't seek past the EOF, and thus lseek won't do it's job of skipping past EOF and the subsequent 'write' won't make those \0-es pop up in that gap! ie. dd assumes outfile is never opened in O_APPEND mode. meanwhile this will always work(the redirect became of=): $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes of=/tmp/out ; stat --format=%s /tmp/out 2+1 records in 2+1 records out 14 bytes copied, 0.000137867 s, 102 kB/s Actually written to disk: '14' bytes (100.00%). 22 old info: https://github.com/libcheck/check/issues/188 diff --git a/make_cmd.c b/make_cmd.c index ecbbfd6e..5db799f2 100644 --- a/make_cmd.c +++ b/make_cmd.c @@ -700,7 +700,7 @@ make_redirection (source, instruction, dest_and_filename, flags) case r_output_direction: /* >foo */ case r_output_force: /* >| foo */ case r_err_and_out: /* &>filename */ - temp->flags = O_TRUNC | O_WRONLY | O_CREAT; + temp->flags = O_APPEND | O_TRUNC | O_WRONLY | O_CREAT; break; case r_appending_to: /* >>foo */
use this patch with bash patch always_append_on_redirection.patch this will fix 'dd' trying to seek past EOF into the file used for redirection while that file is open in O_APPEND mode now(with this patch and bash patch!) it's this: $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out dd: 'standard output': cannot seek: Illegal seek 0+0 records in 0+0 records out 0 bytes copied, 0.000102177 s, 0.0 kB/s Actually written to disk: '0' bytes (-nan%). 0 before patch: $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out 2+1 records in 2+1 records out 14 bytes copied, 0.0001584 s, 88.4 kB/s Actually written to disk: '14' bytes (100.00%). 14 should be(if no bash patch was used): $ rm /tmp/out;echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out 2+1 records in 2+1 records out 14 bytes copied, 0.000112444 s, 125 kB/s Actually written to disk: '14' bytes (100.00%). 22 diff --git a/fs/read_write.c b/fs/read_write.c index 7458fccc59e1..e46c2997a158 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -88,6 +88,10 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence, { switch (whence) { case SEEK_END: + if ((file->f_flags & O_APPEND) && (offset > 0)) { + //tried to seek past EOF in O_APPEND mode will have no effect! so, this 'dd' will fail: echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out ie. 14 written 14 bytes file size, instead of 22 bytes file size, if applied O_APPEND patch to bash's redirect operator, thus /tmp/out is O_APPEND mode! ok but actually it's not SEEK_END that's in effect here but SEEK_CUR instead! + return -ESPIPE; // ESPIPE 29 Illegal seek + } offset += eof; break; case SEEK_CUR: @@ -105,6 +109,13 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence, * like SEEK_SET. */ spin_lock(&file->f_lock); + + if ((file->f_flags & O_APPEND) && (offset + file->f_pos > eof)) { + //tried to seek past EOF in O_APPEND mode will have no effect! so, this 'dd' will fail: echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out ie. 14 written 14 bytes file size, instead of 22 bytes file size, if applied O_APPEND patch to bash's redirect operator, thus /tmp/out is O_APPEND mode! ok but actually it's not SEEK_END that's in effect here but SEEK_CUR instead! + spin_unlock(&file->f_lock); + return -ESPIPE; // ESPIPE 29 Illegal seek + } + offset = vfs_setpos(file, file->f_pos + offset, maxsize); spin_unlock(&file->f_lock); return offset; @@ -127,6 +138,10 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence, break; } + if ((file->f_flags & O_APPEND) && (offset > eof)) { + //tried to seek past EOF in O_APPEND mode will have no effect! so, this 'dd' will fail: echo abcdefghijklm | dd bs=5 seek=8 oflag=seek_bytes > /tmp/out ; stat --format=%s /tmp/out ie. 14 written 14 bytes file size, instead of 22 bytes file size, if applied O_APPEND patch to bash's redirect operator, thus /tmp/out is O_APPEND mode! ok but actually it's not SEEK_END that's in effect here but SEEK_CUR instead! + return -ESPIPE; // ESPIPE 29 Illegal seek + } return vfs_setpos(file, offset, maxsize); } EXPORT_SYMBOL(generic_file_llseek_size);