vfs: hang vfs_cdrom_t off the file handle instead of embedding it

vfs_cdrom_t was an inline member at the head of
libretro_vfs_implementation_file. It carries a 2352-byte sector cache
(last_frame) plus the cue sheet cursor, so in a build with HAVE_CDROM
every open file handle cost 2464 bytes rather than 72 - a 34x
inflation for state that only cdrom:// handles ever read.

Measured offsets, x86-64, HAVE_CDROM, before and after:

  sizeof   2464 ->   80
  mappos   2400 ->    8
  mapsize  2408 ->   16
  mapped   2440 ->   48
  hints    2452 ->   60

The footprint is the real motivation. The layout is a secondary win:
the mmap read path in retro_vfs_file_read_impl() touches hints,
mappos, mapsize and mapped, which sat at 2400..2452 and therefore
straddled two 64-byte lines; they now share the first line with the
rest of the hot set, matching what a build without HAVE_CDROM already
got. That is worth a few cycles against a memcpy, not more - this is
I/O code and the syscall dominates - so it is not the reason for the
change, only a consequence of it.

Allocated in retro_vfs_file_open_impl() when path_is_cdrom() matches,
zeroed because the paths below rely on the old inline member having
been cleared by the handle's calloc() (cue_buf NULL, cur_track 0,
last_frame_valid false). Freed in retro_vfs_file_close_impl() at the
existing 'end' label, which is reached both by the cdrom goto and by
fall-through from the ordinary close path; the NULL test covers the
latter. A failed allocation frees the handle and returns NULL, which
is safe because nothing has been attached to it at that point - fd is
still -1 and orig_path is still NULL.

retro_vfs_file_get_cdrom_position() keeps its signature and now
returns the pointer rather than the address of the member. It can
return NULL for a non-cdrom handle where it previously returned a
zeroed one; it has no callers outside this file today, and every
existing consumer of the cdrom state gates on
scheme == VFS_SCHEME_CDROM before reaching for it.

cdrom_cuesheet_overflow_test.c constructs a handle on the stack, so
it now supplies its own vfs_cdrom_t and points the handle at it.
Verified by building the three HAVE_CDROM translation units clean and
running that regression test under ASan: all five cases pass, no leak
reported at exit.
This commit is contained in:
libretroadmin authored and libretroadmin committed 2026-07-27 10:50:21 +02:00
1 parent fdf9a3a21d
commit ecfa53255b
5 files changed
+163 -128

No files matched your search

+8 -8
View File
@@ -338,7 +338,7 @@ static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stre
if (cmd[0] == 0xB9)
{
double time_taken = (double)(((clock() - t) * 1000) / CLOCKS_PER_SEC);
printf("time taken %f ms for DT received length %ld of %" PRId64 " for %02d:%02d:%02d to %02d:%02d:%02d%s req %d cur %d cur_lba %d\n", time_taken, sptd.s.DataTransferLength, len, cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], extra, lba_req, lba_cur, stream->cdrom.cur_lba);
printf("time taken %f ms for DT received length %ld of %" PRId64 " for %02d:%02d:%02d to %02d:%02d:%02d%s req %d cur %d cur_lba %d\n", time_taken, sptd.s.DataTransferLength, len, cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], extra, lba_req, lba_cur, stream->cdrom->cur_lba);
fflush(stdout);
}
@@ -816,7 +816,7 @@ static int cdrom_send_command(libretro_vfs_implementation_file *stream, CDROM_CM
lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);
if (stream->cdrom.last_frame_valid && lba_req == stream->cdrom.last_frame_lba)
if (stream->cdrom->last_frame_valid && lba_req == stream->cdrom->last_frame_lba)
{
/* use cached frame */
cached_read = true;
@@ -825,7 +825,7 @@ static int cdrom_send_command(libretro_vfs_implementation_file *stream, CDROM_CM
fflush(stdout);
#endif
/* assumes request_len is always equal to the size of last_frame */
memcpy(xfer_buf_pos, stream->cdrom.last_frame, sizeof(stream->cdrom.last_frame));
memcpy(xfer_buf_pos, stream->cdrom->last_frame, sizeof(stream->cdrom->last_frame));
}
}
@@ -876,13 +876,13 @@ retry:
unsigned frame_end = cdrom_msf_to_lba(cmd[6], cmd[7], cmd[8]);
/* cache the last received frame */
memcpy(stream->cdrom.last_frame, xfer_buf_pos, sizeof(stream->cdrom.last_frame));
stream->cdrom.last_frame_valid = true;
memcpy(stream->cdrom->last_frame, xfer_buf_pos, sizeof(stream->cdrom->last_frame));
stream->cdrom->last_frame_valid = true;
/* the ending frame is never actually read, so what we really just read is the one right before that */
stream->cdrom.last_frame_lba = frame_end - 1;
stream->cdrom->last_frame_lba = frame_end - 1;
}
else
stream->cdrom.last_frame_valid = false;
stream->cdrom->last_frame_valid = false;
#if 0
printf("Frame %d, adding %" PRId64 " to buf_pos, is now %" PRId64 ". skip is %" PRId64 "\n", i, request_len, (xfer_buf_pos + request_len) - xfer_buf, skip);
@@ -1581,7 +1581,7 @@ int cdrom_read(libretro_vfs_implementation_file *stream,
if (rv)
{
stream->cdrom.last_frame_valid = false;
stream->cdrom->last_frame_valid = false;
return 1;
}
+14 -3
View File
@@ -72,9 +72,6 @@ struct retro_vfs_file_handle
struct libretro_vfs_implementation_file
#endif
{
#ifdef HAVE_CDROM
vfs_cdrom_t cdrom; /* int64_t alignment */
#endif
int64_t size;
uint64_t mappos;
uint64_t mapsize;
@@ -88,6 +85,20 @@ struct libretro_vfs_implementation_file
int fd;
unsigned hints;
enum vfs_scheme scheme;
#ifdef HAVE_CDROM
/* Allocated by retro_vfs_file_open_impl() only when the path
* carries the cdrom:// scheme, and freed by
* retro_vfs_file_close_impl(). It used to be an inline member at
* the head of this struct, which is a poor trade: vfs_cdrom_t
* embeds a 2352-byte sector cache, so every open file handle in a
* build with HAVE_CDROM cost 2464 bytes instead of 72, and the
* fields the read/seek paths actually touch (mappos, mapsize,
* mapped, hints) were pushed past offset 2392 and split across two
* cache lines instead of sharing one. Every consumer already gates
* on 'scheme == VFS_SCHEME_CDROM' before reaching for it, so a
* NULL here is unreachable on those paths. */
vfs_cdrom_t *cdrom;
#endif
#ifdef HAVE_SMBCLIENT
intptr_t smb_fh;
intptr_t smb_ctx;
@@ -50,21 +50,28 @@ static int failures = 0;
static void test_cuesheet_byte_pos_wrap(void)
{
libretro_vfs_implementation_file stream;
/* vfs_cdrom_t hangs off the handle by pointer rather than being an
* inline member, so the test supplies its own storage. Backing it
* with a local keeps the zero-init below covering both objects and
* spares the test an allocation it would have to unwind. */
vfs_cdrom_t cdrom_state;
char out[64];
int64_t rc;
const char *fake_cue = "FILE \"track01.bin\" BINARY\nTRACK 01 MODE1/2048\n";
size_t cue_size = strlen(fake_cue) + 1; /* incl NUL */
memset(&stream, 0, sizeof(stream));
memset(&cdrom_state, 0, sizeof(cdrom_state));
stream.cdrom = &cdrom_state;
stream.cdrom.cue_buf = strdup(fake_cue);
if (!stream.cdrom.cue_buf)
stream.cdrom->cue_buf = strdup(fake_cue);
if (!stream.cdrom->cue_buf)
{
printf("[ERROR] strdup failed\n");
failures++;
return;
}
stream.cdrom.cue_len = cue_size;
stream.cdrom->cue_len = cue_size;
/* orig_path must end in ".cue" for the read function to dispatch
* into the cuesheet path. The function calls path_get_extension
@@ -72,14 +79,14 @@ static void test_cuesheet_byte_pos_wrap(void)
stream.orig_path = strdup("test.cue");
if (!stream.orig_path)
{
free(stream.cdrom.cue_buf);
free(stream.cdrom->cue_buf);
printf("[ERROR] strdup failed (orig_path)\n");
failures++;
return;
}
/* Baseline: read at byte_pos=0 with small len should succeed. */
stream.cdrom.byte_pos = 0;
stream.cdrom->byte_pos = 0;
rc = retro_vfs_file_read_cdrom(&stream, out, 10);
if (rc < 0 || rc > 10)
{
@@ -94,7 +101,7 @@ static void test_cuesheet_byte_pos_wrap(void)
* cue_len - byte_pos - 1 = 0 - 1 = SIZE_MAX (size_t wrap)
* len = SIZE_MAX, memcpy reads gigabytes -> OOB.
* Post-patch: byte_pos >= cue_len, return 0. */
stream.cdrom.byte_pos = (int64_t)cue_size;
stream.cdrom->byte_pos = (int64_t)cue_size;
rc = retro_vfs_file_read_cdrom(&stream, out, 10);
if (rc != 0)
{
@@ -106,7 +113,7 @@ static void test_cuesheet_byte_pos_wrap(void)
printf("[SUCCESS] byte_pos==cue_len returned 0\n");
/* Attack 2: byte_pos past cue_len. Pre-patch: same size_t wrap. */
stream.cdrom.byte_pos = (int64_t)cue_size + 100;
stream.cdrom->byte_pos = (int64_t)cue_size + 100;
rc = retro_vfs_file_read_cdrom(&stream, out, 10);
if (rc != 0)
{
@@ -121,7 +128,7 @@ static void test_cuesheet_byte_pos_wrap(void)
* SIZE_MAX-ish, then cue_len - huge wraps around into a small
* positive value, then memcpy reads gigabytes off cue_buf.
* Post-patch: byte_pos < 0, return 0. */
stream.cdrom.byte_pos = -1;
stream.cdrom->byte_pos = -1;
rc = retro_vfs_file_read_cdrom(&stream, out, 10);
if (rc != 0)
{
@@ -139,7 +146,7 @@ static void test_cuesheet_byte_pos_wrap(void)
* and the full UINT64_MAX reaches memcpy. OOB.
* Post-patch: clamp is unsigned, len is compared to unsigned
* remaining, clamp always fires correctly. */
stream.cdrom.byte_pos = 5;
stream.cdrom->byte_pos = 5;
rc = retro_vfs_file_read_cdrom(&stream, out, (uint64_t)-1);
{
int64_t max_expected = (int64_t)cue_size - 5 - 1;
@@ -153,7 +160,7 @@ static void test_cuesheet_byte_pos_wrap(void)
printf("[SUCCESS] huge len clamped to rc=%lld\n", (long long)rc);
}
free(stream.cdrom.cue_buf);
free(stream.cdrom->cue_buf);
free(stream.orig_path);
}
+19 -2
View File
@@ -377,6 +377,16 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
#ifdef HAVE_CDROM
if (path_is_cdrom(path))
{
/* The sector cache and cue sheet state only exist for cdrom://
* handles, so they are allocated here rather than carried by
* every open file. Zeroed, because the old inline member was
* zeroed by the calloc() above and the cdrom paths rely on
* that (cue_buf NULL, last_frame_valid false, cur_track 0). */
if (!(stream->cdrom = (vfs_cdrom_t*)calloc(1, sizeof(*stream->cdrom))))
{
free(stream);
return NULL;
}
path += sizeof("cdrom://")-1;
stream->scheme = VFS_SCHEME_CDROM;
}
@@ -709,8 +719,15 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
close(stream->fd);
#ifdef HAVE_CDROM
end:
if (stream->cdrom.cue_buf)
free(stream->cdrom.cue_buf);
/* Reached both by the goto above and by fall-through from the
* non-cdrom path, where stream->cdrom is NULL. */
if (stream->cdrom)
{
if (stream->cdrom->cue_buf)
free(stream->cdrom->cue_buf);
free(stream->cdrom);
stream->cdrom = NULL;
}
#endif
#ifdef HAVE_SMBCLIENT
smbend:
+105 -105
View File
@@ -60,20 +60,20 @@ int64_t retro_vfs_file_seek_cdrom(
switch (whence)
{
case SEEK_SET:
stream->cdrom.byte_pos = offset;
stream->cdrom->byte_pos = offset;
break;
case SEEK_CUR:
stream->cdrom.byte_pos += offset;
stream->cdrom->byte_pos += offset;
break;
case SEEK_END:
stream->cdrom.byte_pos = (stream->cdrom.cue_len - 1) + offset;
stream->cdrom->byte_pos = (stream->cdrom->cue_len - 1) + offset;
break;
}
#ifdef CDROM_DEBUG
printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n",
stream->orig_path,
offset,
stream->cdrom.byte_pos);
stream->cdrom->byte_pos);
fflush(stdout);
#endif
}
@@ -98,22 +98,22 @@ int64_t retro_vfs_file_seek_cdrom(
#ifdef CDROM_DEBUG
seek_type = "SEEK_CUR";
#endif
stream->cdrom.byte_pos += offset;
new_lba = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
stream->cdrom->byte_pos += offset;
new_lba = vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].lba + (stream->cdrom->byte_pos / 2352);
cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
}
break;
case SEEK_END:
{
ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio
ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].audio
? 0
: (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));
ssize_t lba_len = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;
: (vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].lba_start));
ssize_t lba_len = vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].track_size - pregap_lba_len;
#ifdef CDROM_DEBUG
seek_type = "SEEK_END";
#endif
cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);
stream->cdrom.byte_pos = lba_len * 2352;
stream->cdrom->byte_pos = lba_len * 2352;
}
break;
case SEEK_SET:
@@ -122,16 +122,16 @@ int64_t retro_vfs_file_seek_cdrom(
#ifdef CDROM_DEBUG
seek_type = "SEEK_SET";
#endif
stream->cdrom.byte_pos = offset;
cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
stream->cdrom->byte_pos = offset;
cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].lba + (stream->cdrom->byte_pos / 2352), &min, &sec, &frame);
}
break;
}
stream->cdrom.cur_min = min;
stream->cdrom.cur_sec = sec;
stream->cdrom.cur_frame = frame;
stream->cdrom.cur_lba = cdrom_msf_to_lba(min, sec, frame);
stream->cdrom->cur_min = min;
stream->cdrom->cur_sec = sec;
stream->cdrom->cur_frame = frame;
stream->cdrom->cur_lba = cdrom_msf_to_lba(min, sec, frame);
#ifdef CDROM_DEBUG
printf(
@@ -139,11 +139,11 @@ int64_t retro_vfs_file_seek_cdrom(
seek_type,
stream->orig_path,
offset,
stream->cdrom.byte_pos,
(unsigned)stream->cdrom.cur_min,
(unsigned)stream->cdrom.cur_sec,
(unsigned)stream->cdrom.cur_frame,
stream->cdrom.cur_lba);
stream->cdrom->byte_pos,
(unsigned)stream->cdrom->cur_min,
(unsigned)stream->cdrom->cur_sec,
(unsigned)stream->cdrom->cur_frame,
stream->cdrom->cur_lba);
fflush(stdout);
#endif
}
@@ -162,7 +162,7 @@ void retro_vfs_file_open_cdrom(
size_t path_len = strlen(path);
const char *ext = path_get_extension(path);
stream->cdrom.cur_track = 1;
stream->cdrom->cur_track = 1;
if ( !(ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\0')
&& !(ext[0] == 'b' && ext[1] == 'i' && ext[2] == 'n' && ext[3] == '\0'))
@@ -183,9 +183,9 @@ void retro_vfs_file_open_cdrom(
* TOC array (OOB read). Leave the init value (1)
* in place on reject. */
if (parsed >= 1 && parsed <= 99)
stream->cdrom.cur_track = parsed;
stream->cdrom->cur_track = parsed;
#ifdef CDROM_DEBUG
printf("[CDROM] Opening track %d\n", stream->cdrom.cur_track);
printf("[CDROM] Opening track %d\n", stream->cdrom->cur_track);
fflush(stdout);
#endif
}
@@ -200,8 +200,8 @@ void retro_vfs_file_open_cdrom(
if (path[5] >= '0' && path[5] <= '9')
{
cdrom_path[7] = path[5];
stream->cdrom.drive = path[5];
vfs_cdrom_toc.drive = stream->cdrom.drive;
stream->cdrom->drive = path[5];
vfs_cdrom_toc.drive = stream->cdrom->drive;
}
}
}
@@ -217,29 +217,29 @@ void retro_vfs_file_open_cdrom(
if (ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\0')
{
if (stream->cdrom.cue_buf)
if (stream->cdrom->cue_buf)
{
free(stream->cdrom.cue_buf);
stream->cdrom.cue_buf = NULL;
free(stream->cdrom->cue_buf);
stream->cdrom->cue_buf = NULL;
}
cdrom_write_cue(stream,
&stream->cdrom.cue_buf,
&stream->cdrom.cue_len,
stream->cdrom.drive,
&stream->cdrom->cue_buf,
&stream->cdrom->cue_len,
stream->cdrom->drive,
&vfs_cdrom_toc.num_tracks,
&vfs_cdrom_toc);
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
#ifdef CDROM_DEBUG
if (!stream->cdrom.cue_buf || !*stream->cdrom.cue_buf)
if (!stream->cdrom->cue_buf || !*stream->cdrom->cue_buf)
{
printf("[CDROM] Error writing cue sheet.\n");
fflush(stdout);
}
else
{
printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom->cue_buf);
fflush(stdout);
}
#endif
@@ -267,9 +267,9 @@ void retro_vfs_file_open_cdrom(
* TOC array (OOB read). Leave the init value (1) in
* place on reject. */
if (parsed >= 1 && parsed <= 99)
stream->cdrom.cur_track = parsed;
stream->cdrom->cur_track = parsed;
#ifdef CDROM_DEBUG
printf("[CDROM] Opening track %d\n", stream->cdrom.cur_track);
printf("[CDROM] Opening track %d\n", stream->cdrom->cur_track);
fflush(stdout);
#endif
}
@@ -283,8 +283,8 @@ void retro_vfs_file_open_cdrom(
if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
{
cdrom_path[4] = path[0];
stream->cdrom.drive = path[0];
vfs_cdrom_toc.drive = stream->cdrom.drive;
stream->cdrom->drive = path[0];
vfs_cdrom_toc.drive = stream->cdrom->drive;
}
}
}
@@ -306,16 +306,16 @@ void retro_vfs_file_open_cdrom(
if (ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\0')
{
if (stream->cdrom.cue_buf)
if (stream->cdrom->cue_buf)
{
free(stream->cdrom.cue_buf);
stream->cdrom.cue_buf = NULL;
free(stream->cdrom->cue_buf);
stream->cdrom->cue_buf = NULL;
}
cdrom_write_cue(stream,
&stream->cdrom.cue_buf,
&stream->cdrom.cue_len,
stream->cdrom.drive,
&stream->cdrom->cue_buf,
&stream->cdrom->cue_len,
stream->cdrom->drive,
&vfs_cdrom_toc.num_tracks,
&vfs_cdrom_toc);
cdrom_get_timeouts(stream,
@@ -331,7 +331,7 @@ void retro_vfs_file_open_cdrom(
int fd = -1;
int index = 0;
stream->cdrom.cur_track = 1;
stream->cdrom->cur_track = 1;
if ( !(ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\0')
&& !(ext[0] == 'b' && ext[1] == 'i' && ext[2] == 'n' && ext[3] == '\0'))
@@ -352,7 +352,7 @@ void retro_vfs_file_open_cdrom(
* TOC array (OOB read). Leave the init value (1)
* in place on reject. */
if (parsed >= 1 && parsed <= 99)
stream->cdrom.cur_track = parsed;
stream->cdrom->cur_track = parsed;
}
}
}
@@ -365,8 +365,8 @@ void retro_vfs_file_open_cdrom(
if (path[5] >= '0' && path[5] <= '9')
{
index = path[5] - '0';
stream->cdrom.drive = path[5];
vfs_cdrom_toc.drive = stream->cdrom.drive;
stream->cdrom->drive = path[5];
vfs_cdrom_toc.drive = stream->cdrom->drive;
}
}
}
@@ -380,47 +380,47 @@ void retro_vfs_file_open_cdrom(
if (ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\0')
{
if (stream->cdrom.cue_buf)
if (stream->cdrom->cue_buf)
{
free(stream->cdrom.cue_buf);
stream->cdrom.cue_buf = NULL;
free(stream->cdrom->cue_buf);
stream->cdrom->cue_buf = NULL;
}
cdrom_write_cue(stream,
&stream->cdrom.cue_buf,
&stream->cdrom.cue_len,
stream->cdrom.drive,
&stream->cdrom->cue_buf,
&stream->cdrom->cue_len,
stream->cdrom->drive,
&vfs_cdrom_toc.num_tracks,
&vfs_cdrom_toc);
cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
#ifdef CDROM_DEBUG
if (!stream->cdrom.cue_buf || !*stream->cdrom.cue_buf)
if (!stream->cdrom->cue_buf || !*stream->cdrom->cue_buf)
{
printf("[CDROM] Error writing cue sheet.\n");
fflush(stdout);
}
else
{
printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom->cue_buf);
fflush(stdout);
}
#endif
}
#endif
if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track)
if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom->cur_track)
{
stream->cdrom.cur_min = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;
stream->cdrom.cur_sec = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;
stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame;
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
stream->cdrom->cur_min = vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].min;
stream->cdrom->cur_sec = vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].sec;
stream->cdrom->cur_frame = vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].frame;
stream->cdrom->cur_lba = cdrom_msf_to_lba(stream->cdrom->cur_min, stream->cdrom->cur_sec, stream->cdrom->cur_frame);
}
else
{
stream->cdrom.cur_min = vfs_cdrom_toc.track[0].min;
stream->cdrom.cur_sec = vfs_cdrom_toc.track[0].sec;
stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;
stream->cdrom.cur_lba = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
stream->cdrom->cur_min = vfs_cdrom_toc.track[0].min;
stream->cdrom->cur_sec = vfs_cdrom_toc.track[0].sec;
stream->cdrom->cur_frame = vfs_cdrom_toc.track[0].frame;
stream->cdrom->cur_lba = cdrom_msf_to_lba(stream->cdrom->cur_min, stream->cdrom->cur_sec, stream->cdrom->cur_frame);
}
}
@@ -463,10 +463,10 @@ int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
&& ext[3] == '\0')
{
#ifdef CDROM_DEBUG
printf("[CDROM] (cue) Tell: Path %s Position %" PRIu64 "\n", stream->orig_path, stream->cdrom.byte_pos);
printf("[CDROM] (cue) Tell: Path %s Position %" PRIu64 "\n", stream->orig_path, stream->cdrom->byte_pos);
fflush(stdout);
#endif
return stream->cdrom.byte_pos;
return stream->cdrom->byte_pos;
}
else if ( (ext[0] == 'b' || ext[0] == 'B')
&& (ext[1] == 'i' || ext[1] == 'I')
@@ -474,10 +474,10 @@ int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
&& ext[3] == '\0')
{
#ifdef CDROM_DEBUG
printf("[CDROM] (bin) Tell: Path %s Position %" PRId64 "\n", stream->orig_path, stream->cdrom.byte_pos);
printf("[CDROM] (bin) Tell: Path %s Position %" PRId64 "\n", stream->orig_path, stream->cdrom->byte_pos);
fflush(stdout);
#endif
return stream->cdrom.byte_pos;
return stream->cdrom->byte_pos;
}
return -1;
@@ -497,8 +497,8 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
/* Guard against byte_pos being outside the cue buffer (can
* happen after a seek -- seek does not clamp). Treat as
* end-of-file. */
if ( stream->cdrom.byte_pos < 0
|| (size_t)stream->cdrom.byte_pos >= stream->cdrom.cue_len)
if ( stream->cdrom->byte_pos < 0
|| (size_t)stream->cdrom->byte_pos >= stream->cdrom->cue_len)
return 0;
/* Clamp len against the remaining bytes using unsigned
* subtraction. Computing (byte_pos + len) and comparing
@@ -507,8 +507,8 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
* one byte before cue_len so consumers that rely on the cue
* buffer being NUL-terminated don't re-read the terminator. */
{
size_t remaining = stream->cdrom.cue_len
- (size_t)stream->cdrom.byte_pos;
size_t remaining = stream->cdrom->cue_len
- (size_t)stream->cdrom->byte_pos;
if (remaining > 0)
remaining -= 1;
if (len > (uint64_t)remaining)
@@ -518,11 +518,11 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
printf(
"[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n",
len,
stream->cdrom.byte_pos);
stream->cdrom->byte_pos);
fflush(stdout);
#endif
memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, (size_t)len);
stream->cdrom.byte_pos += len;
memcpy(s, stream->cdrom->cue_buf + stream->cdrom->byte_pos, (size_t)len);
stream->cdrom->byte_pos += len;
return (int64_t)len;
}
@@ -537,34 +537,34 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
unsigned char rmin = 0;
unsigned char rsec = 0;
unsigned char rframe = 0;
size_t skip = stream->cdrom.byte_pos % 2352;
size_t skip = stream->cdrom->byte_pos % 2352;
/* Guard against cur_track == 0 (would index track[-1]) and
* against an out-of-range byte_pos. cur_track can become
* 0 via a crafted VFS path like "driveN-track00.bin" unless
* the parser rejects it (see retro_vfs_file_open_cdrom). */
if (stream->cdrom.cur_track == 0
|| stream->cdrom.cur_track > 99)
if (stream->cdrom->cur_track == 0
|| stream->cdrom->cur_track > 99)
return 0;
{
size_t track_bytes =
vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;
if ( stream->cdrom.byte_pos < 0
|| (size_t)stream->cdrom.byte_pos >= track_bytes)
vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].track_bytes;
if ( stream->cdrom->byte_pos < 0
|| (size_t)stream->cdrom->byte_pos >= track_bytes)
return 0;
/* Clamp len against remaining bytes using unsigned
* subtraction. Computing (byte_pos + len) first is a
* uint64_t wrap hazard when len is attacker-controlled. */
{
size_t remaining = track_bytes - (size_t)stream->cdrom.byte_pos;
size_t remaining = track_bytes - (size_t)stream->cdrom->byte_pos;
if (len > (uint64_t)remaining)
len = (uint64_t)remaining;
}
}
cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
cdrom_lba_to_msf(stream->cdrom.cur_lba
- vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba,
cdrom_lba_to_msf(stream->cdrom->cur_lba, &min, &sec, &frame);
cdrom_lba_to_msf(stream->cdrom->cur_lba
- vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].lba,
&rmin, &rsec, &rframe);
#ifdef CDROM_DEBUG
@@ -572,14 +572,14 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
"[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n",
len,
stream->orig_path,
stream->cdrom.byte_pos,
stream->cdrom->byte_pos,
(unsigned)rmin,
(unsigned)rsec,
(unsigned)rframe,
(unsigned)min,
(unsigned)sec,
(unsigned)frame,
stream->cdrom.cur_lba,
stream->cdrom->cur_lba,
skip);
fflush(stdout);
#endif
@@ -588,7 +588,7 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec,
frame, s, (size_t)len, skip);
#else
rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s,
rv = cdrom_read_lba(stream, stream->cdrom->cur_lba, s,
(size_t)len, skip);
#endif
@@ -601,28 +601,28 @@ int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
return 0;
}
stream->cdrom.byte_pos += len;
stream->cdrom.cur_lba =
vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba
+ (stream->cdrom.byte_pos / 2352);
stream->cdrom->byte_pos += len;
stream->cdrom->cur_lba =
vfs_cdrom_toc.track[stream->cdrom->cur_track - 1].lba
+ (stream->cdrom->byte_pos / 2352);
cdrom_lba_to_msf(stream->cdrom.cur_lba,
&stream->cdrom.cur_min,
&stream->cdrom.cur_sec,
&stream->cdrom.cur_frame);
cdrom_lba_to_msf(stream->cdrom->cur_lba,
&stream->cdrom->cur_min,
&stream->cdrom->cur_sec,
&stream->cdrom->cur_frame);
#ifdef CDROM_DEBUG
printf(
"[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n",
len,
stream->cdrom.byte_pos,
(unsigned)stream->cdrom.cur_min,
(unsigned)stream->cdrom.cur_sec,
(unsigned)stream->cdrom.cur_frame,
stream->cdrom->byte_pos,
(unsigned)stream->cdrom->cur_min,
(unsigned)stream->cdrom->cur_sec,
(unsigned)stream->cdrom->cur_frame,
cdrom_msf_to_lba(
stream->cdrom.cur_min,
stream->cdrom.cur_sec,
stream->cdrom.cur_frame)
stream->cdrom->cur_min,
stream->cdrom->cur_sec,
stream->cdrom->cur_frame)
);
fflush(stdout);
#endif
@@ -641,5 +641,5 @@ int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(
const libretro_vfs_implementation_file *stream)
{
return &stream->cdrom;
return stream->cdrom;
}