GcToolKit/app/device.c

269 lines
5.8 KiB
C

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vitasdk.h>
#include "log.h"
#include "f00dbridge.h"
#include "device.h"
#include "mbr.h"
#include "vci.h"
#include "err.h"
#include "net.h"
#define DO_CHECKED(var, func, ...) \
int var = func(__VA_ARGS__); \
PRINT_STR(#var " = %x\n", var); \
if(var < 0) ERROR(var)
#define DEVICE_ACCESS_LOOP(rd_func, wr_func) \
do { \
int rd = rd_func(rd_fd, (void*)DEVICE_DUMP_BUFFER, sizeof(DEVICE_DUMP_BUFFER)); \
if(rd == 0) ERROR(-2); \
if(rd < 0) ERROR(rd); \
\
int wr = wr_func(wr_fd, (void*)DEVICE_DUMP_BUFFER, rd); \
if(wr == 0) ERROR(-3); \
if(wr < 0) ERROR(wr); \
\
total += wr; \
if(progress_callback != NULL) progress_callback(block_device, path, total, device_size); \
} while(total < device_size)
#define CREATE_VCI_HDR(wr_func) \
if(keys != NULL) { \
VciFile vci; \
memset(&vci, 0x00, sizeof(VciFile)); \
\
memcpy(vci.magic, VCI_HDR, sizeof(vci.magic)); \
vci.version = 1; \
vci.devicesize = device_size; \
memcpy(&vci.keys, keys, sizeof(GcKEYS)); \
\
int wr = wr_func(wr_fd, &vci, sizeof(VciFile)); \
PRINT_STR("wr = %x\n", wr); \
\
if(wr == 0) ERROR(-1); \
if(wr != sizeof(VciFile)) ERROR(wr * -1); \
if(wr < 0) ERROR(wr); \
}
#define CREATE_DEV_SZ(dev_fd) \
uint64_t device_size = 0; \
GetDeviceSize(dev_fd, &device_size); \
PRINT_STR("device_size = %llx\n", device_size); \
if(device_size == 0) ERROR(-1); \
if(progress_callback != NULL) progress_callback(block_device, block_device, total, device_size)\
#define SAFE_CHK() if(memcmp(block_device, "sdstor0:gcd", 11) != 0) ERROR(-128)
// exfatfs does each 0x20000 reading internally - Princess of Sleeping
static uint8_t DEVICE_DUMP_BUFFER[0x20000]__attribute__((aligned(0x40)));
char* mmc_vendor_id_to_manufacturer(uint8_t vendorId) {
char* vendor = "Unknown";
switch(vendorId) {
case 0x00:
vendor = "Sandisk";
break;
case 0x02:
vendor = "Kingston or SanDisk";
break;
case 0x03:
case 0x11:
vendor = "Toshiba";
break;
case 0x13:
vendor = "Micron";
break;
case 0x15:
vendor = "Samsung or SanDisk or LG";
break;
case 0x37:
vendor = "KingMax";
break;
case 0x44:
vendor = "ATP";
break;
case 0x45:
vendor = "SanDisk Corporation";
break;
case 0x2c:
case 0x70:
vendor = "Kingston";
break;
case 0x90:
vendor = "Hynix";
break;
case 0xfe:
vendor = "Micron";
break;
}
return vendor;
}
uint8_t device_exist(char* block_device) {
int dfd = OpenDevice(block_device, SCE_O_RDONLY);
if(dfd < 0)
return 0;
CloseDevice(dfd);
return 1;
}
uint64_t device_size(char* block_device) {
uint64_t device_size = 0;
int dfd = OpenDevice(block_device, SCE_O_RDONLY);
if(dfd < 0)
return 0;
GetDeviceSize(dfd, &device_size);
CloseDevice(dfd);
return device_size;
}
// device dump/restore
int read_null(SceUID fd, char* data, int size) {
memset(data, 0x00, size);
return size;
}
int read_data_from_image(SceUID fd, char* data, int size) {
int rd = sceIoRead(fd, data, size);
if(rd < 0) return rd;
// if there is remaining space, memset it to 0
if(rd < size) {
memset(data+rd, 0x00, size-rd);
}
return size;
}
int dump_device_network(char* ip_address, unsigned short port, char* block_device, char* path, GcKEYS* keys, void (*progress_callback)(char*, char*, uint64_t, uint64_t)) {
int ret = 0;
uint64_t total = 0;
PRINT_STR("Begining NETWORK dump of %s to %s:%u\n", block_device, ip_address, port);
// open device
DO_CHECKED(rd_fd, OpenDevice, block_device, SCE_O_RDONLY);
// get device size
CREATE_DEV_SZ(rd_fd);
// open socket
DO_CHECKED(wr_fd, begin_file_send, ip_address, port, path, (keys != NULL) ? device_size + sizeof(VciFile) : device_size);
// write vci header
CREATE_VCI_HDR(file_send_data);
// enter read/write loop
DEVICE_ACCESS_LOOP(ReadDevice, file_send_data);
error:
if(wr_fd >= 0)
end_file_send(wr_fd);
if(rd_fd >= 0)
CloseDevice(rd_fd);
return ret;
}
int dump_device(char* block_device, char* path, GcKEYS* keys, void (*progress_callback)(char*, char*, uint64_t, uint64_t)) {
int ret = 0;
uint64_t total = 0;
PRINT_STR("Begining dump of %s to %s\n", block_device, path);
// open device
DO_CHECKED(rd_fd, OpenDevice, block_device, SCE_O_RDONLY);
// open image file
DO_CHECKED(wr_fd, sceIoOpen, path, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
// get device size
CREATE_DEV_SZ(rd_fd);
// write vci header
CREATE_VCI_HDR(sceIoWrite);
// enter read/write loop
DEVICE_ACCESS_LOOP(ReadDevice, sceIoWrite);
error:
if(wr_fd >= 0)
sceIoClose(wr_fd);
if(rd_fd >= 0)
CloseDevice(rd_fd);
return ret;
}
int restore_device(char* block_device, char* path, void (*progress_callback)(char*, char*, uint64_t, uint64_t)) {
int ret = 0;
uint64_t total = 0;
SAFE_CHK();
PRINT_STR("Begining restore of %s to %s\n", path, block_device);
// get image file size
uint64_t img_file_sz = get_file_size(path);
PRINT_STR("img_file_sz = %llx\n", img_file_sz);
// open image file
DO_CHECKED(rd_fd, sceIoOpen, path, SCE_O_RDONLY, 0777);
// open device
DO_CHECKED(wr_fd, OpenDevice, block_device, SCE_O_WRONLY);
// get device size
CREATE_DEV_SZ(wr_fd);
if(img_file_sz > device_size) ERROR(-2);
// enter read/write loop
DEVICE_ACCESS_LOOP(read_data_from_image, WriteDevice);
error:
if(rd_fd >= 0)
sceIoClose(rd_fd);
if(wr_fd >= 0)
CloseDevice(wr_fd);
return ret;
}
int wipe_device(char* block_device, void (*progress_callback)(char*, char*, uint64_t, uint64_t)) {
int ret = 0;
uint64_t total = 0;
int rd_fd = 0;
char* path = NULL;
SAFE_CHK();
PRINT_STR("Begining wipe of %s\n", block_device);
// open device
DO_CHECKED(wr_fd, OpenDevice, block_device, SCE_O_WRONLY);
// get device size
CREATE_DEV_SZ(wr_fd);
// enter read/write loop
DEVICE_ACCESS_LOOP(read_null, WriteDevice);
error:
if(wr_fd >= 0)
CloseDevice(wr_fd);
return ret;
}