5 ms·
While it's certainly just example code, the initial sendfile version is badly buggy. /* Fall back to traditional copy if the spliced version fails. */ i
by DannyBee 4y ago
While it's certainly just example code, the initial sendfile version is badly buggy.
/* Fall back to traditional copy if the spliced version fails. */
if (!spliced_copy(srcfd))
copy(srcfd);
The thing that they are trying to avoid is sendfile failing due to inability to mmap the the fd.
But they don't check for that (it would return EINVAL), and in fact, by converting the error code to boolean, destroy the ability to differentiate[1].
Instead, they check that sendfile failed for any reason, and then redo it with copy.
Which means sendfile could output half the data, fail for some reason, and depending on why it failed, the fallback copy read/write will do bad things. for example, output the same data again, or more likely, skip data.
Since they are just reading from the fd as it now exists after sendfile failing, it is most likely to skip data but pretend it completed successfully.
Normally, cat would just fail in that situation, as this should - it should not retry the copy when sendfile returns EINVAL or ENOSYS
This is what you get for transforming error codes into booleans :)
(I guess errno will still be set, and they could still check it here, but ugh)
[1] This is why the man page says:
Applications may wish to fall back to read(2)/write(2) in the case where sendfile() fails with EINVAL or ENOSYS.
- Joker_vD 4y agoShould sendfile(2) not report error if it managed to send a non-zero amount of data? IIRC write(2) behaves like that.
- DannyBee 4y agoI don't honestly remember all of the write semantics - I thought it will only not report error if it gets interrupted by a signal handler after it wrote something. In case of true error, i thought it always return an error. write does have a weird error-checking semantic - you can get it to check for a bunch of errors without writing data by using a count of 0. At least as documented, sendfile does not have any of these semantics - it only returns number of bytes written if the transfer was successful. Otherwise, you can't tell how far it made it :)
- saurik 4y agoAs documented, sendfile (I haven't looked at whatever this "spliced_copy" is) does what Joker_vD said it should: if it does a partial write then it is considered "successful" and the caller is required to retry the call if less than the expected amount of data was sent.
- DannyBee 4y agoWhere is this documented? man sendfile on my linux box doesn't even contain the word "partial", nor does it say what you said in some other way that i can see.