Skip to content

libcglue: use the 64-bit lseek callback in _lseek - #972

Open
kaisa847 wants to merge 1 commit into
ps2dev:masterfrom
kaisa847:fix/libcglue-lseek64
Open

kaisa847 wants to merge 1 commit into
ps2dev:masterfrom
kaisa847:fix/libcglue-lseek64

Conversation

@kaisa847

Copy link
Copy Markdown
Contributor

Problem

_lseek() in ee/libcglue/src/glue.c takes a 64-bit off_t but only ever calls the device's 32-bit lseek callback, which takes an int. The offset is silently truncated: a seek to 4 GiB + 100 lands at 100, and offsets between 2 GiB and 4 GiB come back negative and look like errors. This breaks fseeko/lseek on files larger than 2 GiB (exFAT, HDD). The installed code compiles the truncation as sll a1, a1, 0.

Fix

  • Use the device's lseek64 callback when it exists, and fall back to the 32-bit lseek only when 64-bit seeking is not supported (iomanX offers it only on IOP_DT_FSEXT devices).
  • When falling back to the 32-bit callback, reject an offset outside the int range with EOVERFLOW instead of truncating it.

Testing

Tested on real hardware: a PSX DESR-5100 (PS2-based), with a test program started via ps2link. The program opens a file over host: through the standard C library (which uses the fio/ioman path, whose device has no lseek64) and seeks to 4 GiB + 100.

  • Unpatched libcglue: lseek returns 0x00000064 (the offset truncated to 100), errno 0, and a following read returns the byte at offset 100.
  • This PR: lseek returns -1 with errno == EOVERFLOW.

(The 64-bit lseek64 path is not exercised by this test, since the host: device is a legacy fio device without a 64-bit callback.)

🤖 Generated with Claude Code

Comment thread ee/libcglue/src/glue.c Outdated
res = fdinfo->ops->lseek64(fdinfo->userdata, offset, whence);
// Not every device supports 64-bit seeking (iomanX only supports it on IOP_DT_FSEXT devices),
// so fall back to the 32-bit callback if the 64-bit one fails.
if (res >= 0 || fdinfo->ops->lseek == NULL)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to fall back to 32-bit callback only if res is equal to -EUNSUP. Otherwise it will eat errors returned by lseek64

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thanks — fixed to fall back to the 32-bit callback only on -EUNSUP, so real lseek64 errors propagate instead of being masked. Re-tested on hardware (PSX via ps2link): lseek past 2 GiB on a host: file still returns -1/EOVERFLOW.

off_t is 64 bits, but _lseek() always called the lseek callback, which
takes an int offset and returns an int.

fseeko()/lseek() on files larger than 2 GiB (exFAT, HDD) therefore
truncated the offset silently: a seek to 4 GiB + 100 ends at 100.
Positions from 2 GiB on came back negative and were treated as errors.

Use the lseek64 callback when the descriptor has one. Not every device
supports 64-bit seeking (iomanX only supports it on IOP_DT_FSEXT
devices) and returns -EUNSUP for those; fall back to the 32-bit callback
only then, so real lseek64 errors are not masked. Before using the
32-bit callback, reject offsets outside the int range with EOVERFLOW
instead of truncating them.

Tested on hardware (PSX DESR, ps2link): lseek past 2 GiB on a host:
file returns -1/EOVERFLOW.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kaisa847
kaisa847 force-pushed the fix/libcglue-lseek64 branch from c47a25f to d9b1640 Compare November 14, 2026 08:04

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants