https://bugs.winehq.org/show_bug.cgi?id=54243
Bug ID: 54243 Summary: Warcraft 2 BNE: Fails CD check in wine versions >6.0.X Product: Wine Version: 7.0 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: kernel32 Assignee: wine-bugs@winehq.org Reporter: mmogilvi2+wine@gmail.com Distribution: ---
SYMPTOM: Starting with wine versions mid-6.X and including all 7.X through at least 7.22, the game "Warcraft 2: Battle.net Edition" always fails a CD check and pops up an error dialog:
"Warcraft II Battle.net Edition is unable to read a required file. Your Warcraft II Battle.net Edition CD may not be in the CDROM drive. Please ensure that the disk in in the CDROM drive and press OK. To leave the program, press Exit."
----
BACKGROUND:
Wine had long been able to run "Warcraft 2: Battle.net Edition", up through wine version 6.0.2 and some early 6.X versions.
As described in the howto of the application DB https://appdb.winehq.org/objectManager.php?sClass=version&iId=592 (and other places), in my setup I have long used an .iso of my original CD, with symlinks for "d::" (linked to the iso) and "d:" (linked to the directory where the .iso is loop-mounted). (I actually use some wrapper scripts to temporarily mount it only when needed, etc...)
I unsuccessfully asked about this in the wine forum last July https://forum.winehq.org/viewtopic.php?f=8&t=36787&sid=e1b75b6a5ffa1... and am finally digging deeper into it on my own. There are also some tangential mentions in my recent Gentoo Linux forum post: https://forums.gentoo.org/viewtopic-p-8766703.html
----
ANALYSIS:
I have managed to git bisect this bug to commit 50903a15046354e405564aff6430ee505c01100a "kernelbase: Reimplement GetVolumeInformation on top of GetVolumeInformationByHandle" (although I needed to cherry-pick an unrelated "sincos()" build fix at each step...).
Digging deeper, the following sequence of events leads to the bug:
1. The game calls GetVolumeInformationW() with root=L"D:\". - The game only wants file system flags and FS type name. - Wine proceeds to: 2. NtOpenFile() the root (I haven't traced into this much)... 3. GetVolumeInformationByHandleW() 4. NtQueryVolumeInformationFile() with info_class=FileFsAttributeInformation 5. get_mountmgr_fs_info(), which determines unix_name="/archive/wineData/warcraftII-BNE-2001.iso" and letter=25 (Z:). - BUG: letter=25 definitely indicates a bug. The game is asking about D:, not Z:. - MAYBE BUG: Not sure whether mapping "D:\"'s handle to the .iso rather than the loop mount point directory is a bug or not. - FYI: I'll note that NtQueryVolumeInformationFile()'s documentation says that if the handle "represents a direct device open, only FileFsDeviceInformation can be specified..." in the remarks (i.e., not the info_class being asked for here). There doesn't seem to be any attempt to enforce this in wine. See
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntif... 6. Since wine now thinks the game is asking about "Z:", it returns file system type "NTFS" and associated flags, rather than the correct "CDFS" (and flags). 7. Presumably the game sees the "NTFS" and/or flags, decides this isn't a CD at all, and after some more searching, ultimately pops up the error dialog.
----
POTENTIAL FIXES:
I'm not sure the best way to fix this. Some possibilities include:
A. Somehow ensure the handle that GetVolumeInformation() opens gets mapped to the mounted directory, instead of the .iso file? - This would seem to make sense, but I'm not sure. B. Add more logic to find_dos_device() to notice if path is a file (or device) that is pointed at by one of the double-colon symlinks? - It might need similar caching as get_drives_info(), etc? This would be just a little involved, but might be the best "smallish scale" fix. C. Just revert commit 50903a15046354e405564aff6430ee505c01100a? But that might leave GetVolumeInformationByHandle() broken, and it does seem cleaner to only do all the device/FS superblock parsing and determination in one place... D. Do a more thorough audit / cleanup of how different ways of representing and mapping between unix names, NT names, devices, mount points, symlinks, fallback logic, etc all interact with each other? My initial vague impression is that a lot of this logic is a bit haphazard and only "mostly" works, rather than being robustly designed to always work. - Very involved and time consuming, and well beyond anything I currently have any interest in attempting myself.
----
WORKAROUND:
A quick end-user workaround that seems to work is to change the "d::" symlink to point to the correct /dev/loop0 or loop1, or 2...., that just happens to match whatever free loop device that "mount" dynamically picks to use. - I think this only works because these days /dev is usually mounted as a separate file system, and in wine there is find_dos_device() logic to stops looking if the st_dev changes and then later stuff falls back on doing something else... - Even disregarding that, it seems a bit ugly and fragile to assume a particular loop device, especially if you have other things you sometimes loop mount... (Although maybe my wrapper script could dynamically update the symlink based on parsing /proc/mounts after things are mounted...)
https://bugs.winehq.org/show_bug.cgi?id=54243
Matthew Ogilvie mmogilvi2+wine@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Distribution|--- |Gentoo Regression SHA1| |50903a15046354e405564aff643 | |0ee505c01100a
https://bugs.winehq.org/show_bug.cgi?id=54243
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |regression
https://bugs.winehq.org/show_bug.cgi?id=54243
Chiitoo chiitoo@gentoo.org changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |chiitoo@gentoo.org
https://bugs.winehq.org/show_bug.cgi?id=54243
--- Comment #1 from Rafał Mużyło galtgendo@o2.pl --- The wine side aside, did you check if using cdemu sidesteps the problem ?
https://bugs.winehq.org/show_bug.cgi?id=54243
--- Comment #2 from Matthew Ogilvie mmogilvi2+wine@gmail.com --- I hadn't heard of cdemu, but from its wikipedia summary combined with my bug analysis above, I expect that whether it works would be entirely dependent on whether I change the "d::" symlink to point to the virtual device it creates, or leave it pointing directly at the underlying .iso, for the same reason that my "WORKAROUND" works.
https://bugs.winehq.org/show_bug.cgi?id=54243
--- Comment #3 from Rafał Mużyło galtgendo@o2.pl --- Actually, as long as the vhba_ctl gets marked by udev as user accessible (which the ebuild does set up), the virtual device gets treated as any other cd drive by any standard desktop automount system. As such, things like cd swapping tend to work as intended.
Mounting an iso is little different than just coping cdrom content onto your drive (read-only filesystem aside).
While there might be some cdrom checks that check filesystem type (DRM is retarded, news at 11), most tend to go more in the direction 'is this a cdrom drive ?'.
My point is that while it's a regression from 'things stopped working' angle, it also might be a more correct handling. If the check needs more than setting the drive type to cdrom in winecfg, that's quite likely.
https://bugs.winehq.org/show_bug.cgi?id=54243
--- Comment #4 from Hans Leidekker hans@meelstraat.net --- (In reply to Matthew Ogilvie from comment #2)
I hadn't heard of cdemu, but from its wikipedia summary combined with my bug analysis above, I expect that whether it works would be entirely dependent on whether I change the "d::" symlink to point to the virtual device it creates, or leave it pointing directly at the underlying .iso, for the same reason that my "WORKAROUND" works.
Wine can't do anything with the .iso file, it should point to the device file instead.
https://bugs.winehq.org/show_bug.cgi?id=54243
--- Comment #5 from Matthew Ogilvie mmogilvi2+wine@gmail.com --- SIMPLER WORKAROUND: I just discovered that removing the "d::" symlink completely works (or don't create it in the first place), as long as the read-only .iso FS is loop mounted where "d:" indicates. (Contrary to the appdb "Howto" instructions.)
----
(In reply to Hans Leidekker from comment #4)
Wine can't do anything with the .iso file, it should point to the device file instead.
You make a good point that wine obviously can't make any CD-ROM drive-specific ioctl() calls on a .iso file. (Especially relevant for mixed data/music CD's from a slightly older era, including the original DOS version of Warcraft 2 (non-BNE). "cdemu" is probably very useful in such cases.)
But it still seems like wine shouldn't get internally confused and return information about writeable "Z:" when the application asks for GetVolumeInformation() about read-only "D:". It used to to work before version 7, and linking "d::" to the .iso is still documented in the appdb...
Maybe wine should log a helpful warning if it detects the double-colon symlink pointing to a file instead of a device? As is, I couldn't find any hints about exactly how things were failing and how to work around them until I dug into git history and the source code... (Tangent: Are there any cases where a file makes sense? Maybe if it is a hard disk image instead of a CD image, to support (hypothetical) applications that want to read/write to a raw disk directly? Does wine support any such applications at all?)
https://bugs.winehq.org/show_bug.cgi?id=54243
--- Comment #6 from Hans Leidekker hans@meelstraat.net --- (In reply to Matthew Ogilvie from comment #5)
SIMPLER WORKAROUND: I just discovered that removing the "d::" symlink completely works (or don't create it in the first place), as long as the read-only .iso FS is loop mounted where "d:" indicates. (Contrary to the appdb "Howto" instructions.)
This suggests that there's no bug in Wine and that the Howto should be fixed instead.
https://bugs.winehq.org/show_bug.cgi?id=54243
Hans Leidekker hans@meelstraat.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |NOTOURBUG
--- Comment #7 from Hans Leidekker hans@meelstraat.net --- Closing NOTOURBUG. I'll remove the instruction to create that symlink when I get permission to edit the AppDB page.
https://bugs.winehq.org/show_bug.cgi?id=54243
--- Comment #8 from Matthew Ogilvie mmogilvi2+wine@gmail.com --- No hurry: At least the appdb links to this issue and the workaround, which would have been extremely helpful if it had existed when I first encountered the issue.
As a side note, even though it is easy to work around (once you know how), I'll still emphasize/quote myself about what seems like a conceptual bug that maybe should be fixed anyways:
--- QUOTE --- But it still seems like wine shouldn't get internally confused and return information about writeable "Z:" when the application asks for GetVolumeInformation() about read-only "D:". --- QUOTE ---