mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Rewritten file copy / move routines
This commit is contained in:
parent
65af709aa9
commit
9661ffc940
@ -11,8 +11,8 @@
|
|||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
#define SKIP_CUR (1UL<<6)
|
#define SKIP_CUR (1UL<<7)
|
||||||
#define OVERWRITE_CUR (1UL<<7)
|
#define OVERWRITE_CUR (1UL<<8)
|
||||||
|
|
||||||
// Volume2Partition resolution table
|
// Volume2Partition resolution table
|
||||||
PARTITION VolToPart[] = {
|
PARTITION VolToPart[] = {
|
||||||
@ -199,12 +199,13 @@ u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file) {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
bool FileInjectFile(const char* dest, const char* orig, u32 offset, u32* flags) {
|
||||||
FIL ofile;
|
FIL ofile;
|
||||||
FIL dfile;
|
FIL dfile;
|
||||||
u64 osize;
|
u64 osize;
|
||||||
u64 dsize;
|
u64 dsize;
|
||||||
bool ret;
|
bool no_cancel = (flags && (*flags & NO_CANCEL));
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
if (!CheckWritePermissions(dest)) return false;
|
if (!CheckWritePermissions(dest)) return false;
|
||||||
if (strncmp(dest, orig, 256) == 0) {
|
if (strncmp(dest, orig, 256) == 0) {
|
||||||
@ -233,7 +234,6 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = true;
|
|
||||||
ShowProgress(0, 0, orig);
|
ShowProgress(0, 0, orig);
|
||||||
for (u64 pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
for (u64 pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||||
UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos);
|
UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos);
|
||||||
@ -243,7 +243,7 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
|||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((!ShowProgress(pos + (bytes_read / 2), osize, orig)) ||
|
if ((!ShowProgress(pos + (bytes_read / 2), osize, orig) && !no_cancel) ||
|
||||||
(fvx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ||
|
(fvx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ||
|
||||||
(bytes_read != bytes_written))
|
(bytes_read != bytes_written))
|
||||||
ret = false;
|
ret = false;
|
||||||
@ -317,220 +317,39 @@ bool DirInfo(const char* path, u64* tsize, u32* tdirs, u32* tfiles) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathCopyVrtToVrt(const char* destdir, const char* orig, u32* flags) {
|
bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
||||||
VirtualFile dvfile;
|
bool to_virtual = GetVirtualSource(dest);
|
||||||
VirtualFile ovfile;
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
char dest[256]; // maximum path name length in FAT
|
|
||||||
char* oname = strrchr(orig, '/');
|
|
||||||
if (oname == NULL) return false; // not a proper origin path
|
|
||||||
snprintf(dest, 255, "%s/%s", destdir, (++oname));
|
|
||||||
|
|
||||||
char deststr[36 + 1];
|
|
||||||
char origstr[36 + 1];
|
|
||||||
TruncateString(deststr, dest, 36, 8);
|
|
||||||
TruncateString(origstr, orig, 36, 8);
|
|
||||||
|
|
||||||
if (!GetVirtualFile(&dvfile, dest) || !GetVirtualFile(&ovfile, orig))
|
|
||||||
return false;
|
|
||||||
u64 osize = ovfile.size;
|
|
||||||
if (dvfile.size != osize) { // almost impossible, but so what...
|
|
||||||
ShowPrompt(false, "Virtual file size mismatch:\n%s\n%s", origstr, deststr);
|
|
||||||
return false;
|
|
||||||
} else if (strncmp(dest, orig, 256) == 0) { // destination == origin
|
|
||||||
ShowPrompt(false, "Origin equals destination:\n%s\n%s", origstr, deststr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((dvfile.keyslot == ovfile.keyslot) && (dvfile.offset == ovfile.offset))
|
|
||||||
dvfile.keyslot = ovfile.keyslot = 0xFF; // this improves copy times for virtual NAND
|
|
||||||
|
|
||||||
// check write permissions
|
|
||||||
if ((!flags || !(*flags & OVERRIDE_PERM)) && !CheckWritePermissions(dest))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// unmount critical NAND drives
|
|
||||||
DismountDriveType(DriveType(destdir)&(DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE));
|
|
||||||
if (!ShowProgress(0, 0, orig)) ret = false;
|
|
||||||
for (u64 pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
|
||||||
UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos);
|
|
||||||
if (ReadVirtualFile(&ovfile, MAIN_BUFFER, pos, read_bytes, NULL) != 0)
|
|
||||||
ret = false;
|
|
||||||
if (!ShowProgress(pos + (read_bytes / 2), osize, orig))
|
|
||||||
ret = false;
|
|
||||||
if (WriteVirtualFile(&dvfile, MAIN_BUFFER, pos, read_bytes, NULL) != 0)
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
ShowProgress(1, 1, orig);
|
|
||||||
InitExtFS();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PathCopyFatToVrt(const char* destdir, const char* orig, u32* flags) {
|
|
||||||
VirtualFile dvfile;
|
|
||||||
FIL ofile;
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
char dest[256]; // maximum path name length in FAT
|
|
||||||
char* oname = strrchr(orig, '/');
|
|
||||||
if (oname == NULL) return false; // not a proper origin path
|
|
||||||
snprintf(dest, 255, "%s/%s", destdir, (++oname));
|
|
||||||
|
|
||||||
// FAT file size
|
|
||||||
FILINFO fno;
|
|
||||||
if (fa_stat(orig, &fno) != FR_OK) return false; // file does not exist
|
|
||||||
u64 osize = fno.fsize;
|
|
||||||
|
|
||||||
// virtual file
|
|
||||||
if (!GetVirtualFile(&dvfile, dest)) {
|
|
||||||
VirtualDir vdir;
|
|
||||||
if (!GetVirtualDir(&vdir, destdir)) return false;
|
|
||||||
while (true) { // search by size should be a last resort solution
|
|
||||||
if (!ReadVirtualDir(&dvfile, &vdir))
|
|
||||||
return false;
|
|
||||||
if (dvfile.size == osize)
|
|
||||||
break; // file found
|
|
||||||
}
|
|
||||||
if (!ShowPrompt(true, "Entry not found: %s\nInject into %s instead?", dest, dvfile.name))
|
|
||||||
return false;
|
|
||||||
snprintf(dest, 255, "%s/%s", destdir, dvfile.name);
|
|
||||||
} else if (dvfile.size != osize) { // handling for differing sizes
|
|
||||||
char deststr[36 + 1];
|
|
||||||
char origstr[36 + 1];
|
|
||||||
char osizestr[32];
|
|
||||||
char dsizestr[32];
|
|
||||||
TruncateString(deststr, dest, 36, 8);
|
|
||||||
TruncateString(origstr, orig, 36, 8);
|
|
||||||
FormatBytes(osizestr, osize);
|
|
||||||
FormatBytes(dsizestr, dvfile.size);
|
|
||||||
if (dvfile.size > osize) {
|
|
||||||
if (!ShowPrompt(true, "File smaller than available space:\n%s (%s)\n%s (%s)\nContinue?", origstr, osizestr, deststr, dsizestr))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
ShowPrompt(false, "File bigger than available space:\n%s (%s)\n%s (%s)", origstr, osizestr, deststr, dsizestr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check write permissions
|
|
||||||
if ((!flags || !(*flags & OVERRIDE_PERM)) && !CheckWritePermissions(dest))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// FAT file
|
|
||||||
if ((fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) &&
|
|
||||||
(!FileUnlock(orig) || (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
f_lseek(&ofile, 0);
|
|
||||||
f_sync(&ofile);
|
|
||||||
|
|
||||||
// unmount critical NAND drives
|
|
||||||
DismountDriveType(DriveType(destdir)&(DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE));
|
|
||||||
if (!ShowProgress(0, 0, orig)) ret = false;
|
|
||||||
for (u64 pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
|
||||||
UINT bytes_read = 0;
|
|
||||||
if (fx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
|
||||||
ret = false;
|
|
||||||
if (!ShowProgress(pos + (bytes_read / 2), osize, orig))
|
|
||||||
ret = false;
|
|
||||||
if (WriteVirtualFile(&dvfile, MAIN_BUFFER, pos, bytes_read, NULL) != 0)
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
ShowProgress(1, 1, orig);
|
|
||||||
fx_close(&ofile);
|
|
||||||
InitExtFS();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PathCopyToFat(char* dest, char* orig, u32* flags, bool move) {
|
|
||||||
FILINFO fno;
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if (fa_stat(dest, &fno) != FR_OK) { // is root or destination does not exist
|
// check destination write permission (special paths only)
|
||||||
DIR tmp_dir; // check if root
|
if (((*dest == '1') || (strncmp(dest, "0:/Nintendo 3DS", 16) == 0)) &&
|
||||||
if (fa_opendir(&tmp_dir, dest) != FR_OK) return false;
|
(!flags || !(*flags & OVERRIDE_PERM)) &&
|
||||||
f_closedir(&tmp_dir);
|
!CheckWritePermissions(dest)) return false;
|
||||||
} else if (!(fno.fattrib & AM_DIR)) return false; // destination is not a directory (must be at this point)
|
|
||||||
|
FILINFO fno;
|
||||||
if (fvx_stat(orig, &fno) != FR_OK) return false; // origin does not exist
|
if (fvx_stat(orig, &fno) != FR_OK) return false; // origin does not exist
|
||||||
if (move && (fno.fattrib & AM_VRT)) return false; // trying to move a virtual file
|
if (move && (to_virtual || fno.fattrib & AM_VRT)) return false; // trying to move a virtual file
|
||||||
|
|
||||||
// build full destination path (on top of destination directory)
|
|
||||||
char* oname = strrchr(orig, '/');
|
|
||||||
char* dname = dest + strnlen(dest, 255);
|
|
||||||
if (oname == NULL) return false; // not a proper origin path
|
|
||||||
oname++;
|
|
||||||
*(dname++) = '/';
|
|
||||||
strncpy(dname, oname, 256 - (dname - dest));
|
|
||||||
|
|
||||||
// path string (for output)
|
// path string (for output)
|
||||||
char deststr[36 + 1];
|
char deststr[36 + 1];
|
||||||
TruncateString(deststr, dest, 36, 8);
|
TruncateString(deststr, dest, 36, 8);
|
||||||
|
|
||||||
// check if destination is part of or equal origin
|
|
||||||
while (strncmp(dest, orig, 255) == 0) {
|
|
||||||
if (!ShowStringPrompt(dname, 255 - (dname - dest), "%s\nDestination is equal to origin\nChoose another name?", deststr))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (strncmp(dest, orig, strnlen(orig, 255)) == 0) {
|
|
||||||
if ((dest[strnlen(orig, 255)] == '/') || (dest[strnlen(orig, 255)] == '\0')) {
|
|
||||||
ShowPrompt(false, "%s\nError: Destination is part of origin", deststr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if destination exists
|
|
||||||
if (flags && !(*flags & (OVERWRITE_CUR|OVERWRITE_ALL)) && (fa_stat(dest, NULL) == FR_OK)) {
|
|
||||||
if (*flags & SKIP_ALL) {
|
|
||||||
*flags |= SKIP_CUR;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const char* optionstr[5] =
|
|
||||||
{"Choose new name", "Overwrite file(s)", "Skip file(s)", "Overwrite all", "Skip all"};
|
|
||||||
u32 user_select = ShowSelectPrompt((*flags & ASK_ALL) ? 5 : 3, optionstr,
|
|
||||||
"Destination already exists:\n%s", deststr);
|
|
||||||
if (user_select == 1) {
|
|
||||||
do {
|
|
||||||
if (!ShowStringPrompt(dname, 255 - (dname - dest), "Choose new destination name"))
|
|
||||||
return false;
|
|
||||||
} while (fa_stat(dest, NULL) == FR_OK);
|
|
||||||
} else if (user_select == 2) {
|
|
||||||
*flags |= OVERWRITE_CUR;
|
|
||||||
} else if (user_select == 3) {
|
|
||||||
*flags |= SKIP_CUR;
|
|
||||||
return true;
|
|
||||||
} else if (user_select == 4) {
|
|
||||||
*flags |= OVERWRITE_ALL;
|
|
||||||
} else if (user_select == 5) {
|
|
||||||
*flags |= (SKIP_CUR|SKIP_ALL);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check destination write permission (special paths only)
|
|
||||||
if (((*dest == '1') || (strncmp(dest, "0:/Nintendo 3DS", 16) == 0)) &&
|
|
||||||
(!flags || (*flags & (OVERWRITE_CUR|OVERWRITE_ALL))) &&
|
|
||||||
(!flags || !(*flags & OVERRIDE_PERM)) &&
|
|
||||||
!CheckWritePermissions(dest)) return false;
|
|
||||||
|
|
||||||
// the copy process takes place here
|
// the copy process takes place here
|
||||||
if (!ShowProgress(0, 0, orig)) return false;
|
bool no_cancel = (flags && (*flags & NO_CANCEL));
|
||||||
if (move && fa_stat(dest, NULL) != FR_OK) { // moving if dest not existing
|
if (!ShowProgress(0, 0, orig) && !no_cancel) return false;
|
||||||
ret = (f_rename(orig, dest) == FR_OK);
|
if (move && fvx_stat(dest, NULL) != FR_OK) { // moving if dest not existing
|
||||||
|
ret = (fvx_rename(orig, dest) == FR_OK);
|
||||||
} else if (fno.fattrib & AM_DIR) { // processing folders (same for move & copy)
|
} else if (fno.fattrib & AM_DIR) { // processing folders (same for move & copy)
|
||||||
DIR pdir;
|
DIR pdir;
|
||||||
char* fname = orig + strnlen(orig, 256);
|
char* fname = orig + strnlen(orig, 256);
|
||||||
|
|
||||||
// create the destination folder if it does not already exist
|
// create the destination folder if it does not already exist
|
||||||
if (fa_opendir(&pdir, dest) != FR_OK) {
|
if (fvx_opendir(&pdir, dest) != FR_OK) {
|
||||||
if (f_mkdir(dest) != FR_OK) {
|
if (fvx_mkdir(dest) != FR_OK) {
|
||||||
ShowPrompt(false, "%s\nError: Overwriting file with dir", deststr);
|
ShowPrompt(false, "%s\nError: Overwriting file with dir", deststr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else f_closedir(&pdir);
|
} else fvx_closedir(&pdir);
|
||||||
|
|
||||||
if (fvx_opendir(&pdir, orig) != FR_OK)
|
if (fvx_opendir(&pdir, orig) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
@ -543,21 +362,27 @@ bool PathCopyToFat(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
if (fno.fname[0] == 0) {
|
if (fno.fname[0] == 0) {
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
} else if (!PathCopyToFat(dest, orig, flags, move)) {
|
} else {
|
||||||
break;
|
// recursively process directory
|
||||||
|
char* oname = strrchr(orig, '/');
|
||||||
|
char* dname = dest + strnlen(dest, 255);
|
||||||
|
if (oname == NULL) return false; // not a proper origin path
|
||||||
|
*(dname++) = '/';
|
||||||
|
strncpy(dname, oname++, 256 - (dname - dest));
|
||||||
|
bool res = PathMoveCopyRec(dest, orig, flags, move);
|
||||||
|
*(--dname) = '\0';
|
||||||
|
if (!res) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fvx_closedir(&pdir);
|
fvx_closedir(&pdir);
|
||||||
} else if (move) { // moving if destination exists
|
} else if (move) { // moving if destination exists
|
||||||
if (fa_stat(dest, &fno) != FR_OK)
|
if (fvx_stat(dest, &fno) != FR_OK) return false;
|
||||||
return false;
|
|
||||||
if (fno.fattrib & AM_DIR) {
|
if (fno.fattrib & AM_DIR) {
|
||||||
ShowPrompt(false, "%s\nError: Overwriting dir with file", deststr);
|
ShowPrompt(false, "%s\nError: Overwriting dir with file", deststr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (f_unlink(dest) != FR_OK)
|
if (fvx_unlink(dest) != FR_OK) return false;
|
||||||
return false;
|
ret = (fvx_rename(orig, dest) == FR_OK);
|
||||||
ret = (f_rename(orig, dest) == FR_OK);
|
|
||||||
} else { // copying files
|
} else { // copying files
|
||||||
FIL ofile;
|
FIL ofile;
|
||||||
FIL dfile;
|
FIL dfile;
|
||||||
@ -570,20 +395,27 @@ bool PathCopyToFat(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fsize = fvx_size(&ofile);
|
fsize = fvx_size(&ofile);
|
||||||
if (GetFreeSpace(dest) < fsize) {
|
if (!to_virtual && (GetFreeSpace(dest) < fsize)) {
|
||||||
ShowPrompt(false, "%s\nError: File is too big for destination", deststr);
|
ShowPrompt(false, "%s\nError: Not enough space in drive", deststr);
|
||||||
fx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
if (fvx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||||
ShowPrompt(false, "%s\nError: Cannot create destination file", deststr);
|
ShowPrompt(false, "%s\nError: Cannot open destination file", deststr);
|
||||||
fx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
f_lseek(&dfile, 0);
|
if (to_virtual && (fvx_size(&dfile) < fsize)) {
|
||||||
f_sync(&dfile);
|
ShowPrompt(false, "%s\nError: Not enough virtual space", deststr);
|
||||||
|
fvx_close(&ofile);
|
||||||
|
fvx_close(&dfile);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fvx_lseek(&dfile, 0);
|
||||||
|
fvx_sync(&dfile);
|
||||||
fvx_lseek(&ofile, 0);
|
fvx_lseek(&ofile, 0);
|
||||||
fvx_sync(&ofile);
|
fvx_sync(&ofile);
|
||||||
|
|
||||||
@ -592,13 +424,10 @@ bool PathCopyToFat(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
for (u64 pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
for (u64 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 (fvx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
if ((fvx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK) ||
|
||||||
ret = false;
|
(fvx_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK) ||
|
||||||
if (!ShowProgress(pos + (bytes_read / 2), fsize, orig))
|
(bytes_read != bytes_written) ||
|
||||||
ret = false;
|
(!ShowProgress(pos + bytes_read, fsize, orig) && !no_cancel))
|
||||||
if (fx_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK)
|
|
||||||
ret = false;
|
|
||||||
if (bytes_read != bytes_written)
|
|
||||||
ret = false;
|
ret = false;
|
||||||
if (flags && (*flags & CALC_SHA))
|
if (flags && (*flags & CALC_SHA))
|
||||||
sha_update(MAIN_BUFFER, bytes_read);
|
sha_update(MAIN_BUFFER, bytes_read);
|
||||||
@ -606,9 +435,9 @@ bool PathCopyToFat(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
ShowProgress(1, 1, orig);
|
ShowProgress(1, 1, orig);
|
||||||
|
|
||||||
fvx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
fx_close(&dfile);
|
fvx_close(&dfile);
|
||||||
if (!ret) f_unlink(dest);
|
if (!ret) fvx_unlink(dest);
|
||||||
else if (flags && (*flags & CALC_SHA)) {
|
else if (!to_virtual && flags && (*flags & CALC_SHA)) {
|
||||||
u8 sha256[0x20];
|
u8 sha256[0x20];
|
||||||
char* ext_sha = dest + strnlen(dest, 256);
|
char* ext_sha = dest + strnlen(dest, 256);
|
||||||
strncpy(ext_sha, ".sha", 256 - (ext_sha - dest));
|
strncpy(ext_sha, ".sha", 256 - (ext_sha - dest));
|
||||||
@ -617,53 +446,165 @@ bool PathCopyToFat(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*(--dname) = '\0';
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathCopy(const char* destdir, const char* orig, u32* flags) {
|
bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move) {
|
||||||
if ((!flags || !(*flags & OVERRIDE_PERM)) && !CheckWritePermissions(destdir))
|
// check permissions
|
||||||
return false;
|
if (!flags || !(*flags & OVERRIDE_PERM)) {
|
||||||
if (flags) *flags = *flags & ~(SKIP_CUR|OVERWRITE_CUR); // reset local flags
|
if (!CheckWritePermissions(dest)) return false;
|
||||||
int ddrvtype = DriveType(destdir);
|
if (move && !CheckDirWritePermissions(orig)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset local flags
|
||||||
|
if (flags) *flags = *flags & ~(SKIP_CUR|OVERWRITE_CUR);
|
||||||
|
|
||||||
|
// preparations
|
||||||
|
int ddrvtype = DriveType(dest);
|
||||||
int odrvtype = DriveType(orig);
|
int odrvtype = DriveType(orig);
|
||||||
if (!(ddrvtype & DRV_VIRTUAL)) { // FAT / virtual to FAT
|
char ldest[256]; // 256 is the maximum length of a full path
|
||||||
char fdpath[256]; // 256 is the maximum length of a full path
|
char lorig[256];
|
||||||
char fopath[256];
|
strncpy(ldest, dest, 255);
|
||||||
strncpy(fdpath, destdir, 255);
|
strncpy(lorig, orig, 255);
|
||||||
strncpy(fopath, orig, 255);
|
char deststr[36 + 1];
|
||||||
if (flags && (*flags & BUILD_PATH)) fvx_rmkdir(destdir);
|
TruncateString(deststr, ldest, 36, 8);
|
||||||
return PathCopyToFat(fdpath, fopath, flags, false);
|
|
||||||
} else if (!(odrvtype & DRV_VIRTUAL)) { // FAT to virtual
|
// moving only for regular FAT drives (= not alias drives)
|
||||||
|
if (move && !(ddrvtype & odrvtype & DRV_STDFAT)) {
|
||||||
|
ShowPrompt(false, "Error: Only FAT files can be moved");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is destination part of origin?
|
||||||
|
u32 olen = strnlen(lorig, 255);
|
||||||
|
if ((strncmp(ldest, lorig, olen) == 0) && (ldest[olen] == '/')) {
|
||||||
|
ShowPrompt(false, "%s\nError: Destination is part of origin", deststr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ddrvtype & DRV_VIRTUAL)) { // FAT destination handling
|
||||||
|
// get destination name
|
||||||
|
char* dname = strrchr(ldest, '/');
|
||||||
|
if (!dname) return false;
|
||||||
|
dname++;
|
||||||
|
|
||||||
|
// check & fix destination == origin
|
||||||
|
while (strncmp(ldest, lorig, 255) == 0) {
|
||||||
|
if (!ShowStringPrompt(dname, 255 - (dname - ldest), "%s\nDestination equals origin\nChoose another name?", deststr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if destination exists
|
||||||
|
if (flags && !(*flags & (OVERWRITE_CUR|OVERWRITE_ALL)) && (fa_stat(ldest, NULL) == FR_OK)) {
|
||||||
|
if (*flags & SKIP_ALL) {
|
||||||
|
*flags |= SKIP_CUR;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const char* optionstr[5] =
|
||||||
|
{"Choose new name", "Overwrite file(s)", "Skip file(s)", "Overwrite all", "Skip all"};
|
||||||
|
u32 user_select = ShowSelectPrompt((*flags & ASK_ALL) ? 5 : 3, optionstr,
|
||||||
|
"Destination already exists:\n%s", deststr);
|
||||||
|
if (user_select == 1) {
|
||||||
|
do {
|
||||||
|
if (!ShowStringPrompt(dname, 255 - (dname - ldest), "Choose new destination name"))
|
||||||
|
return false;
|
||||||
|
} while (fa_stat(ldest, NULL) == FR_OK);
|
||||||
|
} else if (user_select == 2) {
|
||||||
|
*flags |= OVERWRITE_CUR;
|
||||||
|
} else if (user_select == 3) {
|
||||||
|
*flags |= SKIP_CUR;
|
||||||
|
return true;
|
||||||
|
} else if (user_select == 4) {
|
||||||
|
*flags |= OVERWRITE_ALL;
|
||||||
|
} else if (user_select == 5) {
|
||||||
|
*flags |= (SKIP_CUR|SKIP_ALL);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the destination path exists
|
||||||
|
if (flags && (*flags & BUILD_PATH)) fvx_rmkpath(ldest);
|
||||||
|
|
||||||
|
// actual move / copy operation
|
||||||
|
bool same_drv = (strncmp(lorig, ldest, 2) == 0);
|
||||||
|
bool res = PathMoveCopyRec(ldest, lorig, flags, move & same_drv);
|
||||||
|
if (move & res && (!flags || !(*flags&SKIP_CUR))) PathDelete(lorig);
|
||||||
|
return res;
|
||||||
|
} else { // virtual destination handling
|
||||||
|
// can't write an SHA file to a virtual destination
|
||||||
|
if (flags) *flags |= ~CALC_SHA;
|
||||||
|
|
||||||
|
// prevent illegal operations
|
||||||
if (odrvtype & ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)) {
|
if (odrvtype & ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)) {
|
||||||
ShowPrompt(false, "Copy operation is not allowed");
|
ShowPrompt(false, "Copy operation is not allowed");
|
||||||
return false; // prevent illegal operations
|
return false;
|
||||||
}
|
}
|
||||||
return PathCopyFatToVrt(destdir, orig, flags);
|
|
||||||
} else return PathCopyVrtToVrt(destdir, orig, flags); // virtual to virtual
|
// check destination == origin
|
||||||
|
if (strncmp(ldest, lorig, 255) == 0) {
|
||||||
|
ShowPrompt(false, "%s\nDestination equals origin", deststr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// actual virtual copy operation
|
||||||
|
DismountDriveType(DriveType(ldest)&(DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE));
|
||||||
|
bool res = PathMoveCopyRec(ldest, lorig, flags, false);
|
||||||
|
InitExtFS();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PathCopy(const char* destdir, const char* orig, u32* flags) {
|
||||||
|
// build full destination path (on top of destination directory)
|
||||||
|
char dest[256]; // maximum path name length in FAT
|
||||||
|
char* oname = strrchr(orig, '/');
|
||||||
|
if (oname == NULL) return false; // not a proper origin path
|
||||||
|
snprintf(dest, 255, "%s/%s", destdir, (++oname));
|
||||||
|
|
||||||
|
// virtual destination special handling
|
||||||
|
if (GetVirtualSource(destdir)) {
|
||||||
|
u64 osize = FileGetSize(orig);
|
||||||
|
VirtualFile dvfile;
|
||||||
|
if (!osize) return false;
|
||||||
|
if (!GetVirtualFile(&dvfile, dest)) {
|
||||||
|
VirtualDir vdir;
|
||||||
|
if (!GetVirtualDir(&vdir, destdir)) return false;
|
||||||
|
while (true) { // search by size should be a last resort solution
|
||||||
|
if (!ReadVirtualDir(&dvfile, &vdir)) return false;
|
||||||
|
if (dvfile.size == osize) break; // file found
|
||||||
|
}
|
||||||
|
if (!ShowPrompt(true, "Entry not found: %s\nInject into %s instead?", dest, dvfile.name))
|
||||||
|
return false;
|
||||||
|
snprintf(dest, 255, "%s/%s", destdir, dvfile.name);
|
||||||
|
} else if (osize < dvfile.size) { // if origin is smaller than destination...
|
||||||
|
char deststr[36 + 1];
|
||||||
|
char origstr[36 + 1];
|
||||||
|
char osizestr[32];
|
||||||
|
char dsizestr[32];
|
||||||
|
TruncateString(deststr, dest, 36, 8);
|
||||||
|
TruncateString(origstr, orig, 36, 8);
|
||||||
|
FormatBytes(osizestr, osize);
|
||||||
|
FormatBytes(dsizestr, dvfile.size);
|
||||||
|
if (dvfile.size > osize) {
|
||||||
|
if (!ShowPrompt(true, "File smaller than available space:\n%s (%s)\n%s (%s)\nContinue?", origstr, osizestr, deststr, dsizestr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PathMoveCopy(dest, orig, flags, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathMove(const char* destdir, const char* orig, u32* flags) {
|
bool PathMove(const char* destdir, const char* orig, u32* flags) {
|
||||||
if (!flags || !(*flags & OVERRIDE_PERM)) {
|
// build full destination path (on top of destination directory)
|
||||||
if (!CheckWritePermissions(destdir)) return false;
|
char dest[256]; // maximum path name length in FAT
|
||||||
if (!CheckDirWritePermissions(orig)) return false;
|
char* oname = strrchr(orig, '/');
|
||||||
}
|
if (oname == NULL) return false; // not a proper origin path
|
||||||
if (flags) *flags = *flags & ~(SKIP_CUR|OVERWRITE_CUR); // reset local flags
|
snprintf(dest, 255, "%s/%s", destdir, (++oname));
|
||||||
// moving only for regular FAT drives (= not alias drives)
|
|
||||||
if (!(DriveType(destdir) & DriveType(orig) & DRV_STDFAT)) {
|
return PathMoveCopy(dest, orig, flags, true);
|
||||||
ShowPrompt(false, "Error: Moving is not possible here");
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
char fdpath[256]; // 256 is the maximum length of a full path
|
|
||||||
char fopath[256];
|
|
||||||
strncpy(fdpath, destdir, 255);
|
|
||||||
strncpy(fopath, orig, 255);
|
|
||||||
if (flags && (*flags & BUILD_PATH)) fvx_rmkdir(destdir);
|
|
||||||
bool same_drv = (strncmp(orig, destdir, 2) == 0);
|
|
||||||
bool res = PathCopyToFat(fdpath, fopath, flags, same_drv);
|
|
||||||
if (res && (!flags || !(*flags&SKIP_CUR))) PathDelete(orig);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathDelete(const char* path) {
|
bool PathDelete(const char* path) {
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
|
|
||||||
// move / copy flags
|
// move / copy flags
|
||||||
#define OVERRIDE_PERM (1UL<<0)
|
#define OVERRIDE_PERM (1UL<<0)
|
||||||
#define CALC_SHA (1UL<<1)
|
#define NO_CANCEL (1UL<<1)
|
||||||
#define BUILD_PATH (1UL<<2)
|
#define CALC_SHA (1UL<<2)
|
||||||
#define ASK_ALL (1UL<<3)
|
#define BUILD_PATH (1UL<<3)
|
||||||
#define SKIP_ALL (1UL<<4)
|
#define ASK_ALL (1UL<<4)
|
||||||
#define OVERWRITE_ALL (1UL<<5)
|
#define SKIP_ALL (1UL<<5)
|
||||||
|
#define OVERWRITE_ALL (1UL<<6)
|
||||||
|
|
||||||
/** Return total size of SD card **/
|
/** Return total size of SD card **/
|
||||||
uint64_t GetSDCardSize();
|
uint64_t GetSDCardSize();
|
||||||
@ -38,7 +39,7 @@ bool FileGetSha256(const char* path, u8* sha256);
|
|||||||
u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file);
|
u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file);
|
||||||
|
|
||||||
/** Inject file into file @offset **/
|
/** Inject file into file @offset **/
|
||||||
bool FileInjectFile(const char* dest, const char* orig, u32 offset);
|
bool FileInjectFile(const char* dest, const char* orig, u32 offset, u32* flags);
|
||||||
|
|
||||||
/** Create a new directory in cpath **/
|
/** Create a new directory in cpath **/
|
||||||
bool DirCreate(const char* cpath, const char* dirname);
|
bool DirCreate(const char* cpath, const char* dirname);
|
||||||
@ -46,6 +47,9 @@ bool DirCreate(const char* cpath, const char* dirname);
|
|||||||
/** Get # of files, subdirs and total size for directory **/
|
/** Get # of files, subdirs and total size for directory **/
|
||||||
bool DirInfo(const char* path, u64* tsize, u32* tdirs, u32* tfiles);
|
bool DirInfo(const char* path, u64* tsize, u32* tdirs, u32* tfiles);
|
||||||
|
|
||||||
|
/** Direct recursive move / copy of files or directories **/
|
||||||
|
bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move);
|
||||||
|
|
||||||
/** Recursively copy a file or directory **/
|
/** Recursively copy a file or directory **/
|
||||||
bool PathCopy(const char* destdir, const char* orig, u32* flags);
|
bool PathCopy(const char* destdir, const char* orig, u32* flags);
|
||||||
|
|
||||||
|
@ -213,6 +213,19 @@ FRESULT fvx_rmkdir (const TCHAR* path) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_rmkpath (const TCHAR* path) {
|
||||||
|
#if !_LFN_UNICODE // this will not work for unicode
|
||||||
|
TCHAR tpath[_MAX_FN_LEN+1];
|
||||||
|
strncpy(tpath, path, _MAX_FN_LEN);
|
||||||
|
TCHAR* slash = strrchr(tpath, '/');
|
||||||
|
if (!slash) return FR_DENIED;
|
||||||
|
*slash = '\0';
|
||||||
|
return worker_fvx_rmkdir( tpath );
|
||||||
|
#else
|
||||||
|
return FR_DENIED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if !_LFN_UNICODE // this will not work for unicode
|
#if !_LFN_UNICODE // this will not work for unicode
|
||||||
FRESULT worker_fvx_runlink (TCHAR* tpath) {
|
FRESULT worker_fvx_runlink (TCHAR* tpath) {
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
@ -310,7 +323,7 @@ FRESULT fvx_findpath (TCHAR* path, const TCHAR* pattern) {
|
|||||||
|
|
||||||
*(fname++) = '/';
|
*(fname++) = '/';
|
||||||
strncpy(fname, fno.fname, _MAX_FN_LEN - (fname - path));
|
strncpy(fname, fno.fname, _MAX_FN_LEN - (fname - path));
|
||||||
if (!*(fno.fname)) return FR_NO_FILE;
|
if (!*(fno.fname)) return FR_NO_PATH;
|
||||||
|
|
||||||
return FR_OK;
|
return FR_OK;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ FRESULT fvx_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw,
|
|||||||
|
|
||||||
// additional recursive functions
|
// additional recursive functions
|
||||||
FRESULT fvx_rmkdir (const TCHAR* path);
|
FRESULT fvx_rmkdir (const TCHAR* path);
|
||||||
|
FRESULT fvx_rmkpath (const TCHAR* path);
|
||||||
FRESULT fvx_runlink (const TCHAR* path);
|
FRESULT fvx_runlink (const TCHAR* path);
|
||||||
|
|
||||||
// additional wildcard based functions
|
// additional wildcard based functions
|
||||||
|
@ -801,7 +801,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
TruncateString(origstr, clipboard->entry[0].name, 18, 10);
|
TruncateString(origstr, clipboard->entry[0].name, 18, 10);
|
||||||
u64 offset = ShowHexPrompt(0, 8, "Inject data from %s?\nSpecifiy offset below.", origstr);
|
u64 offset = ShowHexPrompt(0, 8, "Inject data from %s?\nSpecifiy offset below.", origstr);
|
||||||
if (offset != (u64) -1) {
|
if (offset != (u64) -1) {
|
||||||
if (!FileInjectFile(curr_entry->path, clipboard->entry[0].path, (u32) offset))
|
if (!FileInjectFile(curr_entry->path, clipboard->entry[0].path, (u32) offset, NULL))
|
||||||
ShowPrompt(false, "Failed injecting %s", origstr);
|
ShowPrompt(false, "Failed injecting %s", origstr);
|
||||||
clipboard->n_entries = 0;
|
clipboard->n_entries = 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user