mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Common interface for FAT / virtual files
This commit is contained in:
parent
2c271fb97e
commit
d15b850a86
@ -1,6 +1,5 @@
|
|||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "sddata.h"
|
#include "vff.h"
|
||||||
#include "ff.h"
|
|
||||||
|
|
||||||
static FIL mount_file;
|
static FIL mount_file;
|
||||||
static u32 mount_state = 0;
|
static u32 mount_state = 0;
|
||||||
@ -13,11 +12,11 @@ int ReadImageBytes(u8* buffer, u64 offset, u64 count) {
|
|||||||
UINT ret;
|
UINT ret;
|
||||||
if (!count) return -1;
|
if (!count) return -1;
|
||||||
if (!mount_state) return FR_INVALID_OBJECT;
|
if (!mount_state) return FR_INVALID_OBJECT;
|
||||||
if (f_tell(&mount_file) != offset) {
|
if (fvx_tell(&mount_file) != offset) {
|
||||||
if (f_size(&mount_file) < offset) return -1;
|
if (fvx_size(&mount_file) < offset) return -1;
|
||||||
f_lseek(&mount_file, offset);
|
fvx_lseek(&mount_file, offset);
|
||||||
}
|
}
|
||||||
ret = fx_read(&mount_file, buffer, count, &bytes_read);
|
ret = fvx_read(&mount_file, buffer, count, &bytes_read);
|
||||||
return (ret != 0) ? (int) ret : (bytes_read != count) ? -1 : 0;
|
return (ret != 0) ? (int) ret : (bytes_read != count) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,9 +25,9 @@ int WriteImageBytes(const u8* buffer, u64 offset, u64 count) {
|
|||||||
UINT ret;
|
UINT ret;
|
||||||
if (!count) return -1;
|
if (!count) return -1;
|
||||||
if (!mount_state) return FR_INVALID_OBJECT;
|
if (!mount_state) return FR_INVALID_OBJECT;
|
||||||
if (f_tell(&mount_file) != offset)
|
if (fvx_tell(&mount_file) != offset)
|
||||||
f_lseek(&mount_file, offset);
|
fvx_lseek(&mount_file, offset);
|
||||||
ret = fx_write(&mount_file, buffer, count, &bytes_written);
|
ret = fvx_write(&mount_file, buffer, count, &bytes_written);
|
||||||
return (ret != 0) ? (int) ret : (bytes_written != count) ? -1 : 0;
|
return (ret != 0) ? (int) ret : (bytes_written != count) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,11 +40,11 @@ int WriteImageSectors(const u8* buffer, u32 sector, u32 count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int SyncImage(void) {
|
int SyncImage(void) {
|
||||||
return mount_state ? f_sync(&mount_file) : FR_INVALID_OBJECT;
|
return mount_state ? fvx_sync(&mount_file) : FR_INVALID_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetMountSize(void) {
|
u64 GetMountSize(void) {
|
||||||
return mount_state ? f_size(&mount_file) : 0;
|
return mount_state ? fvx_size(&mount_file) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetMountState(void) {
|
u32 GetMountState(void) {
|
||||||
@ -59,16 +58,16 @@ const char* GetMountPath(void) {
|
|||||||
u32 MountImage(const char* path) {
|
u32 MountImage(const char* path) {
|
||||||
u32 type = (path) ? IdentifyFileType(path) : 0;
|
u32 type = (path) ? IdentifyFileType(path) : 0;
|
||||||
if (mount_state) {
|
if (mount_state) {
|
||||||
fx_close(&mount_file);
|
fvx_close(&mount_file);
|
||||||
mount_state = 0;
|
mount_state = 0;
|
||||||
*mount_path = 0;
|
*mount_path = 0;
|
||||||
}
|
}
|
||||||
if (!type) return 0;
|
if (!type) return 0;
|
||||||
if ((fx_open(&mount_file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) &&
|
if ((fvx_open(&mount_file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) &&
|
||||||
(fx_open(&mount_file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK))
|
(fvx_open(&mount_file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK))
|
||||||
return 0;
|
return 0;
|
||||||
f_lseek(&mount_file, 0);
|
fvx_lseek(&mount_file, 0);
|
||||||
f_sync(&mount_file);
|
fvx_sync(&mount_file);
|
||||||
strncpy(mount_path, path, 255);
|
strncpy(mount_path, path, 255);
|
||||||
return (mount_state = type);
|
return (mount_state = type);
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,9 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "fsperm.h"
|
#include "fsperm.h"
|
||||||
#include "filetype.h"
|
#include "filetype.h"
|
||||||
#include "sddata.h"
|
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "ff.h"
|
#include "vff.h"
|
||||||
|
|
||||||
u32 GetOutputPath(char* dest, const char* path, const char* ext) {
|
u32 GetOutputPath(char* dest, const char* path, const char* ext) {
|
||||||
// special handling for input from title directories (somewhat hacky)
|
// special handling for input from title directories (somewhat hacky)
|
||||||
@ -36,17 +35,17 @@ u32 GetOutputPath(char* dest, const char* path, const char* ext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, FIL* file) {
|
u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, FIL* file) {
|
||||||
u32 offset_ncch = f_tell(file);
|
u32 offset_ncch = fvx_tell(file);
|
||||||
UINT btr;
|
UINT btr;
|
||||||
|
|
||||||
if ((fx_read(file, ncch, sizeof(NcchHeader), &btr) != FR_OK) ||
|
if ((fvx_read(file, ncch, sizeof(NcchHeader), &btr) != FR_OK) ||
|
||||||
(ValidateNcchHeader(ncch) != 0))
|
(ValidateNcchHeader(ncch) != 0))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (exthdr) {
|
if (exthdr) {
|
||||||
if (!ncch->size_exthdr) return 1;
|
if (!ncch->size_exthdr) return 1;
|
||||||
f_lseek(file, offset_ncch + NCCH_EXTHDR_OFFSET);
|
fvx_lseek(file, offset_ncch + NCCH_EXTHDR_OFFSET);
|
||||||
if ((fx_read(file, exthdr, NCCH_EXTHDR_SIZE, &btr) != FR_OK) ||
|
if ((fvx_read(file, exthdr, NCCH_EXTHDR_SIZE, &btr) != FR_OK) ||
|
||||||
(DecryptNcch((u8*) exthdr, NCCH_EXTHDR_OFFSET, NCCH_EXTHDR_SIZE, ncch, NULL) != 0))
|
(DecryptNcch((u8*) exthdr, NCCH_EXTHDR_OFFSET, NCCH_EXTHDR_SIZE, ncch, NULL) != 0))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -54,8 +53,8 @@ u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs,
|
|||||||
if (exefs) {
|
if (exefs) {
|
||||||
if (!ncch->size_exefs) return 1;
|
if (!ncch->size_exefs) return 1;
|
||||||
u32 offset_exefs = offset_ncch + (ncch->offset_exefs * NCCH_MEDIA_UNIT);
|
u32 offset_exefs = offset_ncch + (ncch->offset_exefs * NCCH_MEDIA_UNIT);
|
||||||
f_lseek(file, offset_exefs);
|
fvx_lseek(file, offset_exefs);
|
||||||
if ((fx_read(file, exefs, sizeof(ExeFsHeader), &btr) != FR_OK) ||
|
if ((fvx_read(file, exefs, sizeof(ExeFsHeader), &btr) != FR_OK) ||
|
||||||
(DecryptNcch((u8*) exefs, ncch->offset_exefs * NCCH_MEDIA_UNIT, sizeof(ExeFsHeader), ncch, NULL) != 0) ||
|
(DecryptNcch((u8*) exefs, ncch->offset_exefs * NCCH_MEDIA_UNIT, sizeof(ExeFsHeader), ncch, NULL) != 0) ||
|
||||||
(ValidateExeFsHeader(exefs, ncch->size_exefs * NCCH_MEDIA_UNIT) != 0))
|
(ValidateExeFsHeader(exefs, ncch->size_exefs * NCCH_MEDIA_UNIT) != 0))
|
||||||
return 1;
|
return 1;
|
||||||
@ -65,14 +64,14 @@ u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 CheckNcchHash(u8* expected, FIL* file, u32 size_data, u32 offset_ncch, NcchHeader* ncch, ExeFsHeader* exefs) {
|
u32 CheckNcchHash(u8* expected, FIL* file, u32 size_data, u32 offset_ncch, NcchHeader* ncch, ExeFsHeader* exefs) {
|
||||||
u32 offset_data = f_tell(file) - offset_ncch;
|
u32 offset_data = fvx_tell(file) - offset_ncch;
|
||||||
u8 hash[32];
|
u8 hash[32];
|
||||||
|
|
||||||
sha_init(SHA256_MODE);
|
sha_init(SHA256_MODE);
|
||||||
for (u32 i = 0; i < size_data; i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; i < size_data; i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size_data - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size_data - i));
|
||||||
UINT bytes_read;
|
UINT bytes_read;
|
||||||
fx_read(file, MAIN_BUFFER, read_bytes, &bytes_read);
|
fvx_read(file, MAIN_BUFFER, read_bytes, &bytes_read);
|
||||||
DecryptNcch(MAIN_BUFFER, offset_data + i, read_bytes, ncch, exefs);
|
DecryptNcch(MAIN_BUFFER, offset_data + i, read_bytes, ncch, exefs);
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
sha_update(MAIN_BUFFER, read_bytes);
|
||||||
}
|
}
|
||||||
@ -85,14 +84,14 @@ u32 LoadNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs,
|
|||||||
FIL file;
|
FIL file;
|
||||||
|
|
||||||
// open file, get NCCH header
|
// open file, get NCCH header
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&file, offset);
|
fvx_lseek(&file, offset);
|
||||||
if (GetNcchHeaders(ncch, exthdr, exefs, &file) != 0) {
|
if (GetNcchHeaders(ncch, exthdr, exefs, &file) != 0) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -102,15 +101,15 @@ u32 LoadNcsdHeader(NcsdHeader* ncsd, const char* path) {
|
|||||||
UINT btr;
|
UINT btr;
|
||||||
|
|
||||||
// open file, get NCSD header
|
// open file, get NCSD header
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_read(&file, ncsd, sizeof(NcsdHeader), &btr) != FR_OK) ||
|
if ((fvx_read(&file, ncsd, sizeof(NcsdHeader), &btr) != FR_OK) ||
|
||||||
(ValidateNcsdHeader(ncsd) != 0)) {
|
(ValidateNcsdHeader(ncsd) != 0)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -120,26 +119,26 @@ u32 LoadCiaStub(CiaStub* stub, const char* path) {
|
|||||||
UINT btr;
|
UINT btr;
|
||||||
CiaInfo info;
|
CiaInfo info;
|
||||||
|
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// first 0x20 byte of CIA header
|
// first 0x20 byte of CIA header
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_read(&file, stub, 0x20, &btr) != FR_OK) || (btr != 0x20) ||
|
if ((fvx_read(&file, stub, 0x20, &btr) != FR_OK) || (btr != 0x20) ||
|
||||||
(ValidateCiaHeader(&(stub->header)) != 0)) {
|
(ValidateCiaHeader(&(stub->header)) != 0)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
GetCiaInfo(&info, &(stub->header));
|
GetCiaInfo(&info, &(stub->header));
|
||||||
|
|
||||||
// everything up till content offset
|
// everything up till content offset
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_read(&file, stub, info.offset_content, &btr) != FR_OK) || (btr != info.offset_content)) {
|
if ((fvx_read(&file, stub, info.offset_content, &btr) != FR_OK) || (btr != info.offset_content)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,12 +150,12 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3
|
|||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
|
|
||||||
// open file, get NCCH, ExeFS header
|
// open file, get NCCH, ExeFS header
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&file, offset);
|
fvx_lseek(&file, offset);
|
||||||
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0) ||
|
if ((GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0) ||
|
||||||
(!ncch.size_exefs)) {
|
(!ncch.size_exefs)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,15 +173,15 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3
|
|||||||
if (exefile) {
|
if (exefile) {
|
||||||
u32 size_exefile = exefile->size;
|
u32 size_exefile = exefile->size;
|
||||||
u32 offset_exefile = (ncch.offset_exefs * NCCH_MEDIA_UNIT) + sizeof(ExeFsHeader) + exefile->offset;
|
u32 offset_exefile = (ncch.offset_exefs * NCCH_MEDIA_UNIT) + sizeof(ExeFsHeader) + exefile->offset;
|
||||||
f_lseek(&file, offset + offset_exefile); // offset to file
|
fvx_lseek(&file, offset + offset_exefile); // offset to file
|
||||||
if ((fx_read(&file, data, size_exefile, &btr) != FR_OK) ||
|
if ((fvx_read(&file, data, size_exefile, &btr) != FR_OK) ||
|
||||||
(DecryptNcch(data, offset_exefile, size_exefile, &ncch, &exefs) != 0) ||
|
(DecryptNcch(data, offset_exefile, size_exefile, &ncch, &exefs) != 0) ||
|
||||||
(btr != size_exefile)) {
|
(btr != size_exefile)) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
} else ret = 1;
|
} else ret = 1;
|
||||||
|
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,19 +203,19 @@ u32 LoadTmdFile(TitleMetaData* tmd, const char* path) {
|
|||||||
FIL file;
|
FIL file;
|
||||||
UINT btr;
|
UINT btr;
|
||||||
|
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// full TMD file
|
// full TMD file
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_read(&file, tmd, TMD_SIZE_MAX, &btr) != FR_OK) ||
|
if ((fvx_read(&file, tmd, TMD_SIZE_MAX, &btr) != FR_OK) ||
|
||||||
(memcmp(tmd->sig_type, magic, sizeof(magic)) != 0) ||
|
(memcmp(tmd->sig_type, magic, sizeof(magic)) != 0) ||
|
||||||
(btr < TMD_SIZE_N(getbe16(tmd->content_count)))) {
|
(btr < TMD_SIZE_N(getbe16(tmd->content_count)))) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,15 +227,15 @@ u32 WriteCiaStub(CiaStub* stub, const char* path) {
|
|||||||
GetCiaInfo(&info, &(stub->header));
|
GetCiaInfo(&info, &(stub->header));
|
||||||
|
|
||||||
// everything up till content offset
|
// everything up till content offset
|
||||||
if (fx_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS) != FR_OK)
|
if (fvx_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_write(&file, stub, info.offset_content, &btw) != FR_OK) || (btw != info.offset_content)) {
|
if ((fvx_write(&file, stub, info.offset_content, &btw) != FR_OK) || (btw != info.offset_content)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,26 +249,26 @@ u32 VerifyTmdContent(const char* path, u64 offset, TmdContentChunk* chunk, const
|
|||||||
bool encrypted = getbe16(chunk->type) & 0x1;
|
bool encrypted = getbe16(chunk->type) & 0x1;
|
||||||
|
|
||||||
if (!ShowProgress(0, 0, path)) return 1;
|
if (!ShowProgress(0, 0, path)) return 1;
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
if (offset + size > f_size(&file)) {
|
if (offset + size > fvx_size(&file)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
f_lseek(&file, offset);
|
fvx_lseek(&file, offset);
|
||||||
|
|
||||||
GetTmdCtr(ctr, chunk);
|
GetTmdCtr(ctr, chunk);
|
||||||
sha_init(SHA256_MODE);
|
sha_init(SHA256_MODE);
|
||||||
for (u32 i = 0; i < size; i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; i < size; i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
UINT bytes_read;
|
UINT bytes_read;
|
||||||
fx_read(&file, MAIN_BUFFER, read_bytes, &bytes_read);
|
fvx_read(&file, MAIN_BUFFER, read_bytes, &bytes_read);
|
||||||
if (encrypted) DecryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey);
|
if (encrypted) DecryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey);
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
sha_update(MAIN_BUFFER, read_bytes);
|
||||||
if (!ShowProgress(i + read_bytes, size, path)) break;
|
if (!ShowProgress(i + read_bytes, size, path)) break;
|
||||||
}
|
}
|
||||||
sha_get(hash);
|
sha_get(hash);
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
|
|
||||||
return memcmp(hash, expected, 32);
|
return memcmp(hash, expected, 32);
|
||||||
}
|
}
|
||||||
@ -283,35 +282,35 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
|
|||||||
TruncateString(pathstr, path, 32, 8);
|
TruncateString(pathstr, path, 32, 8);
|
||||||
|
|
||||||
// open file, get NCCH, ExeFS header
|
// open file, get NCCH, ExeFS header
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
f_lseek(&file, offset);
|
fvx_lseek(&file, offset);
|
||||||
if (GetNcchHeaders(&ncch, NULL, NULL, &file) != 0) {
|
if (GetNcchHeaders(&ncch, NULL, NULL, &file) != 0) {
|
||||||
if (!offset) ShowPrompt(false, "%s\nError: Not a NCCH file", pathstr);
|
if (!offset) ShowPrompt(false, "%s\nError: Not a NCCH file", pathstr);
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
f_lseek(&file, offset);
|
fvx_lseek(&file, offset);
|
||||||
if (ncch.size_exefs && (GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0)) {
|
if (ncch.size_exefs && (GetNcchHeaders(&ncch, NULL, &exefs, &file) != 0)) {
|
||||||
if (!offset) ShowPrompt(false, "%s\nError: Bad ExeFS header", pathstr);
|
if (!offset) ShowPrompt(false, "%s\nError: Bad ExeFS header", pathstr);
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// size checks
|
// size checks
|
||||||
if (!size) size = f_size(&file) - offset;
|
if (!size) size = fvx_size(&file) - offset;
|
||||||
if ((f_size(&file) < offset) || (size < ncch.size * NCCH_MEDIA_UNIT)) {
|
if ((fvx_size(&file) < offset) || (size < ncch.size * NCCH_MEDIA_UNIT)) {
|
||||||
if (!offset) ShowPrompt(false, "%s\nError: File is too small", pathstr);
|
if (!offset) ShowPrompt(false, "%s\nError: File is too small", pathstr);
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check / setup crypto
|
// check / setup crypto
|
||||||
if (SetupNcchCrypto(&ncch) != 0) {
|
if (SetupNcchCrypto(&ncch) != 0) {
|
||||||
if (!offset) ShowPrompt(false, "%s\nError: Crypto not set up", pathstr);
|
if (!offset) ShowPrompt(false, "%s\nError: Crypto not set up", pathstr);
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,19 +320,19 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
|
|||||||
|
|
||||||
// base hash check for extheader
|
// base hash check for extheader
|
||||||
if (ncch.size_exthdr > 0) {
|
if (ncch.size_exthdr > 0) {
|
||||||
f_lseek(&file, offset + NCCH_EXTHDR_OFFSET);
|
fvx_lseek(&file, offset + NCCH_EXTHDR_OFFSET);
|
||||||
ver_exthdr = CheckNcchHash(ncch.hash_exthdr, &file, 0x400, offset, &ncch, NULL);
|
ver_exthdr = CheckNcchHash(ncch.hash_exthdr, &file, 0x400, offset, &ncch, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// base hash check for exefs
|
// base hash check for exefs
|
||||||
if (ncch.size_exefs > 0) {
|
if (ncch.size_exefs > 0) {
|
||||||
f_lseek(&file, offset + (ncch.offset_exefs * NCCH_MEDIA_UNIT));
|
fvx_lseek(&file, offset + (ncch.offset_exefs * NCCH_MEDIA_UNIT));
|
||||||
ver_exefs = CheckNcchHash(ncch.hash_exefs, &file, ncch.size_exefs_hash * NCCH_MEDIA_UNIT, offset, &ncch, &exefs);
|
ver_exefs = CheckNcchHash(ncch.hash_exefs, &file, ncch.size_exefs_hash * NCCH_MEDIA_UNIT, offset, &ncch, &exefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// base hash check for romfs
|
// base hash check for romfs
|
||||||
if (ncch.size_romfs > 0) {
|
if (ncch.size_romfs > 0) {
|
||||||
f_lseek(&file, offset + (ncch.offset_romfs * NCCH_MEDIA_UNIT));
|
fvx_lseek(&file, offset + (ncch.offset_romfs * NCCH_MEDIA_UNIT));
|
||||||
ver_romfs = CheckNcchHash(ncch.hash_romfs, &file, ncch.size_romfs_hash * NCCH_MEDIA_UNIT, offset, &ncch, NULL);
|
ver_romfs = CheckNcchHash(ncch.hash_romfs, &file, ncch.size_romfs_hash * NCCH_MEDIA_UNIT, offset, &ncch, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +342,7 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
|
|||||||
ExeFsFileHeader* exefile = exefs.files + i;
|
ExeFsFileHeader* exefile = exefs.files + i;
|
||||||
u8* hash = exefs.hashes[9 - i];
|
u8* hash = exefs.hashes[9 - i];
|
||||||
if (!exefile->size) continue;
|
if (!exefile->size) continue;
|
||||||
f_lseek(&file, offset + (ncch.offset_exefs * NCCH_MEDIA_UNIT) + 0x200 + exefile->offset);
|
fvx_lseek(&file, offset + (ncch.offset_exefs * NCCH_MEDIA_UNIT) + 0x200 + exefile->offset);
|
||||||
ver_exefs = CheckNcchHash(hash, &file, exefile->size, offset, &ncch, &exefs);
|
ver_exefs = CheckNcchHash(hash, &file, exefile->size, offset, &ncch, &exefs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,7 +354,7 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) {
|
|||||||
(!ncch.size_romfs) ? "-" : (ver_romfs == 0) ? "ok" : "fail");
|
(!ncch.size_romfs) ? "-" : (ver_romfs == 0) ? "ok" : "fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return ver_exthdr|ver_exefs|ver_romfs;
|
return ver_exthdr|ver_exefs|ver_romfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,12 +467,12 @@ u32 VerifyFirmFile(const char* path) {
|
|||||||
UINT btr;
|
UINT btr;
|
||||||
|
|
||||||
// open file, get FIRM header
|
// open file, get FIRM header
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_read(&file, &header, sizeof(FirmHeader), &btr) != FR_OK) ||
|
if ((fvx_read(&file, &header, sizeof(FirmHeader), &btr) != FR_OK) ||
|
||||||
(ValidateFirmHeader(&header) != 0)) {
|
(ValidateFirmHeader(&header) != 0)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,11 +481,11 @@ u32 VerifyFirmFile(const char* path) {
|
|||||||
FirmSectionHeader* section = header.sections + i;
|
FirmSectionHeader* section = header.sections + i;
|
||||||
u32 size = section->size;
|
u32 size = section->size;
|
||||||
if (!size) continue;
|
if (!size) continue;
|
||||||
f_lseek(&file, section->offset);
|
fvx_lseek(&file, section->offset);
|
||||||
sha_init(SHA256_MODE);
|
sha_init(SHA256_MODE);
|
||||||
for (u32 i = 0; i < size; i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; i < size; i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
fx_read(&file, MAIN_BUFFER, read_bytes, &btr);
|
fvx_read(&file, MAIN_BUFFER, read_bytes, &btr);
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
sha_update(MAIN_BUFFER, read_bytes);
|
||||||
}
|
}
|
||||||
u8 hash[0x20];
|
u8 hash[0x20];
|
||||||
@ -495,11 +494,11 @@ u32 VerifyFirmFile(const char* path) {
|
|||||||
char pathstr[32 + 1];
|
char pathstr[32 + 1];
|
||||||
TruncateString(pathstr, path, 32, 8);
|
TruncateString(pathstr, path, 32, 8);
|
||||||
ShowPrompt(false, "%s\nSection %u hash mismatch", pathstr, i);
|
ShowPrompt(false, "%s\nSection %u hash mismatch", pathstr, i);
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -573,12 +572,12 @@ u32 CheckEncryptedFirmFile(const char* path) {
|
|||||||
UINT btr;
|
UINT btr;
|
||||||
|
|
||||||
// open file, get FIRM header
|
// open file, get FIRM header
|
||||||
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_read(&file, &header, sizeof(FirmHeader), &btr) != FR_OK) ||
|
if ((fvx_read(&file, &header, sizeof(FirmHeader), &btr) != FR_OK) ||
|
||||||
(ValidateFirmHeader(&header) != 0)) {
|
(ValidateFirmHeader(&header) != 0)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,15 +585,15 @@ u32 CheckEncryptedFirmFile(const char* path) {
|
|||||||
FirmSectionHeader* arm9s = FindFirmArm9Section(&header);
|
FirmSectionHeader* arm9s = FindFirmArm9Section(&header);
|
||||||
if (arm9s) {
|
if (arm9s) {
|
||||||
FirmA9LHeader a9l;
|
FirmA9LHeader a9l;
|
||||||
f_lseek(&file, arm9s->offset);
|
fvx_lseek(&file, arm9s->offset);
|
||||||
if ((fx_read(&file, &a9l, sizeof(FirmA9LHeader), &btr) == FR_OK) &&
|
if ((fvx_read(&file, &a9l, sizeof(FirmA9LHeader), &btr) == FR_OK) &&
|
||||||
(ValidateFirmA9LHeader(&a9l) == 0)) {
|
(ValidateFirmA9LHeader(&a9l) == 0)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,21 +622,21 @@ u32 DecryptNcchNcsdFirmFile(const char* orig, const char* dest, u32 mode,
|
|||||||
|
|
||||||
// open file(s)
|
// open file(s)
|
||||||
if (inplace) {
|
if (inplace) {
|
||||||
if (fx_open(ofp, orig, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(ofp, orig, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(ofp, offset);
|
fvx_lseek(ofp, offset);
|
||||||
} else {
|
} else {
|
||||||
if (fx_open(ofp, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(ofp, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
if (fx_open(dfp, dest, FA_WRITE | (offset ? FA_OPEN_ALWAYS : FA_CREATE_ALWAYS)) != FR_OK) {
|
if (fvx_open(dfp, dest, FA_WRITE | (offset ? FA_OPEN_ALWAYS : FA_CREATE_ALWAYS)) != FR_OK) {
|
||||||
fx_close(ofp);
|
fvx_close(ofp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
f_lseek(ofp, offset);
|
fvx_lseek(ofp, offset);
|
||||||
f_lseek(dfp, offset);
|
fvx_lseek(dfp, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
fsize = f_size(ofp); // for progress bar
|
fsize = fvx_size(ofp); // for progress bar
|
||||||
if (!size) size = fsize;
|
if (!size) size = fsize;
|
||||||
|
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
@ -646,13 +645,13 @@ u32 DecryptNcchNcsdFirmFile(const char* orig, const char* dest, u32 mode,
|
|||||||
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
UINT bytes_read, bytes_written;
|
UINT bytes_read, bytes_written;
|
||||||
if (fx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
||||||
if (((mode & GAME_NCCH) && (DecryptNcchSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
if (((mode & GAME_NCCH) && (DecryptNcchSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
||||||
((mode & GAME_NCSD) && (DecryptNcsdSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
((mode & GAME_NCSD) && (DecryptNcsdSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
||||||
((mode & SYS_FIRM) && (DecryptFirmSequential(MAIN_BUFFER, i, read_bytes) != 0)))
|
((mode & SYS_FIRM) && (DecryptFirmSequential(MAIN_BUFFER, i, read_bytes) != 0)))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
if (inplace) f_lseek(ofp, f_tell(ofp) - read_bytes);
|
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
||||||
if (fx_write(dfp, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
if (fvx_write(dfp, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
||||||
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
|
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
|
||||||
if (!ShowProgress(offset + i + read_bytes, fsize, dest)) ret = 1;
|
if (!ShowProgress(offset + i + read_bytes, fsize, dest)) ret = 1;
|
||||||
}
|
}
|
||||||
@ -663,7 +662,7 @@ u32 DecryptNcchNcsdFirmFile(const char* orig, const char* dest, u32 mode,
|
|||||||
u8 ctr[16];
|
u8 ctr[16];
|
||||||
|
|
||||||
GetTmdCtr(ctr, chunk); // NCCH crypto?
|
GetTmdCtr(ctr, chunk); // NCCH crypto?
|
||||||
if (fx_read(ofp, MAIN_BUFFER, sizeof(NcchHeader), &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(ofp, MAIN_BUFFER, sizeof(NcchHeader), &bytes_read) != FR_OK) ret = 1;
|
||||||
if (cia_crypto) DecryptCiaContentSequential(MAIN_BUFFER, sizeof(NcchHeader), ctr, titlekey);
|
if (cia_crypto) DecryptCiaContentSequential(MAIN_BUFFER, sizeof(NcchHeader), ctr, titlekey);
|
||||||
ncch_crypto = ((ValidateNcchHeader((NcchHeader*) (void*) MAIN_BUFFER) == 0) &&
|
ncch_crypto = ((ValidateNcchHeader((NcchHeader*) (void*) MAIN_BUFFER) == 0) &&
|
||||||
NCCH_ENCRYPTED((NcchHeader*) (void*) MAIN_BUFFER));
|
NCCH_ENCRYPTED((NcchHeader*) (void*) MAIN_BUFFER));
|
||||||
@ -671,15 +670,15 @@ u32 DecryptNcchNcsdFirmFile(const char* orig, const char* dest, u32 mode,
|
|||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
GetTmdCtr(ctr, chunk);
|
GetTmdCtr(ctr, chunk);
|
||||||
f_lseek(ofp, offset);
|
fvx_lseek(ofp, offset);
|
||||||
sha_init(SHA256_MODE);
|
sha_init(SHA256_MODE);
|
||||||
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
if (fx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
||||||
if (cia_crypto && (DecryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey) != 0)) ret = 1;
|
if (cia_crypto && (DecryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey) != 0)) ret = 1;
|
||||||
if (ncch_crypto && (DecryptNcchSequential(MAIN_BUFFER, i, read_bytes) != 0)) ret = 1;
|
if (ncch_crypto && (DecryptNcchSequential(MAIN_BUFFER, i, read_bytes) != 0)) ret = 1;
|
||||||
if (inplace) f_lseek(ofp, f_tell(ofp) - read_bytes);
|
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
||||||
if (fx_write(dfp, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
if (fvx_write(dfp, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
sha_update(MAIN_BUFFER, read_bytes);
|
||||||
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
|
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
|
||||||
if (!ShowProgress(offset + i + read_bytes, fsize, dest)) ret = 1;
|
if (!ShowProgress(offset + i + read_bytes, fsize, dest)) ret = 1;
|
||||||
@ -688,8 +687,8 @@ u32 DecryptNcchNcsdFirmFile(const char* orig, const char* dest, u32 mode,
|
|||||||
chunk->type[1] &= ~0x01;
|
chunk->type[1] &= ~0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_close(ofp);
|
fvx_close(ofp);
|
||||||
if (!inplace) fx_close(dfp);
|
if (!inplace) fvx_close(dfp);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -742,12 +741,12 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// open destination file, get FIRM header
|
// open destination file, get FIRM header
|
||||||
if (fx_open(&file, dest, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, dest, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
if ((fx_read(&file, &firm, sizeof(FirmHeader), &btr) != FR_OK) ||
|
if ((fvx_read(&file, &firm, sizeof(FirmHeader), &btr) != FR_OK) ||
|
||||||
(ValidateFirmHeader(&firm) != 0)) {
|
(ValidateFirmHeader(&firm) != 0)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,21 +756,21 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
|
|||||||
|
|
||||||
// decrypt ARM9 loader header
|
// decrypt ARM9 loader header
|
||||||
FirmA9LHeader a9l;
|
FirmA9LHeader a9l;
|
||||||
f_lseek(&file, arm9s->offset);
|
fvx_lseek(&file, arm9s->offset);
|
||||||
if ((fx_read(&file, &a9l, sizeof(FirmA9LHeader), &btr) != FR_OK) ||
|
if ((fvx_read(&file, &a9l, sizeof(FirmA9LHeader), &btr) != FR_OK) ||
|
||||||
(DecryptA9LHeader(&a9l) != 0) || (f_lseek(&file, arm9s->offset) != FR_OK) ||
|
(DecryptA9LHeader(&a9l) != 0) || (fvx_lseek(&file, arm9s->offset) != FR_OK) ||
|
||||||
(fx_write(&file, &a9l, sizeof(FirmA9LHeader), &btr) != FR_OK)) {
|
(fvx_write(&file, &a9l, sizeof(FirmA9LHeader), &btr) != FR_OK)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate new hash for ARM9 section
|
// calculate new hash for ARM9 section
|
||||||
f_lseek(&file, arm9s->offset);
|
fvx_lseek(&file, arm9s->offset);
|
||||||
sha_init(SHA256_MODE);
|
sha_init(SHA256_MODE);
|
||||||
for (u32 i = 0; i < arm9s->size; i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; i < arm9s->size; i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (arm9s->size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (arm9s->size - i));
|
||||||
if ((fx_read(&file, MAIN_BUFFER, read_bytes, &btr) != FR_OK) || (btr != read_bytes)) {
|
if ((fvx_read(&file, MAIN_BUFFER, read_bytes, &btr) != FR_OK) || (btr != read_bytes)) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
sha_update(MAIN_BUFFER, read_bytes);
|
||||||
@ -779,14 +778,14 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
|
|||||||
sha_get(arm9s->hash);
|
sha_get(arm9s->hash);
|
||||||
|
|
||||||
// write back FIRM header
|
// write back FIRM header
|
||||||
f_lseek(&file, 0);
|
fvx_lseek(&file, 0);
|
||||||
memcpy(firm.dec_magic, dec_magic, sizeof(dec_magic));
|
memcpy(firm.dec_magic, dec_magic, sizeof(dec_magic));
|
||||||
if (fx_write(&file, &firm, sizeof(FirmHeader), &btr) != FR_OK) {
|
if (fvx_write(&file, &firm, sizeof(FirmHeader), &btr) != FR_OK) {
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,25 +835,25 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset,
|
|||||||
FIL dfile;
|
FIL dfile;
|
||||||
FSIZE_t fsize;
|
FSIZE_t fsize;
|
||||||
UINT bytes_read, bytes_written;
|
UINT bytes_read, bytes_written;
|
||||||
if (fx_open(&ofile, path_content, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&ofile, path_content, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
f_lseek(&ofile, offset);
|
fvx_lseek(&ofile, offset);
|
||||||
fsize = f_size(&ofile);
|
fsize = fvx_size(&ofile);
|
||||||
if (offset > fsize) return 1;
|
if (offset > fsize) return 1;
|
||||||
if (!size) size = fsize - offset;
|
if (!size) size = fsize - offset;
|
||||||
if (fx_open(&dfile, path_cia, FA_WRITE | FA_OPEN_APPEND) != FR_OK) {
|
if (fvx_open(&dfile, path_cia, FA_WRITE | FA_OPEN_APPEND) != FR_OK) {
|
||||||
fx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if NCCH crypto is available
|
// check if NCCH crypto is available
|
||||||
if (ncch_crypto) {
|
if (ncch_crypto) {
|
||||||
NcchHeader ncch;
|
NcchHeader ncch;
|
||||||
if ((fx_read(&ofile, &ncch, sizeof(NcchHeader), &bytes_read) != FR_OK) ||
|
if ((fvx_read(&ofile, &ncch, sizeof(NcchHeader), &bytes_read) != FR_OK) ||
|
||||||
(ValidateNcchHeader(&ncch) != 0) ||
|
(ValidateNcchHeader(&ncch) != 0) ||
|
||||||
(SetupNcchCrypto(&ncch) != 0))
|
(SetupNcchCrypto(&ncch) != 0))
|
||||||
ncch_crypto = false;
|
ncch_crypto = false;
|
||||||
f_lseek(&ofile, offset);
|
fvx_lseek(&ofile, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// main loop starts here
|
// main loop starts here
|
||||||
@ -864,21 +863,21 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset,
|
|||||||
if (!ShowProgress(0, 0, path_content)) ret = 1;
|
if (!ShowProgress(0, 0, path_content)) ret = 1;
|
||||||
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
if (fx_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
||||||
if (ncch_crypto && (DecryptNcchSequential(MAIN_BUFFER, i, read_bytes) != 0)) ret = 1;
|
if (ncch_crypto && (DecryptNcchSequential(MAIN_BUFFER, i, read_bytes) != 0)) ret = 1;
|
||||||
if ((i == 0) && cxi_fix && (SetNcchSdFlag(MAIN_BUFFER) != 0)) ret = 1;
|
if ((i == 0) && cxi_fix && (SetNcchSdFlag(MAIN_BUFFER) != 0)) ret = 1;
|
||||||
if (i == 0) sha_init(SHA256_MODE);
|
if (i == 0) sha_init(SHA256_MODE);
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
sha_update(MAIN_BUFFER, read_bytes);
|
||||||
if (cia_crypto && (EncryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey) != 0)) ret = 1;
|
if (cia_crypto && (EncryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey) != 0)) ret = 1;
|
||||||
if (fx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
if (fvx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
||||||
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
|
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
|
||||||
if (!ShowProgress(offset + i + read_bytes, fsize, path_content)) ret = 1;
|
if (!ShowProgress(offset + i + read_bytes, fsize, path_content)) ret = 1;
|
||||||
}
|
}
|
||||||
u8 hash[0x20];
|
u8 hash[0x20];
|
||||||
sha_get(hash);
|
sha_get(hash);
|
||||||
|
|
||||||
fx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
fx_close(&dfile);
|
fvx_close(&dfile);
|
||||||
|
|
||||||
// force legit?
|
// force legit?
|
||||||
if (force_legit && (memcmp(hash, chunk->hash, 0x20) != 0)) return 1;
|
if (force_legit && (memcmp(hash, chunk->hash, 0x20) != 0)) return 1;
|
||||||
@ -894,10 +893,10 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset,
|
|||||||
u32 InsertCiaMeta(const char* path_cia, CiaMeta* meta) {
|
u32 InsertCiaMeta(const char* path_cia, CiaMeta* meta) {
|
||||||
FIL file;
|
FIL file;
|
||||||
UINT btw;
|
UINT btw;
|
||||||
if (fx_open(&file, path_cia, FA_WRITE | FA_OPEN_APPEND) != FR_OK)
|
if (fvx_open(&file, path_cia, FA_WRITE | FA_OPEN_APPEND) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
bool res = ((fx_write(&file, meta, CIA_META_SIZE, &btw) == FR_OK) && (btw == CIA_META_SIZE));
|
bool res = ((fvx_write(&file, meta, CIA_META_SIZE, &btw) == FR_OK) && (btw == CIA_META_SIZE));
|
||||||
fx_close(&file);
|
fvx_close(&file);
|
||||||
return (res) ? 0 : 1;
|
return (res) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,21 +572,23 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
u32 filetype = IdentifyFileType(curr_entry->path);
|
u32 filetype = IdentifyFileType(curr_entry->path);
|
||||||
u32 drvtype = DriveType(curr_entry->path);
|
u32 drvtype = DriveType(curr_entry->path);
|
||||||
|
|
||||||
// special stuff, only available on FAT drives (see int special below)
|
// special stuff, only available for known filetypes (see int special below)
|
||||||
bool mountable = ((filetype & FTYPE_MOUNTABLE) && !(drvtype & DRV_IMAGE));
|
bool mountable = ((filetype & FTYPE_MOUNTABLE) && !(drvtype & DRV_IMAGE));
|
||||||
bool verificable = (filetype & FYTPE_VERIFICABLE);
|
bool verificable = (filetype & FYTPE_VERIFICABLE);
|
||||||
bool decryptable = (filetype & FYTPE_DECRYPTABLE);
|
bool decryptable = (filetype & FYTPE_DECRYPTABLE);
|
||||||
bool decryptable_inplace = (decryptable && (drvtype & (DRV_SDCARD|DRV_RAMDRIVE)));
|
bool decryptable_inplace = (decryptable && (drvtype & (DRV_SDCARD|DRV_RAMDRIVE)));
|
||||||
bool buildable = (filetype & FTYPE_BUILDABLE);
|
bool buildable = (filetype & FTYPE_BUILDABLE);
|
||||||
bool buildable_legit = (filetype & FTYPE_BUILDABLE_L);
|
bool buildable_legit = (filetype & FTYPE_BUILDABLE_L);
|
||||||
bool restorable = CheckA9lh() && (filetype & FTYPE_RESTORABLE);
|
bool restorable = (CheckA9lh() && (filetype & FTYPE_RESTORABLE) && !(drvtype & DRV_SYSNAND));
|
||||||
|
bool special_opt = mountable || verificable || decryptable || decryptable_inplace ||
|
||||||
|
buildable || buildable_legit || restorable;
|
||||||
|
|
||||||
char pathstr[32 + 1];
|
char pathstr[32 + 1];
|
||||||
TruncateString(pathstr, curr_entry->path, 32, 8);
|
TruncateString(pathstr, curr_entry->path, 32, 8);
|
||||||
|
|
||||||
// main menu processing
|
// main menu processing
|
||||||
int n_opt = 0;
|
int n_opt = 0;
|
||||||
int special = (filetype && (drvtype & DRV_FAT)) ? ++n_opt : -1;
|
int special = (special_opt) ? ++n_opt : -1;
|
||||||
int hexviewer = ++n_opt;
|
int hexviewer = ++n_opt;
|
||||||
int calcsha = ++n_opt;
|
int calcsha = ++n_opt;
|
||||||
int inject = ((clipboard->n_entries == 1) &&
|
int inject = ((clipboard->n_entries == 1) &&
|
||||||
|
@ -5,15 +5,15 @@
|
|||||||
#include "fsperm.h"
|
#include "fsperm.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "ff.h"
|
#include "vff.h"
|
||||||
|
|
||||||
u32 ReadNandFile(FIL* file, void* buffer, u32 sector, u32 count, u32 keyslot) {
|
u32 ReadNandFile(FIL* file, void* buffer, u32 sector, u32 count, u32 keyslot) {
|
||||||
u32 offset = sector * 0x200;
|
u32 offset = sector * 0x200;
|
||||||
u32 size = count * 0x200;
|
u32 size = count * 0x200;
|
||||||
UINT btr;
|
UINT btr;
|
||||||
if ((f_tell(file) != offset) && (f_lseek(file, offset) != FR_OK))
|
if ((fvx_tell(file) != offset) && (fvx_lseek(file, offset) != FR_OK))
|
||||||
return 1; // seek failed
|
return 1; // seek failed
|
||||||
if ((f_read(file, buffer, size, &btr) != FR_OK) || (btr != size))
|
if ((fvx_read(file, buffer, size, &btr) != FR_OK) || (btr != size))
|
||||||
return 1; // read failed
|
return 1; // read failed
|
||||||
if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot);
|
if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot);
|
||||||
return 0;
|
return 0;
|
||||||
@ -33,21 +33,21 @@ u32 ValidateNandDump(const char* path) {
|
|||||||
TruncateString(pathstr, path, 32, 8);
|
TruncateString(pathstr, path, 32, 8);
|
||||||
|
|
||||||
// open file
|
// open file
|
||||||
if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// check NAND header
|
// check NAND header
|
||||||
if ((ReadNandFile(&file, buffer, 0, 1, 0xFF) != 0) ||
|
if ((ReadNandFile(&file, buffer, 0, 1, 0xFF) != 0) ||
|
||||||
((nand_type = CheckNandHeader(buffer)) == 0)) { // zero means header not recognized
|
((nand_type = CheckNandHeader(buffer)) == 0)) { // zero means header not recognized
|
||||||
ShowPrompt(false, "%s\nHeader does not belong to device", pathstr);
|
ShowPrompt(false, "%s\nHeader does not belong to device", pathstr);
|
||||||
f_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check size
|
// check size
|
||||||
if (f_size(&file) < ((nand_type == NAND_TYPE_O3DS) ? NAND_MIN_SECTORS_O3DS : NAND_MIN_SECTORS_N3DS)) {
|
if (fvx_size(&file) < ((nand_type == NAND_TYPE_O3DS) ? NAND_MIN_SECTORS_O3DS : NAND_MIN_SECTORS_N3DS)) {
|
||||||
ShowPrompt(false, "%s\nNAND dump misses data", pathstr);
|
ShowPrompt(false, "%s\nNAND dump misses data", pathstr);
|
||||||
f_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ u32 ValidateNandDump(const char* path) {
|
|||||||
if ((ReadNandFile(&file, &mbr, mbr_sectors[i], 1, keyslot) != 0) ||
|
if ((ReadNandFile(&file, &mbr, mbr_sectors[i], 1, keyslot) != 0) ||
|
||||||
(ValidateMbrHeader(&mbr) != 0)) {
|
(ValidateMbrHeader(&mbr) != 0)) {
|
||||||
ShowPrompt(false, "%s\nError: %s MBR is corrupt", pathstr, section_type);
|
ShowPrompt(false, "%s\nError: %s MBR is corrupt", pathstr, section_type);
|
||||||
f_close(&file);
|
fvx_close(&file);
|
||||||
return 1; // impossible to happen
|
return 1; // impossible to happen
|
||||||
}
|
}
|
||||||
for (u32 p = 0; p < 4; p++) {
|
for (u32 p = 0; p < 4; p++) {
|
||||||
@ -67,7 +67,7 @@ u32 ValidateNandDump(const char* path) {
|
|||||||
if ((ReadNandFile(&file, buffer, mbr_sectors[i] + p_sector, 1, keyslot) != 0) ||
|
if ((ReadNandFile(&file, buffer, mbr_sectors[i] + p_sector, 1, keyslot) != 0) ||
|
||||||
(ValidateFatHeader(buffer) != 0)) {
|
(ValidateFatHeader(buffer) != 0)) {
|
||||||
ShowPrompt(false, "%s\nError: %s partition%u is corrupt", pathstr, section_type, p);
|
ShowPrompt(false, "%s\nError: %s partition%u is corrupt", pathstr, section_type, p);
|
||||||
f_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ u32 ValidateNandDump(const char* path) {
|
|||||||
(ValidateFirmHeader(&firm) != 0) ||
|
(ValidateFirmHeader(&firm) != 0) ||
|
||||||
(getbe32(firm.dec_magic) != 0)) { // decrypted firms are not allowed
|
(getbe32(firm.dec_magic) != 0)) { // decrypted firms are not allowed
|
||||||
ShowPrompt(false, "%s\nError: FIRM%u header is corrupt", pathstr, i);
|
ShowPrompt(false, "%s\nError: FIRM%u header is corrupt", pathstr, i);
|
||||||
f_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// hash verify all available sections
|
// hash verify all available sections
|
||||||
@ -101,7 +101,7 @@ u32 ValidateNandDump(const char* path) {
|
|||||||
sha_get(hash);
|
sha_get(hash);
|
||||||
if (memcmp(hash, section->hash, 0x20) != 0) {
|
if (memcmp(hash, section->hash, 0x20) != 0) {
|
||||||
ShowPrompt(false, "%s\nFIRM%u/%u hash mismatch", pathstr, i, s);
|
ShowPrompt(false, "%s\nFIRM%u/%u hash mismatch", pathstr, i, s);
|
||||||
f_close(&file);
|
fvx_close(&file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,9 +125,9 @@ u32 SafeRestoreNandDump(const char* path) {
|
|||||||
if (!SetWritePermissions(PERM_SYSNAND, true)) return 1;
|
if (!SetWritePermissions(PERM_SYSNAND, true)) return 1;
|
||||||
|
|
||||||
// open file, get size
|
// open file, get size
|
||||||
if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
u32 fsize = f_size(&file);
|
u32 fsize = fvx_size(&file);
|
||||||
safe_sectors[(sizeof(safe_sectors) / sizeof(u32)) - 1] = fsize / 0x200;
|
safe_sectors[(sizeof(safe_sectors) / sizeof(u32)) - 1] = fsize / 0x200;
|
||||||
|
|
||||||
// main processing loop
|
// main processing loop
|
||||||
@ -136,17 +136,17 @@ u32 SafeRestoreNandDump(const char* path) {
|
|||||||
for (u32 p = 0; p < sizeof(safe_sectors) / sizeof(u32); p += 2) {
|
for (u32 p = 0; p < sizeof(safe_sectors) / sizeof(u32); p += 2) {
|
||||||
u32 sector0 = safe_sectors[p];
|
u32 sector0 = safe_sectors[p];
|
||||||
u32 sector1 = safe_sectors[p+1];
|
u32 sector1 = safe_sectors[p+1];
|
||||||
f_lseek(&file, sector0 * 0x200);
|
fvx_lseek(&file, sector0 * 0x200);
|
||||||
for (u32 s = sector0; (s < sector1) && (ret == 0); s += MAIN_BUFFER_SIZE / 0x200) {
|
for (u32 s = sector0; (s < sector1) && (ret == 0); s += MAIN_BUFFER_SIZE / 0x200) {
|
||||||
UINT btr;
|
UINT btr;
|
||||||
u32 count = min(MAIN_BUFFER_SIZE / 0x200, (sector1 - s));
|
u32 count = min(MAIN_BUFFER_SIZE / 0x200, (sector1 - s));
|
||||||
if (f_read(&file, MAIN_BUFFER, count * 0x200, &btr) != FR_OK) ret = 1;
|
if (fvx_read(&file, MAIN_BUFFER, count * 0x200, &btr) != FR_OK) ret = 1;
|
||||||
if (WriteNandSectors(MAIN_BUFFER, s, count, 0xFF, NAND_SYSNAND)) ret = 1;
|
if (WriteNandSectors(MAIN_BUFFER, s, count, 0xFF, NAND_SYSNAND)) ret = 1;
|
||||||
if (btr != count * 0x200) ret = 1;
|
if (btr != count * 0x200) ret = 1;
|
||||||
if (!ShowProgress(s + count, fsize / 0x200, path)) ret = 1;
|
if (!ShowProgress(s + count, fsize / 0x200, path)) ret = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f_close(&file);
|
fvx_close(&file);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
67
source/virtual/vff.c
Normal file
67
source/virtual/vff.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "sddata.h"
|
||||||
|
#include "virtual.h"
|
||||||
|
#include "ffconf.h"
|
||||||
|
|
||||||
|
#define VFIL(fp) ((VirtualFile*) (void*) fp->buf)
|
||||||
|
|
||||||
|
FRESULT fvx_open (FIL* fp, const TCHAR* path, BYTE mode) {
|
||||||
|
#if !_FS_TINY
|
||||||
|
VirtualFile* vfile = VFIL(fp);
|
||||||
|
memset(fp, 0, sizeof(FIL));
|
||||||
|
if (GetVirtualFile(vfile, path)) {
|
||||||
|
fp->obj.fs = NULL;
|
||||||
|
fp->obj.objsize = vfile->size;
|
||||||
|
fp->fptr = 0;
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return fx_open ( fp, path, mode );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_read (FIL* fp, void* buff, UINT btr, UINT* br) {
|
||||||
|
#if !_FS_TINY
|
||||||
|
if (fp->obj.fs == NULL) {
|
||||||
|
VirtualFile* vfile = VFIL(fp);
|
||||||
|
int res = ReadVirtualFile(vfile, buff, fp->fptr, btr, (u32*) br);
|
||||||
|
fp->fptr += *br;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return fx_read ( fp, buff, btr, br );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
||||||
|
#if !_FS_TINY
|
||||||
|
if (fp->obj.fs == NULL) {
|
||||||
|
VirtualFile* vfile = VFIL(fp);
|
||||||
|
int res = WriteVirtualFile(vfile, buff, fp->fptr, btw, (u32*) bw);
|
||||||
|
fp->fptr += *bw;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return fx_write ( fp, buff, btw, bw );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_close (FIL* fp) {
|
||||||
|
#if !_FS_TINY
|
||||||
|
if (fp->obj.fs == NULL) return FR_OK;
|
||||||
|
#endif
|
||||||
|
return fx_close( fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs) {
|
||||||
|
#if !_FS_TINY
|
||||||
|
if (fp->obj.fs == NULL) {
|
||||||
|
fp->fptr = ofs;
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return f_lseek( fp, ofs );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_sync (FIL* fp) {
|
||||||
|
#if !_FS_TINY
|
||||||
|
if (fp->obj.fs == NULL) return FR_OK;
|
||||||
|
#endif
|
||||||
|
return f_sync( fp );
|
||||||
|
}
|
16
source/virtual/vff.h
Normal file
16
source/virtual/vff.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "ff.h"
|
||||||
|
|
||||||
|
#define fvx_tell(fp) ((fp)->fptr)
|
||||||
|
#define fvx_size(fp) ((fp)->obj.objsize)
|
||||||
|
|
||||||
|
// wrapper functions for ff.h + sddata.h
|
||||||
|
// incomplete(!) extension to FatFS to support a common interface for virtual and FAT
|
||||||
|
FRESULT fvx_open (FIL* fp, const TCHAR* path, BYTE mode);
|
||||||
|
FRESULT fvx_read (FIL* fp, void* buff, UINT btr, UINT* br);
|
||||||
|
FRESULT fvx_write (FIL* fp, const void* buff, UINT btw, UINT* bw);
|
||||||
|
FRESULT fvx_close (FIL* fp);
|
||||||
|
FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs);
|
||||||
|
FRESULT fvx_sync (FIL* fp);
|
Loading…
x
Reference in New Issue
Block a user