mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-06 13:30:00 +00:00
Nine of the twenty-one exports implement the no-device path: the lifecycle pair accepts every call and keeps no state, the device queries answer the empty list, the not-exists 0 and the device-not-found error, the map requests answer device-not-found with their outputs untouched, and the getdents family answers device-not-found on open and not-supported with zero bytes on the read of a never-opened descriptor. The argument validation of the register, unregister, unmap and getdents-close exports is implemented and answers 0x80f40002; past it they keep their markers, because no reference establishes their success path. The device-info record and two prototypes follow SharpProspero, the rest shadPS4, each pinned in the debt entry.
246 lines
13 KiB
C++
246 lines
13 KiB
C++
#include "prx/libSceUsbStorage/UsbStorage.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <string_view>
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceUsbStorageGetMountPointOfShellCore(unsigned int device, char* mountPoint);
|
|
int APS5_VABI sceUsbStorageClearFakeWriteProtection();
|
|
int APS5_VABI sceUsbStorageSetFakeMapLockForDebug();
|
|
int APS5_VABI sceUsbStorageSetFakeWriteProtection();
|
|
}
|
|
|
|
namespace {
|
|
|
|
int g_attr = 0;
|
|
|
|
void CallbackStub() {}
|
|
|
|
void* Callback() {
|
|
return reinterpret_cast<void*>(&CallbackStub);
|
|
}
|
|
|
|
void Require(bool condition, const char* message) {
|
|
if (!condition) {
|
|
std::fprintf(stderr, "USBSTORAGE: %s\n", message);
|
|
std::abort();
|
|
}
|
|
}
|
|
|
|
void TestInitializeAndTerminate() {
|
|
Require(sceUsbStorageInit(nullptr) == 0, "initialize with a null attribute");
|
|
Require(sceUsbStorageInit(&g_attr) == 0, "initialize with an attribute");
|
|
Require(sceUsbStorageTerm() == 0, "terminate");
|
|
Require(sceUsbStorageInit(nullptr) == 0, "initialize after terminate");
|
|
Require(sceUsbStorageTerm() == 0, "terminate again");
|
|
}
|
|
|
|
void TestRegisterCallbacks() {
|
|
bool threw = false;
|
|
try {
|
|
sceUsbStorageRegisterCallback(1, Callback(), nullptr);
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageRegisterCallback not implemented";
|
|
}
|
|
Require(threw, "register callback of event type 1 did not throw its marker");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageRegisterCallback(2, Callback(), nullptr);
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageRegisterCallback not implemented";
|
|
}
|
|
Require(threw, "register callback of event type 2 did not throw its marker");
|
|
Require(sceUsbStorageRegisterCallback(1, nullptr, nullptr) == UsbStorage::InvalidArgument, "register a null callback");
|
|
Require(sceUsbStorageRegisterCallback(0, Callback(), nullptr) == UsbStorage::InvalidArgument, "register callback of event type 0");
|
|
Require(sceUsbStorageRegisterCallback(3, Callback(), nullptr) == UsbStorage::InvalidArgument, "register callback of event type 3");
|
|
Require(sceUsbStorageRegisterCallback(-1, Callback(), nullptr) == UsbStorage::InvalidArgument, "register callback of a negative event type");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageUnregisterCallback(1, Callback());
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageUnregisterCallback not implemented";
|
|
}
|
|
Require(threw, "unregister callback of event type 1 did not throw its marker");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageUnregisterCallback(2, Callback());
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageUnregisterCallback not implemented";
|
|
}
|
|
Require(threw, "unregister callback of event type 2 did not throw its marker");
|
|
Require(sceUsbStorageUnregisterCallback(1, nullptr) == UsbStorage::InvalidArgument, "unregister a null callback");
|
|
Require(sceUsbStorageUnregisterCallback(0, Callback()) == UsbStorage::InvalidArgument, "unregister callback of event type 0");
|
|
}
|
|
|
|
void TestMapCallbacks() {
|
|
bool threw = false;
|
|
try {
|
|
sceUsbStorageRegisterCallbackForMapAvailable(0, "/data", Callback(), nullptr);
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageRegisterCallbackForMapAvailable not implemented";
|
|
}
|
|
Require(threw, "register map-available callback did not throw its marker");
|
|
Require(sceUsbStorageRegisterCallbackForMapAvailable(0, nullptr, Callback(), nullptr) == UsbStorage::InvalidArgument, "register map-available callback with a null directory");
|
|
Require(sceUsbStorageRegisterCallbackForMapAvailable(0, "/data", nullptr, nullptr) == UsbStorage::InvalidArgument, "register a null map-available callback");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageUnregisterCallbackForMapAvailable(0, "/data", Callback());
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageUnregisterCallbackForMapAvailable not implemented";
|
|
}
|
|
Require(threw, "unregister map-available callback did not throw its marker");
|
|
Require(sceUsbStorageUnregisterCallbackForMapAvailable(0, nullptr, Callback()) == UsbStorage::InvalidArgument, "unregister map-available callback with a null directory");
|
|
Require(sceUsbStorageUnregisterCallbackForMapAvailable(0, "/data", nullptr) == UsbStorage::InvalidArgument, "unregister a null map-available callback");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageRegisterCallbackForMapUnavailable(0, "/data", Callback(), nullptr);
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageRegisterCallbackForMapUnavailable not implemented";
|
|
}
|
|
Require(threw, "register map-unavailable callback did not throw its marker");
|
|
Require(sceUsbStorageRegisterCallbackForMapUnavailable(0, nullptr, Callback(), nullptr) == UsbStorage::InvalidArgument, "register map-unavailable callback with a null directory");
|
|
Require(sceUsbStorageRegisterCallbackForMapUnavailable(0, "/data", nullptr, nullptr) == UsbStorage::InvalidArgument, "register a null map-unavailable callback");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageUnregisterCallbackForMapUnavailable(0, "/data", Callback());
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageUnregisterCallbackForMapUnavailable not implemented";
|
|
}
|
|
Require(threw, "unregister map-unavailable callback did not throw its marker");
|
|
Require(sceUsbStorageUnregisterCallbackForMapUnavailable(0, nullptr, Callback()) == UsbStorage::InvalidArgument, "unregister map-unavailable callback with a null directory");
|
|
Require(sceUsbStorageUnregisterCallbackForMapUnavailable(0, "/data", nullptr) == UsbStorage::InvalidArgument, "unregister a null map-unavailable callback");
|
|
}
|
|
|
|
void TestNoDevice() {
|
|
std::uint32_t devices[4]{0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a};
|
|
std::int32_t count = -1;
|
|
Require(sceUsbStorageGetDeviceList(devices, &count) == 0, "get the device list");
|
|
Require(count == 0, "no usb storage device is attached");
|
|
Require(devices[0] == 0x5a5a5a5a && devices[3] == 0x5a5a5a5a, "the device list was written");
|
|
Require(sceUsbStorageGetDeviceList(nullptr, &count) == UsbStorage::InvalidArgument, "get the device list without a device array");
|
|
Require(sceUsbStorageGetDeviceList(devices, nullptr) == UsbStorage::InvalidArgument, "get the device list without a count");
|
|
|
|
std::uint8_t info[16];
|
|
std::memset(info, 0x5a, sizeof(info));
|
|
Require(sceUsbStorageGetDeviceInfo(0, info) == UsbStorage::DeviceNotFound, "get device info of device 0");
|
|
Require(sceUsbStorageGetDeviceInfo(1, info) == UsbStorage::DeviceNotFound, "get device info of device 1");
|
|
Require(info[0] == 0x5a && info[15] == 0x5a, "device info was written");
|
|
Require(sceUsbStorageGetDeviceInfo(0, nullptr) == UsbStorage::InvalidArgument, "get device info without an info buffer");
|
|
|
|
Require(sceUsbStorageIsExist(0) == 0, "device 0 does not exist");
|
|
Require(sceUsbStorageIsExist(1) == 0, "device 1 does not exist");
|
|
Require(sceUsbStorageIsExist(0xffffffffu) == 0, "no device id exists");
|
|
}
|
|
|
|
void TestMapRequests() {
|
|
char mountPoint[16];
|
|
std::uint64_t mountId = 0x5a5a5a5a5a5a5a5aull;
|
|
std::int32_t status = 0x5a5a5a5a;
|
|
std::memset(mountPoint, 0x5a, sizeof(mountPoint));
|
|
Require(sceUsbStorageRequestMap(0, "/data", 0, 0, mountPoint, &mountId, nullptr, 0) == UsbStorage::DeviceNotFound, "request a map of device 0");
|
|
Require(sceUsbStorageRequestMap(1, nullptr, 0, 0, nullptr, nullptr, nullptr, 0) == UsbStorage::DeviceNotFound, "request a map of device 1");
|
|
Require(mountId == 0x5a5a5a5a5a5a5a5aull && mountPoint[0] == static_cast<char>(0x5a), "the map request wrote its outputs");
|
|
std::memset(mountPoint, 0x5a, sizeof(mountPoint));
|
|
Require(sceUsbStorageRequestMapWSB(0, "/data", 0, 0, mountPoint, &status) == UsbStorage::DeviceNotFound, "request a WSB map of device 0");
|
|
Require(sceUsbStorageRequestMapWSB(0, nullptr, 0, 0, nullptr, nullptr) == UsbStorage::DeviceNotFound, "request a WSB map without a subpath");
|
|
Require(mountPoint[0] == static_cast<char>(0x5a) && status == 0x5a5a5a5a, "the WSB map request wrote its outputs");
|
|
Require(sceUsbStorageRequestUnmap(0, nullptr) == UsbStorage::InvalidArgument, "unmap a null directory");
|
|
bool threw = false;
|
|
try {
|
|
sceUsbStorageRequestUnmap(0, "/mnt/usb0");
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageRequestUnmap not implemented";
|
|
}
|
|
Require(threw, "unmap a directory did not throw its marker");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageRequestUnmap(7, "/mnt/usb7");
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageRequestUnmap not implemented";
|
|
}
|
|
Require(threw, "unmap a directory of another device did not throw its marker");
|
|
}
|
|
|
|
void TestGetdents() {
|
|
std::int32_t fd = -1;
|
|
std::uint64_t bufferSize = 0x5a5a5a5a5a5a5a5aull;
|
|
Require(sceUsbStorageGetdentsOpen(0, &fd, &bufferSize) == UsbStorage::DeviceNotFound, "open a getdents scan of device 0");
|
|
Require(sceUsbStorageGetdentsOpen(3, &fd, &bufferSize) == UsbStorage::DeviceNotFound, "open a getdents scan of device 3");
|
|
Require(fd == -1 && bufferSize == 0x5a5a5a5a5a5a5a5aull, "the getdents open wrote its outputs");
|
|
Require(sceUsbStorageGetdentsOpen(0, nullptr, &bufferSize) == UsbStorage::InvalidArgument, "open a getdents scan without a descriptor");
|
|
Require(sceUsbStorageGetdentsOpen(0, &fd, nullptr) == UsbStorage::InvalidArgument, "open a getdents scan without a buffer size");
|
|
|
|
std::uint8_t buffer[64];
|
|
std::uint64_t bytesRead = 0x5a5a5a5a5a5a5a5aull;
|
|
std::memset(buffer, 0x5a, sizeof(buffer));
|
|
Require(sceUsbStorageGetdentsRead(1, buffer, sizeof(buffer), &bytesRead) == UsbStorage::NotSupported, "read a getdents scan that was never opened");
|
|
Require(bytesRead == 0, "the getdents read did not answer zero bytes");
|
|
Require(buffer[0] == 0x5a, "the getdents read wrote the buffer");
|
|
Require(sceUsbStorageGetdentsRead(1, nullptr, sizeof(buffer), &bytesRead) == UsbStorage::InvalidArgument, "read a getdents scan without a buffer");
|
|
Require(sceUsbStorageGetdentsRead(1, buffer, sizeof(buffer), nullptr) == UsbStorage::InvalidArgument, "read a getdents scan without a byte count");
|
|
|
|
bool threw = false;
|
|
try {
|
|
sceUsbStorageGetdentsClose(1);
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageGetdentsClose not implemented";
|
|
}
|
|
Require(threw, "close a getdents scan that was never opened did not throw its marker");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageGetdentsClose(0);
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageGetdentsClose not implemented";
|
|
}
|
|
Require(threw, "close descriptor 0 did not throw its marker");
|
|
}
|
|
|
|
void TestThrowingExports() {
|
|
char mountPoint[8]{};
|
|
bool threw = false;
|
|
try {
|
|
sceUsbStorageGetMountPointOfShellCore(0, mountPoint);
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageGetMountPointOfShellCore not implemented";
|
|
}
|
|
Require(threw, "get the mount point of shell core did not throw its marker");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageClearFakeWriteProtection();
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageClearFakeWriteProtection not implemented";
|
|
}
|
|
Require(threw, "clear fake write protection did not throw its marker");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageSetFakeMapLockForDebug();
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageSetFakeMapLockForDebug not implemented";
|
|
}
|
|
Require(threw, "set fake map lock for debug did not throw its marker");
|
|
threw = false;
|
|
try {
|
|
sceUsbStorageSetFakeWriteProtection();
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string_view(error.what()) == "sceUsbStorageSetFakeWriteProtection not implemented";
|
|
}
|
|
Require(threw, "set fake write protection did not throw its marker");
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
TestInitializeAndTerminate();
|
|
TestRegisterCallbacks();
|
|
TestMapCallbacks();
|
|
TestNoDevice();
|
|
TestMapRequests();
|
|
TestGetdents();
|
|
TestThrowingExports();
|
|
return 0;
|
|
}
|