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);

Reply via email to