mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
Handle SD data crypto
This commit is contained in:
parent
779b6fe25b
commit
94c0608477
@ -6,6 +6,15 @@
|
|||||||
#define SDCRYPT_BUFFER_SIZE (0x100000)
|
#define SDCRYPT_BUFFER_SIZE (0x100000)
|
||||||
|
|
||||||
#define NUM_ALIAS_DRV 2
|
#define NUM_ALIAS_DRV 2
|
||||||
|
#define NUM_FILCRYPTINFO 16
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FIL* fptr;
|
||||||
|
u8 ctr[16];
|
||||||
|
u8 keyy[16];
|
||||||
|
} __attribute__((packed)) FilCryptInfo;
|
||||||
|
|
||||||
|
static FilCryptInfo filcrypt[NUM_FILCRYPTINFO] = { 0 };
|
||||||
|
|
||||||
char alias_drv[NUM_ALIAS_DRV]; // 1 char ASCII drive number of the alias drive / 0x00 if unused
|
char alias_drv[NUM_ALIAS_DRV]; // 1 char ASCII drive number of the alias drive / 0x00 if unused
|
||||||
char alias_path[NUM_ALIAS_DRV][128]; // full path to resolve the alias into
|
char alias_path[NUM_ALIAS_DRV][128]; // full path to resolve the alias into
|
||||||
@ -31,86 +40,107 @@ void dealias_path (TCHAR* alias, const TCHAR* path) {
|
|||||||
else strncpy(alias, path, 256);
|
else strncpy(alias, path, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fx_crypt(XFIL* xfp, void* buff, FSIZE_t off, UINT bt) {
|
FilCryptInfo* fx_find_cryptinfo(FIL* fptr) {
|
||||||
|
FilCryptInfo* info = NULL;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < NUM_FILCRYPTINFO; i++) {
|
||||||
|
if (!info && !filcrypt[i].fptr) // use first free
|
||||||
|
info = &filcrypt[i];
|
||||||
|
if (fptr == filcrypt[i].fptr) {
|
||||||
|
info = &filcrypt[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fx_crypt(FilCryptInfo* info, void* buff, FSIZE_t off, UINT bt) {
|
||||||
u32 mode = AES_CNT_CTRNAND_MODE;
|
u32 mode = AES_CNT_CTRNAND_MODE;
|
||||||
u8 ctr[16] __attribute__((aligned(32)));
|
u8 ctr[16] __attribute__((aligned(32)));
|
||||||
u8 buff16[16];
|
u8 buff16[16];
|
||||||
u8* buffer = buff;
|
u8* buffer = buff;
|
||||||
|
|
||||||
// copy CTR and increment it
|
// copy CTR and increment it
|
||||||
memcpy(ctr, xfp->iv, 16);
|
memcpy(ctr, info->ctr, 16);
|
||||||
add_ctr(ctr, off / 16);
|
add_ctr(ctr, off / 16);
|
||||||
|
|
||||||
// setup the key
|
// setup the key
|
||||||
setup_aeskeyY(xfp->keyslot, xfp->keyy);
|
setup_aeskeyY(0x34, info->keyy);
|
||||||
use_aeskey(xfp->keyslot);
|
use_aeskey(0x34);
|
||||||
|
|
||||||
// handle misaligned offset (at beginning)
|
// handle misaligned offset (at beginning)
|
||||||
if (off % 16) {
|
if (off % 16) {
|
||||||
memcpy(buff16 + (off % 16), buff, 16 - (off % 16));
|
memcpy(buff16 + (off % 16), buffer, 16 - (off % 16));
|
||||||
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
||||||
bt -= 16 - (off % 16);
|
memcpy(buffer, buff16 + (off % 16), 16 - (off % 16));
|
||||||
buffer += 16 - (off % 16);
|
buffer += 16 - (off % 16);
|
||||||
|
bt -= 16 - (off % 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
// de/encrypt the data
|
// de/encrypt the data
|
||||||
ctr_decrypt(buff, buff, bt / 16, mode, ctr);
|
ctr_decrypt(buffer, buffer, bt / 16, mode, ctr);
|
||||||
bt -= 16 * (UINT) (bt / 16);
|
|
||||||
buffer += 16 * (UINT) (bt / 16);
|
buffer += 16 * (UINT) (bt / 16);
|
||||||
|
bt -= 16 * (UINT) (bt / 16);
|
||||||
|
|
||||||
// handle misaligned offset (at end)
|
// handle misaligned offset (at end)
|
||||||
if (bt) {
|
if (bt) {
|
||||||
memcpy(buff16, buff, bt);
|
memcpy(buff16, buffer, bt);
|
||||||
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
||||||
|
memcpy(buffer, buff16, bt);
|
||||||
buffer += bt;
|
buffer += bt;
|
||||||
bt = 0;
|
bt = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fx_open (FIL* fp, XFIL* xfp, const TCHAR* path, BYTE mode) {
|
FRESULT fx_open (FIL* fp, const TCHAR* path, BYTE mode) {
|
||||||
int num = alias_num(path);
|
int num = alias_num(path);
|
||||||
xfp->keyslot = 0x40;
|
FilCryptInfo* info = fx_find_cryptinfo(fp);
|
||||||
if (num >= 0) {
|
if (info) info->fptr = NULL;
|
||||||
|
|
||||||
|
if (info && (num >= 0)) {
|
||||||
// get AES counter, see: http://www.3dbrew.org/wiki/Extdata#Encryption
|
// get AES counter, see: http://www.3dbrew.org/wiki/Extdata#Encryption
|
||||||
// path is the part of the full path after //Nintendo 3DS/<ID0>/<ID1>
|
// path is the part of the full path after //Nintendo 3DS/<ID0>/<ID1>
|
||||||
u8 hashstr[256];
|
u8 hashstr[256];
|
||||||
u8 sha256sum[32];
|
u8 sha256sum[32];
|
||||||
u32 plen = 0;
|
u32 plen = 0;
|
||||||
// poor man's UTF-8 -> UTF-16
|
// poor man's UTF-8 -> UTF-16
|
||||||
for (u32 plen = 0; plen < 128; plen++) {
|
for (plen = 0; plen < 128; plen++) {
|
||||||
hashstr[2*plen] = path[2 + plen];
|
hashstr[2*plen] = path[2 + plen];
|
||||||
hashstr[2*plen+1] = 0;
|
hashstr[2*plen+1] = 0;
|
||||||
if (path[plen] == 0) break;
|
if (path[2 + plen] == 0) break;
|
||||||
}
|
}
|
||||||
sha_quick(sha256sum, hashstr, (plen + 1) * 2, SHA256_MODE);
|
sha_quick(sha256sum, hashstr, (plen + 1) * 2, SHA256_MODE);
|
||||||
for (u32 i = 0; i < 16; i++)
|
for (u32 i = 0; i < 16; i++)
|
||||||
xfp->iv[i] = sha256sum[i] ^ sha256sum[i+16];
|
info->ctr[i] = sha256sum[i] ^ sha256sum[i+16];
|
||||||
// copy over key, set keyslot
|
// copy over key, FIL pointer
|
||||||
memcpy(xfp->keyy, sd_keyy[num], 16);
|
memcpy(info->keyy, sd_keyy[num], 16);
|
||||||
xfp->keyslot = 0x34;
|
info->fptr = fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fa_open(fp, path, mode);
|
return fa_open(fp, path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fx_read (FIL* fp, XFIL* xfp, void* buff, UINT btr, UINT* br) {
|
FRESULT fx_read (FIL* fp, void* buff, UINT btr, UINT* br) {
|
||||||
|
FilCryptInfo* info = fx_find_cryptinfo(fp);
|
||||||
FSIZE_t off = f_tell(fp);
|
FSIZE_t off = f_tell(fp);
|
||||||
FRESULT res = f_read(fp, buff, btr, br);
|
FRESULT res = f_read(fp, buff, btr, br);
|
||||||
if (xfp && (xfp->keyslot < 0x40))
|
if (info && info->fptr)
|
||||||
fx_crypt(xfp, buff, off, btr);
|
fx_crypt(info, buff, off, btr);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fx_write (FIL* fp, XFIL* xfp, const void* buff, UINT btw, UINT* bw) {
|
FRESULT fx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
||||||
|
FilCryptInfo* info = fx_find_cryptinfo(fp);
|
||||||
FSIZE_t off = f_tell(fp);
|
FSIZE_t off = f_tell(fp);
|
||||||
FRESULT res = FR_OK;
|
FRESULT res = FR_OK;
|
||||||
if (xfp && (xfp->keyslot < 0x40)) {
|
if (info && info->fptr) {
|
||||||
*bw = 0;
|
*bw = 0;
|
||||||
for (UINT p = 0; (p < btw) && (res == FR_OK); p += SDCRYPT_BUFFER_SIZE) {
|
for (UINT p = 0; (p < btw) && (res == FR_OK); p += SDCRYPT_BUFFER_SIZE) {
|
||||||
UINT pcount = min(SDCRYPT_BUFFER_SIZE, (btw - p));
|
UINT pcount = min(SDCRYPT_BUFFER_SIZE, (btw - p));
|
||||||
UINT bwl = 0;
|
UINT bwl = 0;
|
||||||
memcpy(SDCRYPT_BUFFER, (u8*) buff + p, pcount);
|
memcpy(SDCRYPT_BUFFER, (u8*) buff + p, pcount);
|
||||||
fx_crypt(xfp, SDCRYPT_BUFFER, off + p, pcount);
|
fx_crypt(info, SDCRYPT_BUFFER, off + p, pcount);
|
||||||
res = f_write(fp, (const void*) SDCRYPT_BUFFER, pcount, &bwl);
|
res = f_write(fp, (const void*) SDCRYPT_BUFFER, pcount, &bwl);
|
||||||
*bw += bwl;
|
*bw += bwl;
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,11 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u8 iv[16];
|
|
||||||
u8 keyy[16];
|
|
||||||
u32 keyslot;
|
|
||||||
} __attribute__((packed)) XFIL;
|
|
||||||
|
|
||||||
// wrapper functions for ff.h
|
// wrapper functions for ff.h
|
||||||
// incomplete(!) extension to FatFS to support on-the-fly crypto & path aliases
|
// incomplete(!) extension to FatFS to support on-the-fly crypto & path aliases
|
||||||
FRESULT fx_open (FIL* fp, XFIL* xfp, const TCHAR* path, BYTE mode);
|
FRESULT fx_open (FIL* fp, const TCHAR* path, BYTE mode);
|
||||||
FRESULT fx_read (FIL* fp, XFIL* xfp, void* buff, UINT btr, UINT* br);
|
FRESULT fx_read (FIL* fp, void* buff, UINT btr, UINT* br);
|
||||||
FRESULT fx_write (FIL* fp, XFIL* xfp, const void* buff, UINT btw, UINT* bw);
|
FRESULT fx_write (FIL* fp, const void* buff, UINT btw, UINT* bw);
|
||||||
|
|
||||||
void dealias_path (TCHAR* alias, const TCHAR* path);
|
void dealias_path (TCHAR* alias, const TCHAR* path);
|
||||||
FRESULT fa_open (FIL* fp, const TCHAR* path, BYTE mode);
|
FRESULT fa_open (FIL* fp, const TCHAR* path, BYTE mode);
|
||||||
|
36
source/fs.c
36
source/fs.c
@ -343,10 +343,10 @@ bool FileSetData(const char* path, const u8* data, size_t size, size_t foffset,
|
|||||||
if (drvtype & DRV_FAT) {
|
if (drvtype & DRV_FAT) {
|
||||||
UINT bytes_written = 0;
|
UINT bytes_written = 0;
|
||||||
FIL file;
|
FIL file;
|
||||||
if (fa_open(&file, path, FA_WRITE | (create ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS)) != FR_OK)
|
if (fx_open(&file, path, FA_WRITE | (create ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS)) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
f_lseek(&file, foffset);
|
f_lseek(&file, foffset);
|
||||||
f_write(&file, data, size, &bytes_written);
|
fx_write(&file, data, size, &bytes_written);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
return (bytes_written == size);
|
return (bytes_written == size);
|
||||||
} else if (drvtype & DRV_VIRTUAL) {
|
} else if (drvtype & DRV_VIRTUAL) {
|
||||||
@ -363,10 +363,10 @@ size_t FileGetData(const char* path, u8* data, size_t size, size_t foffset) {
|
|||||||
if (drvtype & DRV_FAT) {
|
if (drvtype & DRV_FAT) {
|
||||||
UINT bytes_read = 0;
|
UINT bytes_read = 0;
|
||||||
FIL file;
|
FIL file;
|
||||||
if (fa_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return 0;
|
return 0;
|
||||||
f_lseek(&file, foffset);
|
f_lseek(&file, foffset);
|
||||||
if (f_read(&file, data, size, &bytes_read) != FR_OK) {
|
if (fx_read(&file, data, size, &bytes_read) != FR_OK) {
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -423,7 +423,7 @@ bool FileGetSha256(const char* path, u8* sha256) {
|
|||||||
FIL file;
|
FIL file;
|
||||||
size_t fsize;
|
size_t fsize;
|
||||||
|
|
||||||
if (fa_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
fsize = f_size(&file);
|
fsize = f_size(&file);
|
||||||
f_lseek(&file, 0);
|
f_lseek(&file, 0);
|
||||||
@ -431,7 +431,7 @@ bool FileGetSha256(const char* path, u8* sha256) {
|
|||||||
|
|
||||||
for (size_t pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
for (size_t pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||||
UINT bytes_read = 0;
|
UINT bytes_read = 0;
|
||||||
if (f_read(&file, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
if (fx_read(&file, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||||
ret = false;
|
ret = false;
|
||||||
if (!ShowProgress(pos + bytes_read, fsize, path))
|
if (!ShowProgress(pos + bytes_read, fsize, path))
|
||||||
ret = false;
|
ret = false;
|
||||||
@ -502,7 +502,7 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
|||||||
dsize = dvfile.size;
|
dsize = dvfile.size;
|
||||||
} else {
|
} else {
|
||||||
vdest = false;
|
vdest = false;
|
||||||
if (fa_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
if (fx_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
dsize = f_size(&dfile);
|
dsize = f_size(&dfile);
|
||||||
f_lseek(&dfile, offset);
|
f_lseek(&dfile, offset);
|
||||||
@ -519,7 +519,7 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
|||||||
osize = ovfile.size;
|
osize = ovfile.size;
|
||||||
} else {
|
} else {
|
||||||
vorig = false;
|
vorig = false;
|
||||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
if (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||||
if (!vdest) f_close(&dfile);
|
if (!vdest) f_close(&dfile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -542,12 +542,12 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
|||||||
UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos);
|
UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos);
|
||||||
UINT bytes_read = read_bytes;
|
UINT bytes_read = read_bytes;
|
||||||
UINT bytes_written = read_bytes;
|
UINT bytes_written = read_bytes;
|
||||||
if ((!vorig && (f_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK)) ||
|
if ((!vorig && (fx_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK)) ||
|
||||||
(vorig && ReadVirtualFile(&ovfile, MAIN_BUFFER, pos, read_bytes, NULL) != 0))
|
(vorig && ReadVirtualFile(&ovfile, MAIN_BUFFER, pos, read_bytes, NULL) != 0))
|
||||||
ret = false;
|
ret = false;
|
||||||
if (!ShowProgress(pos + (bytes_read / 2), osize, orig))
|
if (!ShowProgress(pos + (bytes_read / 2), osize, orig))
|
||||||
ret = false;
|
ret = false;
|
||||||
if ((!vdest && (f_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)) ||
|
if ((!vdest && (fx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)) ||
|
||||||
(vdest && WriteVirtualFile(&dvfile, MAIN_BUFFER, offset + pos, read_bytes, NULL) != 0))
|
(vdest && WriteVirtualFile(&dvfile, MAIN_BUFFER, offset + pos, read_bytes, NULL) != 0))
|
||||||
ret = false;
|
ret = false;
|
||||||
if (bytes_read != bytes_written)
|
if (bytes_read != bytes_written)
|
||||||
@ -616,7 +616,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
|||||||
FIL ofile;
|
FIL ofile;
|
||||||
u32 osize;
|
u32 osize;
|
||||||
|
|
||||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
f_lseek(&ofile, 0);
|
f_lseek(&ofile, 0);
|
||||||
f_sync(&ofile);
|
f_sync(&ofile);
|
||||||
@ -654,7 +654,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
|||||||
if (!ShowProgress(0, 0, orig)) ret = false;
|
if (!ShowProgress(0, 0, orig)) ret = false;
|
||||||
for (size_t pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
for (size_t pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||||
UINT bytes_read = 0;
|
UINT bytes_read = 0;
|
||||||
if (f_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
if (fx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||||
ret = false;
|
ret = false;
|
||||||
if (!ShowProgress(pos + (bytes_read / 2), osize, orig))
|
if (!ShowProgress(pos + (bytes_read / 2), osize, orig))
|
||||||
ret = false;
|
ret = false;
|
||||||
@ -703,7 +703,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fa_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
f_lseek(&dfile, 0);
|
f_lseek(&dfile, 0);
|
||||||
f_sync(&dfile);
|
f_sync(&dfile);
|
||||||
@ -722,7 +722,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
|||||||
ret = false;
|
ret = false;
|
||||||
if (!ShowProgress(pos + (read_bytes / 2), osize, orig))
|
if (!ShowProgress(pos + (read_bytes / 2), osize, orig))
|
||||||
ret = false;
|
ret = false;
|
||||||
if (f_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)
|
if (fx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)
|
||||||
ret = false;
|
ret = false;
|
||||||
if (read_bytes != bytes_written)
|
if (read_bytes != bytes_written)
|
||||||
ret = false;
|
ret = false;
|
||||||
@ -845,7 +845,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
FIL dfile;
|
FIL dfile;
|
||||||
size_t fsize;
|
size_t fsize;
|
||||||
|
|
||||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
if (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
fsize = f_size(&ofile);
|
fsize = f_size(&ofile);
|
||||||
if (GetFreeSpace(dest) < fsize) {
|
if (GetFreeSpace(dest) < fsize) {
|
||||||
@ -854,7 +854,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fa_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||||
ShowPrompt(false, "Error: Cannot create destination file");
|
ShowPrompt(false, "Error: Cannot create destination file");
|
||||||
f_close(&ofile);
|
f_close(&ofile);
|
||||||
return false;
|
return false;
|
||||||
@ -869,11 +869,11 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
for (size_t pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
for (size_t pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||||
UINT bytes_read = 0;
|
UINT bytes_read = 0;
|
||||||
UINT bytes_written = 0;
|
UINT bytes_written = 0;
|
||||||
if (f_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
if (fx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||||
ret = false;
|
ret = false;
|
||||||
if (!ShowProgress(pos + (bytes_read / 2), fsize, orig))
|
if (!ShowProgress(pos + (bytes_read / 2), fsize, orig))
|
||||||
ret = false;
|
ret = false;
|
||||||
if (f_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK)
|
if (fx_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK)
|
||||||
ret = false;
|
ret = false;
|
||||||
if (bytes_read != bytes_written)
|
if (bytes_read != bytes_written)
|
||||||
ret = false;
|
ret = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user