genext2fs icon indicating copy to clipboard operation
genext2fs copied to clipboard

Don't call ftruncate() on stdout

Open mart-jansink opened this issue 3 years ago • 9 comments

While - seems to be explicitly supported as the output option (because if(strcmp(fsout, "-") == 0) is checked), this doesn't work since ftruncate is called on it anyway in copy_file. This commit adds a small check on the given dst, just like it does in the loop that actually writes the output.

mart-jansink avatar Dec 29 '20 15:12 mart-jansink

Interesting. I'm a heavy user of the - output option and never saw this error. What OS are you running?

josch avatar Dec 29 '20 20:12 josch

A form of Linux that's running on the QNAP NAS devices. I'm saying "a form of" because it has some limitations compared to distributions like Ubuntu, e.g. sudo doesn't work because they completely reworked the user management. But I would never had thought that something related to that would be the cause of this issue. My bad, I'll give it a go with Ubuntu to confirm.

Regardless, I will need to run this tool on such QNAP devices and have already tested that this commit fixes genext2fs for it.

mart-jansink avatar Dec 29 '20 20:12 mart-jansink

Oh I wasn't trying to shoot down your contribution. It looks sane to me (without having tested it myself).

josch avatar Dec 29 '20 20:12 josch

No problem, I never took it like that :-) But I can confirm that using the stdout works as expected on a regular Ubuntu, without this commit being necessary. So it appears to be something more obscure, probably related to the version of Linux running on QNAP devices.

I'm no expert in C, so if you think that there's some risk of this commit breaking things I'd completely understand if you feel like this is an edge case that's not worth solving. Applying it as a patch already solved the problem for me, so I'm fine either way.

mart-jansink avatar Dec 30 '20 15:12 mart-jansink

@mart-jansink could you try the exact same genext2fs command under strace on your QNAP (without your patch) and a regular Linux, and report the diff ? I'm curious to see what's changing.

bestouff avatar Dec 30 '20 21:12 bestouff

While doing this I found that it isn't actually the QNAP Linux version that's causing the problem. I didn't mention that I'm calling genext2fs from a node.js script that takes the stdout, instead of running something like genext2fs -N 128 -m 0 -b 1048576 - > test.ext from the shell. The latter works across the board, while using node.js doesn't on either a QNAP or regular Ubuntu.

The error is easily reproduced by running the following with node.js (at least the LTS one, v14.15.3):

var child_process = require( "child_process" );
var fs = require( "fs" );

var child = child_process.spawn( "genext2fs-patched", [ "-N", 128, "-m", 0, "-b", ( 1024 * 1024 ), "-" ] )
  .on( "error", console.error );

child.stderr
  .on( "data", function( chunk ) { console.log( chunk.toString() ); } );

child.stdout
  .pipe( fs.createWriteStream( "test.ext2" ) )
  .on( "error", console.error );

I can't tell if node.js is doing something special with the stdout of a spawned child process, nor could I find any issues like this for it.

mart-jansink avatar Dec 31 '20 11:12 mart-jansink

Please ignore the node.js part, its not necessarily relevant either.

The problem appears to be piping the output to another program instead of redirecting it to a file. Under Ubuntu 20.04 genext2fs -N 128 -m 0 -b 1048576 - > test.ext2 works as expected but genext2fs -N 128 -m 0 -b 1048576 - | gzip -c - > test.ext2.gz fails with genext2fs: copy_file: ftruncate: Invalid argument. I've run strace on both examples and attached the output:

mart-jansink avatar Dec 31 '20 17:12 mart-jansink

How does genext2fs manage to work with a piped output ? Do seek() and arbitrary write() work on a pipe ? I'm surprised.

bestouff avatar Jan 01 '21 17:01 bestouff

I just applied the same logic, for consistency, as it's done a few lines below: https://github.com/bestouff/genext2fs/blob/3b99f4a43f612b9ee74bbf24ca9890606295313f/genext2fs.c#L2930 This is probably also the answer to your surprise, genext2fs doesn't try to seek() on a piped output because of this.

Do you still like me to make the change?

mart-jansink avatar Jan 04 '21 11:01 mart-jansink