[vlc-commits] [Git][videolan/vlc][master] cdrom: distinguish unrecoverable read failures
Steve Lhomme (@robUx4)
gitlab at videolan.org
Tue Sep 15 06:08:15 UTC 2026
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
c0a6eb3d by Pierre Bogdanovscky at 2026-09-15T05:59:07+00:00
cdrom: distinguish unrecoverable read failures
ioctl_ReadSectors() answered -1 for every failure, so callers skipped the
sector and asked for the next one. That is right for a scratch and wrong
for an ejected disc, where a track takes its full running time to produce
silence. Return -2 when the drive says there is nothing left to read, from
ENOMEDIUM, ENODEV and ENXIO on Linux; the other platforms keep returning
-1 until someone with the hardware can look at them. cdda.c then returns
VLC_DEMUXER_EGENERIC and vcd.c sets *eof, Block() having no way to report
an error. Nothing else changes: -2 is a value no arm returned before, and
every caller tested for a negative result.
Fixes: #7545
Assisted-by: claude-code:claude-opus-5-0
- - - - -
4 changed files:
- modules/access/cdda.c
- modules/access/vcd/cdrom.c
- modules/access/vcd/cdrom.h
- modules/access/vcd/vcd.c
Changes:
=====================================
modules/access/cdda.c
=====================================
@@ -165,13 +165,18 @@ static int Demux(demux_t *demux)
if (unlikely(block == NULL))
return VLC_DEMUXER_EOF;
- if (ioctl_ReadSectors(VLC_OBJECT(demux), sys->vcddev,
- sys->start + sys->position,
- block->p_buffer, count, CDDA_TYPE) < 0)
+ int ret = ioctl_ReadSectors(VLC_OBJECT(demux), sys->vcddev,
+ sys->start + sys->position,
+ block->p_buffer, count, CDDA_TYPE);
+ if (ret < 0)
{
msg_Err(demux, "cannot read sector %u", sys->position);
block_Release(block);
+ /* Nothing left to read: the disc is gone, or the drive is. */
+ if (ret == -2)
+ return VLC_DEMUXER_EGENERIC;
+
/* Skip potentially bad sector */
sys->position++;
return VLC_DEMUXER_SUCCESS;
=====================================
modules/access/vcd/cdrom.c
=====================================
@@ -41,6 +41,7 @@
# define INCL_DOSDEVIOCTL
#endif
+#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
@@ -658,6 +659,7 @@ int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
if( ioctl( p_vcddev->i_device_handle, DKIOCCDREAD, &cd_read ) == -1 )
{
+ /* TODO return -2 in case of unrecoverable read failure. */
msg_Err( p_this, "could not read block %d", i_sector );
goto error;
}
@@ -676,18 +678,40 @@ int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
VCD_SECTOR_SIZE * i_nb, &dwBytesReturned,
NULL ) == 0 )
{
+ DWORD dwError = GetLastError();
+ bool b_read = false;
+
if( i_type == VCD_TYPE )
{
/* Retry in YellowMode2 */
cdrom_raw.TrackMode = YellowMode2;
- if( DeviceIoControl( p_vcddev->h_device_handle,
- IOCTL_CDROM_RAW_READ, &cdrom_raw,
- sizeof(RAW_READ_INFO), p_block,
- VCD_SECTOR_SIZE * i_nb, &dwBytesReturned,
- NULL ) == 0 )
- goto error;
+ b_read = DeviceIoControl( p_vcddev->h_device_handle,
+ IOCTL_CDROM_RAW_READ, &cdrom_raw,
+ sizeof(RAW_READ_INFO), p_block,
+ VCD_SECTOR_SIZE * i_nb,
+ &dwBytesReturned, NULL ) != 0;
+ if( !b_read )
+ dwError = GetLastError();
+ }
+
+ if( !b_read )
+ {
+ if( dwError == ERROR_NOT_READY ||
+ dwError == ERROR_MEDIA_CHANGED ||
+ dwError == ERROR_NO_MEDIA_IN_DRIVE ||
+ dwError == ERROR_DEV_NOT_EXIST ||
+ dwError == ERROR_DEVICE_NOT_CONNECTED ||
+ dwError == ERROR_DEVICE_REMOVED )
+ {
+ msg_Err( p_this, "cannot read block %d: no disc",
+ i_sector );
+ goto unrecoverable;
+ }
+
+ msg_Err( p_this, "could not read block %d from disc "
+ "(error %lu)", i_sector, dwError );
+ goto error;
}
- else return -1;
}
#elif defined( __OS2__ )
@@ -706,6 +730,7 @@ int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
p_block, VCD_SECTOR_SIZE * i_nb, &data_len );
if( rc )
{
+ /* TODO return -2 in case of unrecoverable read failure. */
msg_Err( p_this, "could not read block %d", i_sector );
goto error;
}
@@ -742,6 +767,7 @@ int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
}
if( sc.retsts || sc.error )
{
+ /* TODO return -2 in case of unrecoverable read failure. */
msg_Err( p_this, "SCSI command failed: status %d error %d",
sc.retsts, sc.error );
goto error;
@@ -767,6 +793,7 @@ int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
ssize_t toread = VCD_SECTOR_SIZE * i_nb;
if( read( p_vcddev->i_device_handle, p_block, toread ) != toread )
{
+ /* TODO return -2 in case of unrecoverable read failure. */
msg_Err( p_this, "Could not read sector %d", i_sector );
goto error;
}
@@ -785,6 +812,21 @@ int ioctl_ReadSectors( vlc_object_t *p_this, const vcddev_t *p_vcddev,
if( ioctl( p_vcddev->i_device_handle, CDROMREADRAW,
p_block + i * VCD_SECTOR_SIZE ) == -1 )
{
+ /* ENOMEDIUM is Linux's, and this arm is the last #else of the
+ * platform chain, so it may be compiled where that spelling
+ * does not exist. ENODEV and ENXIO are POSIX and need no
+ * guard. */
+ if( errno == ENODEV || errno == ENXIO
+#ifdef ENOMEDIUM
+ || errno == ENOMEDIUM
+#endif
+ )
+ {
+ msg_Err( p_this, "cannot read block %i: no disc",
+ i_sector );
+ goto unrecoverable;
+ }
+
msg_Err( p_this, "could not read block %i from disc",
i_sector );
@@ -816,6 +858,11 @@ error:
if( i_type == VCD_TYPE )
free( p_block );
return( -1 );
+
+unrecoverable:
+ if( i_type == VCD_TYPE )
+ free( p_block );
+ return( -2 );
}
/****************************************************************************
=====================================
modules/access/vcd/cdrom.h
=====================================
@@ -155,6 +155,11 @@ typedef struct entries_sect_s
vcddev_t *ioctl_Open ( vlc_object_t *, const char * );
void ioctl_Close ( vlc_object_t *, vcddev_t * );
vcddev_toc_t * ioctl_GetTOC ( vlc_object_t *, const vcddev_t * );
+
+/* Returns:
+ * 0 success
+ * -1 recoverable failure, or at least not known not to be (ex: a scratch)
+ * -2 irrecoverable failure (ex: disc ejected, device unplugged) */
int ioctl_ReadSectors ( vlc_object_t *, const vcddev_t *,
int, uint8_t *, int, int );
=====================================
modules/access/vcd/vcd.c
=====================================
@@ -369,12 +369,20 @@ static block_t *Block( stream_t *p_access, bool *restrict eof )
return NULL;
}
- if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev,
- p_sys->i_sector, p_block->p_buffer, i_blocks, VCD_TYPE ) < 0 )
+ int i_ret = ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev,
+ p_sys->i_sector, p_block->p_buffer, i_blocks, VCD_TYPE );
+ if( i_ret < 0 )
{
msg_Err( p_access, "cannot read sector %i", p_sys->i_sector );
block_Release( p_block );
+ /* Nothing left to read: the disc is gone, or the drive is. */
+ if( i_ret == -2 )
+ {
+ *eof = true;
+ return NULL;
+ }
+
/* Try to skip one sector (in case of bad sectors) */
p_sys->offset += VCD_DATA_SIZE;
p_sys->i_sector++;
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/c0a6eb3d965bacb3f1f34a9f6d55742257dcd66b
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/c0a6eb3d965bacb3f1f34a9f6d55742257dcd66b
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help
More information about the vlc-commits
mailing list