Files
AnyPS5/docs/dev/debt/libSceUsbStorage.md
simnJS 6988438d77 feat(libSceUsbStorage): pass host volumes through only with APS5_USB_STORAGE_PASSTHROUGH
Unset, ScanHostVolumes returns no volume, so nothing is scanned or
exposed and the guest sees no USB storage, as on main. The test checks
that injected volumes are neither listed nor raised by a rescan with the
switch off, and turns it on for the device cases.
2026-10-27 00:01:56 +01:00

11 KiB

libSceUsbStorage technical debt

Unknown function info

Functional

  • the host passthrough (libSceUsbStorage) - only with APS5_USB_STORAGE_PASSTHROUGH set; without it no host volume is scanned. The devices are the FAT and exFAT volumes the host mounted from USB mass-storage devices: on Linux the whole-file-system vfat, msdos and exfat entries of /proc/self/mountinfo whose block device sits under a USB interface of class 08 in sysfs, on Windows the drive letters whose FAT, FAT32 or exFAT volume reports BusTypeUsb, and none on macOS. NTFS and a FUSE exFAT (fuseblk) are not listed. sceUsbStorageInit scans the host and a service thread rescans it once a second; a volume keeps its id, the lowest free of eight slots, while it stays mounted, and /mnt/usb<id> resolves to its current root until a scan drops it or sceUsbStorageTerm. How the console numbers its devices is unknown. Closes when: measured on a PS5
  • sceUsbStorageUnregisterCallback (libSceUsbStorage) - it waits for a callback that is running, except when called from inside a callback, so a callback must not wait on a thread that is unregistering. Whether the console's unregistration waits is unknown. Closes when: measured on a PS5
  • the device-info record (libSceUsbStorage) - the 0x338-byte record is unverified on hardware; its layout follows SharpProspero, which recovered it from the module's own export: the u64 volume size at offset 0, the vendor, product and serial strings at 0x16, 0x120 and 0x228, and the flags the service masks with 0xd0 at 0x330. The vendor id, product id and release at 0x10, 0x12 and 0x14, the string lengths at 0x118, 0x220 and 0x328 and flag bits 4 (read-only), 6 (FAT) and 7 (exFAT) follow shadPS4, whose record otherwise starts with a device id where a title reads the volume size. Closes when: measured on a PS5
  • the device-info values (libSceUsbStorage) - which strings and which size the console reports is unknown. The volume size is the capacity of the mounted file system, not of the partition; the vendor and product are the SCSI inquiry strings (sysfs vendor and model, or the storage device descriptor on Windows) without trailing spaces, and the serial number is the USB one, empty when the device has none. A string longer than 255 bytes throws. Closes when: measured on a PS5
  • the map requests (libSceUsbStorage) - sceUsbStorageRequestMap and sceUsbStorageRequestMapWSB follow shadPS4: the mount point is /mnt/usb<id> followed by the requested directory (the device root for a null or empty one), the last argument receives 0 and null outputs are skipped. The directory must exist on the device; a missing one, a . or .. component, a component with a root name (a drive letter on Windows), a backslash, a mount point longer than 127 bytes, a second map of the same directory, nonzero flags or volume size, and a nonzero fourth RequestMapWSB argument throw, as their answers are unknown. Unlike shadPS4, a directory that starts with /mnt/usb is not returned unchanged. The mapping limit SharpProspero names (0x80f40015) is not enforced. Closes when: measured on a PS5
  • sceUsbStorageIsExist (libSceUsbStorage) - it reports whether the attached device holds the directory, resolved and refused as for a map request (the device root for a null or empty one), where shadPS4's one-argument version has no directory; what the console does with the directory or a null output, and whether the bool result reports success or failure, is unknown; a null output throws. Closes when: measured on a PS5
  • the getdents scan (libSceUsbStorage) - sceUsbStorageGetdentsOpen lists the root of the device into descriptors numbered from 1 with a 0x8000-byte buffer size, skipping names that start with a dot, and sceUsbStorageGetdentsRead writes shadPS4's packed dirent (u32 file number from 1, u16 record length rounded to 8, type 4 for a directory and 8 otherwise, u8 name length, NUL-terminated name) until the buffer is full and zero bytes at the end. A name longer than 255 bytes, a host listing error and a buffer too small for the next record throw where shadPS4 truncates, ignores or answers zero bytes. None of this is measured on a console. Closes when: measured on a PS5
  • the argument validation (libSceUsbStorage) - the null-pointer, null-callback, event-type and null-directory refusals with 0x80f40002, the answers 0x80f40004 for a device that is not attached, and the getdents read of a descriptor that is not open answering 0x80f40005 with zero bytes, follow shadPS4; the validation runs before the markers the exports keep above. None of this is measured on a console.
  • the prototypes of sceUsbStorageRequestMap and sceUsbStorageGetDeviceList (libSceUsbStorage) - the signatures follow the ABI restored on main (the firmware-database sweep of 2026-10-21), which matches shadPS4: RequestMap's six parameters, the typed UsbStorageCallback of the register/unregister family, IsExist's three-argument bool form and GetDeviceList's std::int32_t* count (the count also follows SharpProspero, whose earlier eight-parameter RequestMap reading carried the trailing reserved pair the restored ABI drops).