Merge pull request #251 from rakslice/cd_eject_lock

Sort out the situation with CD ejection on Windows and real CD drives generally
This commit is contained in:
kanjitalk755
2025-01-20 21:44:06 +09:00
committed by GitHub
3 changed files with 85 additions and 15 deletions

View File

@@ -24,6 +24,10 @@
#include <winioctl.h>
#define DEBUG 0
#include "debug.h"
// Prototypes
extern "C" {
@@ -128,12 +132,17 @@ BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
PMRBuffer.PreventMediaRemoval = fPreventRemoval;
return DeviceIoControl( hVolume,
IOCTL_STORAGE_MEDIA_REMOVAL,
BOOL ret = DeviceIoControl( hVolume,
IOCTL_STORAGE_EJECTION_CONTROL,
&PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
NULL, 0,
&dwBytesReturned,
NULL);
D(bug(" PreventRemoval IOCTL returned %d\n", ret));
if (!ret) {
D(bug(" failed, last error %d\n", GetLastError()));
}
return ret;
}
BOOL AutoEjectVolume( HANDLE hVolume, BOOL reload )

View File

@@ -60,12 +60,23 @@ struct file_handle {
loff_t file_size; // Size of file data (only valid if is_file is true)
cachetype cache;
bool is_media_present;
bool is_tray_locked;
HANDLE storage_ejection_handle; // Handle used for storage ejection prevention
#if defined(BINCUE)
bool is_bincue; // Flag: BIN CUE file
void *bincue_fd;
file_handle() {is_bincue = false;} // default bincue false
#endif
file_handle() {
// Since our PreventRemovalOfVolume implementaion on Windows increments a lock counter,
// let's have our own safeguard to prevent incrementing it more than once.
is_tray_locked = false;
storage_ejection_handle = NULL;
#if defined(BINCUE)
is_bincue = false; // default bincue false
#endif
}
};
// Open file handles
@@ -581,6 +592,10 @@ void Sys_close(void *arg)
cache_final(&fh->cache);
SysAllowRemoval((void *)fh);
}
if (fh->storage_ejection_handle != NULL) {
CloseHandle(fh->storage_ejection_handle);
fh->storage_ejection_handle = NULL;
}
if (fh->fh != NULL) {
CloseHandle(fh->fh);
fh->fh = NULL;
@@ -694,6 +709,35 @@ loff_t SysGetFileSize(void *arg)
}
}
static void PreventRemovalCommon(file_handle * fh, bool val) {
D(bug("PreventRemovalCommon %p %d\n", fh, val));
if (!fh) return;
if (!fh->is_cdrom) return;
if (!fh->name) return;
D(bug(" seems ok to do\n"));
if (fh->storage_ejection_handle == NULL) {
// we need a device handle with just FILE_READ_ATTRIBUTES
TCHAR device_name[MAX_PATH];
_sntprintf(device_name, lengthof(device_name), TEXT("\\\\.\\%c:"), fh->name[0]);
// Open device
HANDLE h = CreateFile(
device_name,
FILE_READ_ATTRIBUTES,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
D(bug(" failed to get suitable handle\n"));
return;
}
fh->storage_ejection_handle = h;
}
PreventRemovalOfVolume(fh->storage_ejection_handle, val);
}
/*
* Eject volume (if applicable)
@@ -718,9 +762,9 @@ void SysEject(void *arg)
// exactly ... need to find out
// EjectVolume(toupper(*fh->name),false);
// Preventing is cumulative, try to make sure it's indeed released now
for (int i = 0; i < 10; i++)
PreventRemovalOfVolume(fh->fh, false);
D(bug("SysEject disabling PreventRemoval\n"));
PreventRemovalCommon(fh, false);
fh->is_tray_locked = false;
if (!PrefsFindBool("nocdrom")) {
DWORD dummy;
@@ -819,12 +863,16 @@ bool SysIsDiskInserted(void *arg)
void SysPreventRemoval(void *arg)
{
D(bug("SysPreventRemoval %p\n", arg));
file_handle *fh = (file_handle *)arg;
if (!fh)
return;
if (fh->is_cdrom && fh->fh)
PreventRemovalOfVolume(fh->fh, true);
if (fh->is_cdrom && fh->fh && !fh->is_tray_locked) {
D(bug(" doing prevent removal\n"));
PreventRemovalCommon(fh, true);
fh->is_tray_locked = true;
}
}
@@ -834,12 +882,16 @@ void SysPreventRemoval(void *arg)
void SysAllowRemoval(void *arg)
{
D(bug("SysAllowRemoval %p\n", arg));
file_handle *fh = (file_handle *)arg;
if (!fh)
return;
if (fh->is_cdrom && fh->fh)
PreventRemovalOfVolume(fh->fh, false);
if (fh->is_cdrom && fh->fh) {
D(bug(" doing allow removal\n"));
PreventRemovalCommon(fh, false);
fh->is_tray_locked = false;
}
}

View File

@@ -351,6 +351,8 @@ void CDROMDrop(const char *path) {
void CDROMExit(void)
{
CDROMRemount(); // just to put the handles moved to the remount collection back so they get cleaned up
drive_vec::iterator info, end = drives.end();
for (info = drives.begin(); info != end; ++info)
info->close_fh();
@@ -369,6 +371,7 @@ bool CDROMMountVolume(void *fh)
++info;
if (info != end) {
if (SysIsDiskInserted(info->fh)) {
D(bug("CDROMMountVolume doing SysPreventRemoval cdrom drive num %d\n", info->num));
SysPreventRemoval(info->fh);
WriteMacInt8(info->status + dsDiskInPlace, 1);
read_toc(*info);
@@ -538,6 +541,7 @@ int16 CDROMOpen(uint32 pb, uint32 dce)
// Disk in drive?
if (SysIsDiskInserted(info->fh)) {
D(bug("CDROMOpen doing SysPreventRemoval cdrom drive num %d\n", info->num));
SysPreventRemoval(info->fh);
WriteMacInt8(info->status + dsDiskInPlace, 1);
read_toc(*info);
@@ -670,12 +674,15 @@ int16 CDROMControl(uint32 pb, uint32 dce)
case 7: // EjectTheDisc
D(bug("CDROMControl EjectTheDisc\n"));
if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
if (info->drop) {
if (info->drop || !SysIsFixedDisk(info->fh)) {
SysAllowRemoval(info->fh);
SysEject(info->fh);
info->twok_offset = -1;
info->close_fh();
info->drop = false;
if (info->drop) {
info->close_fh();
info->drop = false;
info->fh = NULL;
}
}
else {
remount_map.insert(std::make_pair(ReadMacInt16(pb + ioVRefNum), info->fh));
@@ -683,9 +690,9 @@ int16 CDROMControl(uint32 pb, uint32 dce)
D(bug("At least stop cd playback if it's some kind of CD %d,%d,%d\n",
info->lead_out[0], info->lead_out[1], info->lead_out[2]));
SysCDStop(info->fh, info->lead_out[0], info->lead_out[1], info->lead_out[2]);
info->fh = NULL;
}
info->fh = NULL;
WriteMacInt8(info->status + dsDiskInPlace, 0);
return noErr;
} else {
@@ -754,8 +761,10 @@ int16 CDROMControl(uint32 pb, uint32 dce)
if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
if (ReadMacInt16(pb + csParam) == 1)
SysAllowRemoval(info->fh);
else
else {
D(bug("SetUserEject call doing SysPreventRemoval cdrom drive num %d\n", info->num));
SysPreventRemoval(info->fh);
}
return noErr;
} else {
return offLinErr;