SCSI command 0xAD (GPCMD_READ_DVD_STRUCTURE) with the eighth byte of the
command set to 0x00 (DVD_STRUCT_PHYSICAL) returns physical disc
information for DVDs and blu-rays. On success, the command returns
status 0, and for ordinary CDs, the command returns the error status
0x02 (SAM_STAT_CHECK_CONDITION). The format of the data returned is
different for blu-rays than for DVDs, and the second byte of the command
indicates whether to return DVD information or blu-ray information. (My
LG WH16NS40 drive actually ignores the second byte when there is a DVD
in the drive, but it returns SAM_STAT_CHECK_CONDITION when there is a
blu-ray in the drive and the second byte is not 0x01.) Windows does not
distinguish between DVDs and blu-rays in IOCTL_DISK_GET_MEDIA_TYPES, so
if the SCSI command succeeds for either disc type, report
FILE_DEVICE_DVD.
More specific media information is still not implemented.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57790
--
v3: ntdll: Detect the optical disc type on Linux using a SCSI command.
https://gitlab.winehq.org/wine/wine/-/merge_requests/7747
Function GdipGetImageAttributesAdjustedPalette gets [called with type = -1](https://gitlab.winehq.org/wine/wine/-/blob/22af42ac22279e6c0c671f033661f95c1761b4bb/dlls/gdiplus/tests/image.c?page=6#L5649) and therefore accesses several arrays at index -1.
This patch adds a helper which additionally checks for `type >= ColorAdjustTypeDefault`.
<details>
<summary>ASan output</summary>
```
=================================================================
==gdiplus_test.exe==308==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f21342c57f8 at pc 0x6ffffadfd25b bp 0x7ffffe1ff750 sp 0x7ffffe1ff798
READ of size 4 at 0x7f21342c57f8 thread T0
#0 0x6ffffadfd25a in apply_image_attributes .../dlls/gdiplus/graphics.c:929:41
#1 0x6ffffae5c2f2 in GdipGetImageAttributesAdjustedPalette .../dlls/gdiplus/imageattributes.c:123:5
#2 0x000140084b59 in test_getadjustedpalette .../dlls/gdiplus/tests/image.c:5649:12
#3 0x000140062be6 in func_image .../dlls/gdiplus/tests/image.c:6719:5
#4 0x0001400c9132 in run_test .../include/wine/test.h:765:5
#5 0x0001400c8b50 in main .../include/wine/test.h:884:12
#6 0x0001400cad3a in mainCRTStartup .../dlls/msvcrt/crt_main.c:60:11
#7 0x6fffffc45aa0 in BaseThreadInitThunk .../dlls/kernel32/thread.c:61:24
#8 0x6fffffdcc776 in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17004c776)
0x7f21342c57f8 is located 144 bytes after 1256-byte region [0x7f21342c5280,0x7f21342c5768)
freed by thread T0 here:
#0 0x6ffffe88aab1 in free C:/llvm-mingw/llvm-mingw/llvm-project/compiler-rt/lib/asan\asan_malloc_win.cpp:71:3
#1 0x6ffffae5c21d in GdipDisposeImageAttributes .../dlls/gdiplus/imageattributes.c:109:5
#2 0x000140083598 in test_colorkey .../dlls/gdiplus/tests/image.c:3709:5
#3 0x000140062bd7 in func_image .../dlls/gdiplus/tests/image.c:6716:5
#4 0x0001400c9132 in run_test .../include/wine/test.h:765:5
#5 0x0001400c8b50 in main .../include/wine/test.h:884:12
#6 0x0001400cad3a in mainCRTStartup .../dlls/msvcrt/crt_main.c:60:11
#7 0x6fffffc45aa0 in BaseThreadInitThunk .../dlls/kernel32/thread.c:61:24
#8 0x6fffffdcc776 in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17004c776)
previously allocated by thread T0 here:
#0 0x6ffffe88ace6 in calloc C:/llvm-mingw/llvm-mingw/llvm-project/compiler-rt/lib/asan\asan_malloc_win.cpp:91:3
#1 0x6ffffae5c0fc in GdipCreateImageAttributes .../dlls/gdiplus/imageattributes.c:87:18
#2 0x000140082bf9 in test_colorkey .../dlls/gdiplus/tests/image.c:3629:12
#3 0x000140062bd7 in func_image .../dlls/gdiplus/tests/image.c:6716:5
#4 0x0001400c9132 in run_test .../include/wine/test.h:765:5
#5 0x0001400c8b50 in main .../include/wine/test.h:884:12
#6 0x0001400cad3a in mainCRTStartup .../dlls/msvcrt/crt_main.c:60:11
#7 0x6fffffc45aa0 in BaseThreadInitThunk .../dlls/kernel32/thread.c:61:24
#8 0x6fffffdcc776 in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17004c776)
SUMMARY: AddressSanitizer: heap-buffer-overflow .../dlls/gdiplus/graphics.c:929:41 in apply_image_attributes
Shadow bytes around the buggy address:
0x7f21342c5500: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x7f21342c5580: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x7f21342c5600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x7f21342c5680: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x7f21342c5700: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa
=>0x7f21342c5780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fa]
0x7f21342c5800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x7f21342c5880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f21342c5900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f21342c5980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7f21342c5a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==gdiplus_test.exe==308==ABORTING
```
</details>
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/8141
On Fri May 23 04:23:45 2025 +0000, Alex Henrie wrote:
> Linux has only three [DVD
> ioctls](https://docs.kernel.org/userspace-api/ioctl/cdrom.html):
> DVD_READ_STRUCT, DVD_WRITE_STRUCT, and DVD_AUTH. It has no blu-ray
> ioctls. Of the three DVD ioctls, only DVD_READ_STRUCT would be suitable
> for disc type detection.
> DVD_READ_STRUCT can read five kinds of information: DVD_STRUCT_PHYSICAL,
> DVD_STRUCT_COPYRIGHT, DVD_STRUCT_DISCKEY, DVD_STRUCT_BCA, and
> DVD_STRUCT_MANUFACT. Of those five, only DVD_STRUCT_PHYSICAL would be
> suitable for disc type detection.
> At least on my LG WH16NS40 drive, DVD_STRUCT_PHYSICAL succeeds when
> there is a DVD in the drive, but it fails when there is a CD or a
> blu-ray in the drive. That means that we could use DVD_STRUCT_PHYSICAL
> to accurately detect whether there is a DVD in the drive, but we would
> still need another way to detect blu-rays.
> Is there another ioctl that you had in mind, or something else that I
> missed? Do you want to try DVD_STRUCT_PHYSICAL first and fall back to
> guessing based on the data size if it fails? Please let me know how to proceed.
Any chance it could be a driver bug?
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/7747#note_104478
eric pouech (@epo) commented about programs/cmd/wcmdmain.c:
> +
> + /* Calculate cursor position at beginning of prompt, accounting for lines scrolled
> + * due to length of input.
> + */
> + GetConsoleScreenBufferInfo(hOutput, ¤tConsoleInfo);
> + currentConsoleInfo.dwCursorPosition.X = startConsoleInfo.dwCursorPosition.X;
> + len2 -= (currentConsoleInfo.dwSize.X - currentConsoleInfo.dwCursorPosition.X);
> + if (len2 > 0) {
> + currentConsoleInfo.dwCursorPosition.Y -= ((len2 / currentConsoleInfo.dwSize.X) + 1);
> + }
> + SetConsoleCursorPosition(hOutput, currentConsoleInfo.dwCursorPosition);
> +
> + WriteConsoleW(hOutput, inputBuffer, len, &numWritten, NULL);
> + if (maxLen > len) {
> + clear_console_characters(hOutput, maxLen - len, lastConsoleInfo.dwSize.X); /* width at time of last console update */
> + }
and likely you could do 'maxLen = len;' here: as screen is "cleared" after 'len' position, there's no need to clear it again (unless a wider string is needed, but you'll catch that later)
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/7843#note_104474
eric pouech (@epo) commented about programs/cmd/wcmdmain.c:
> + len = lstrlenW(inputBuffer);
> + len2 = len;
> +
> + /* Update current input display in console */
> + set_cursor_visible(hOutput, FALSE);
> +
> + /* Calculate cursor position at beginning of prompt, accounting for lines scrolled
> + * due to length of input.
> + */
> + GetConsoleScreenBufferInfo(hOutput, ¤tConsoleInfo);
> + currentConsoleInfo.dwCursorPosition.X = startConsoleInfo.dwCursorPosition.X;
> + len2 -= (currentConsoleInfo.dwSize.X - currentConsoleInfo.dwCursorPosition.X);
> + if (len2 > 0) {
> + currentConsoleInfo.dwCursorPosition.Y -= ((len2 / currentConsoleInfo.dwSize.X) + 1);
> + }
> + SetConsoleCursorPosition(hOutput, currentConsoleInfo.dwCursorPosition);
did you try just reusing startConsoleInfo.dwCursorPosition here instead of recomputing the initial cursor position?
Actually I'm worried that we have to convert between cursor position from/to number of characters
- this makes assumptions about how the string is layed out (one vs multiple lines, one string character == one cell == one glyph on screen (this is not the case for CJK characters; if we support them one day))
- anyway, I don't see a simple straightforward way to do it (ReadConsole doesn't return the farthest cursor point where it has written to, and since it can be on multiple lines...).
- but the less code that does it, the better
the pain here comes from conhost wrapping the strings (in WriteConsole) larger than screen buffer width onto different lines... native use an unbounded line length and wraps it depending on window size.
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/7843#note_104473