[Toybox] Pondering fdlength()...

Rob Landley rob at landley.net
Thu Jul 8 00:27:48 PDT 2021


Many moons ago, trying to determine the size of a CD in a cdrom drive was a
pain, and the "binary search for last location we can actually read" was the
only reliable way to determine the length of the image I could find.

But I'm not sure that's still relevant? That hardware's mostly gone away. DVD
drives are still around, but require a ritual sacrifice in order to read the
actual image data with that whole decss nonsense to <strike>remove the style
sheet</strike> unscramble the contents, and while burning your own DVD for
backup CLAIMS to have a half life of 5 years mine were more like 3, which ain't
great for data retention, which was a widely known problem at least a decade ago
ala
https://www.rlvision.com/blog/how-long-do-writable-cddvd-last-400-discs-put-to-the-test/
so people just bought USB hard drives and stuck them in a safe deposit box if
they cared... Ahem. Anyway:

Doing stat() to find a length, the "get block device size" ioctl, and finally
lseek(SEEK_END) is _probably good enough? I can still fall back to the binary
search but I'm not sure how SEEK_END is going to return failure and yet SEEK_SET
still work in that binary search case? (The CD didn't even spin up the drive for
the checks that didn't actually try to read data, because spinning up the drive
was expensive so they disabled it and stubbed out the return values. This was
related to the scsi layer throwing all the devices into a big pile and giving it
a stir so /dev/sd? devices never enumerated in a known order the way IDE had
because if the IBM zseries was going to have a serious device enumeration
problem then all those IBM Linux developers Sam Palmisano was spending $1
billion/year on from 2001-2005 were going to inflict that problem on the Linux
on the Desktop crowd until there were no more people trying to use Linux on the
Desktop. And thus was systemd forged in the fires of Mt Doom, and short of
hiring Peter Dinklage to throw a recording of the song "bananaphone" into
Kilauea nobody has a plan to make it go away again. Where was I?)

The other thing is that fdlength() currently returns 0 when it can't find the
length, and off_t is signed* and 0 is a valid length so it SHOULD return -1
(with an xfdlength exiting), but I need to audit the callers:

load_policy: xmmap(0) will barf, eh, close enough?

ftpget: storing the return value in unsigned long long. Can't check.

hexedit: checking <1 for bad length, should be fine.

mkswap: no check, int underflow for 0 length file (unsigned pages = 0-1) so it
would write a corrupted header... to a zero length file you couldn't mount anyway?

modinfo: storing into a signed 32 bit int. Not that people are going to load a
single module larger than 2 gigabytes but still... Then feeds length to xmmap()
which would die on <0.

shred: stores in off_t (signed long), checks for <1

truncate: stores in a signed variable, no check, negative length in ftruncate()
would be EINVAL.

mkdev, mke2fs, modprobe, vi are all in pending.

Rob

* glibc defines off_t as __off_t which is __OFF_T_TYPE which is
__SYSCALL_SLONG_TYPE which is __SLONGWORD_TYPE which is long int. The
<strike>aristocrats</strike> FSF!



More information about the Toybox mailing list