diff --git a/arm9/source/driveMenu.cpp b/arm9/source/driveMenu.cpp index 5293fcf..b7383be 100644 --- a/arm9/source/driveMenu.cpp +++ b/arm9/source/driveMenu.cpp @@ -160,12 +160,12 @@ void dm_drawBottomScreen(void) { case DriveMenuOperation::sdCard: font->printf(0, 0, false, Alignment::left, Palette::white, STR_SDCARD_LABEL.c_str(), sdLabel[0] == 0 ? STR_UNTITLED.c_str() : sdLabel); font->printf(0, 1, false, Alignment::left, Palette::white, STR_SD_FAT.c_str(), getBytes(sdSize).c_str()); - font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(getBytesFree("sd:/")).c_str()); + font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(driveSizeFree(Drive::sdCard)).c_str()); break; case DriveMenuOperation::flashcard: font->printf(0, 0, false, Alignment::left, Palette::white, STR_FLASHCARD_LABEL.c_str(), fatLabel[0] == 0 ? STR_UNTITLED.c_str() : fatLabel); font->printf(0, 1, false, Alignment::left, Palette::white, STR_SLOT1_FAT.c_str(), getBytes(fatSize).c_str()); - font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(getBytesFree("fat:/")).c_str()); + font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(driveSizeFree(Drive::flashcard)).c_str()); break; case DriveMenuOperation::gbaCart: font->printf(0, 0, false, Alignment::left, Palette::white, STR_GBA_GAMECART.c_str(), romTitle[1]); @@ -186,16 +186,17 @@ void dm_drawBottomScreen(void) { case DriveMenuOperation::ramDrive: font->print(0, 0, false, STR_RAMDRIVE_LABEL); font->printf(0, 1, false, Alignment::left, Palette::white, STR_RAMDRIVE_FAT.c_str(), getBytes(ramdSize).c_str()); - font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(getBytesFree("ram:/")).c_str()); + font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(driveSizeFree(Drive::ramDrive)).c_str()); break; case DriveMenuOperation::sysNand: font->print(0, 0, false, STR_SYSNAND_LABEL); font->printf(0, 1, false, Alignment::left, Palette::white, STR_SYSNAND_FAT.c_str(), getBytes(nandSize).c_str()); - font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(getBytesFree("nand:/")).c_str()); + font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(driveSizeFree(Drive::nand)).c_str()); break; case DriveMenuOperation::fatImage: font->printf(0, 0, false, Alignment::left, Palette::white, STR_FAT_LABEL.c_str(), imgLabel[0] == 0 ? STR_UNTITLED.c_str() : imgLabel); font->printf(0, 1, false, Alignment::left, Palette::white, STR_FAT_IMAGE.c_str(), getBytes(imgSize).c_str()); + font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getBytes(driveSizeFree(Drive::fatImg)).c_str()); break; case DriveMenuOperation::none: break; diff --git a/arm9/source/driveOperations.cpp b/arm9/source/driveOperations.cpp index 59db8d5..10e1cfd 100644 --- a/arm9/source/driveOperations.cpp +++ b/arm9/source/driveOperations.cpp @@ -443,3 +443,22 @@ bool driveRemoved(Drive drive) { return false; } + +u64 driveSizeFree(Drive drive) { + switch(drive) { + case Drive::sdCard: + return getBytesFree("sd:/"); + case Drive::flashcard: + return getBytesFree("fat:/"); + case Drive::ramDrive: + return getBytesFree("ram:/"); + case Drive::nand: + return getBytesFree("nand:/"); + case Drive::nitroFS: + return 0; + case Drive::fatImg: + return getBytesFree("img:/"); + } + + return 0; +} diff --git a/arm9/source/driveOperations.h b/arm9/source/driveOperations.h index 6873ac5..b91a176 100644 --- a/arm9/source/driveOperations.h +++ b/arm9/source/driveOperations.h @@ -56,5 +56,6 @@ extern void imgUnmount(void); extern u64 getBytesFree(const char* drivePath); extern bool driveWritable(Drive drive); extern bool driveRemoved(Drive drive); +extern u64 driveSizeFree(Drive drive); #endif //FLASHCARD_H diff --git a/arm9/source/fileOperations.cpp b/arm9/source/fileOperations.cpp index c1984e5..06a42fe 100644 --- a/arm9/source/fileOperations.cpp +++ b/arm9/source/fileOperations.cpp @@ -180,17 +180,56 @@ void dirCopy(const DirEntry &entry, int i, const char *destinationPath, const ch if (((int)dirContents.size()) != 1) fcopy((sourcePath + ("/" + entry.name)).c_str(), (destinationPath + ("/" + entry.name)).c_str()); } -int fcopy(const char *sourcePath, const char *destinationPath) { +u64 dirSize(const std::vector &dirContents) { + u64 size = 0; + + for(const DirEntry &entry : dirContents) { + if(entry.name == "." || entry.name == "..") + continue; + + if(entry.isDirectory) { + std::vector subdirContents; + if(chdir(entry.name.c_str()) == 0 && getDirectoryContents(subdirContents)) { + size += dirSize(subdirContents); + chdir(".."); + } + } else { + size += getFileSize(entry.name.c_str()); + } + } + + return size; +} + +bool fcopy(const char *sourcePath, const char *destinationPath) { DIR *isDir = opendir(sourcePath); if (isDir != NULL) { closedir(isDir); // Source path is a directory + char startPath[PATH_MAX]; + getcwd(startPath, PATH_MAX); + chdir(sourcePath); std::vector dirContents; getDirectoryContents(dirContents); + // Check that everything will fit + if(dirSize(dirContents) > driveSizeFree(currentDrive)) { + font->clear(false); + font->printf(0, 0, false, Alignment::left, Palette::white, (STR_FILE_TOO_BIG + "\n\n" + STR_A_OK).c_str(), sourcePath); + font->update(false); + + do { + swiWaitForVBlank(); + scanKeys(); + } while(!(keysDown() & KEY_A)); + + chdir(startPath); + return false; + } + mkdir(destinationPath, 0777); for (int i = 1; i < ((int)dirContents.size()); i++) { chdir(sourcePath); @@ -199,25 +238,39 @@ int fcopy(const char *sourcePath, const char *destinationPath) { chdir(destinationPath); chdir(".."); - return 1; + return true; } else { closedir(isDir); // Source path is a file FILE* sourceFile = fopen(sourcePath, "rb"); - off_t fsize = 0; + long fsize = 0; if (sourceFile) { fseek(sourceFile, 0, SEEK_END); fsize = ftell(sourceFile); // Get source file's size fseek(sourceFile, 0, SEEK_SET); } else { - return -1; + return false; + } + + // Check that the file will fit + if((u64)fsize > driveSizeFree(currentDrive)) { + font->clear(false); + font->printf(0, 0, false, Alignment::left, Palette::white, (STR_FILE_TOO_BIG + "\n\n" + STR_A_OK).c_str(), sourcePath); + font->update(false); + + do { + swiWaitForVBlank(); + scanKeys(); + } while(!(keysDown() & KEY_A)); + + return false; } FILE* destinationFile = fopen(destinationPath, "wb"); if (!destinationFile) { fclose(sourceFile); - return -1; + return false; } font->clear(false); @@ -233,8 +286,7 @@ int fcopy(const char *sourcePath, const char *destinationPath) { // Cancel copying fclose(sourceFile); fclose(destinationFile); - return -1; - break; + return false; } font->print((offset / (fsize / (SCREEN_COLS - 2))) + 1, 1, false, "="); @@ -246,7 +298,7 @@ int fcopy(const char *sourcePath, const char *destinationPath) { if(fwrite(copyBuf, 1, numr, destinationFile) != numr) { fclose(sourceFile); fclose(destinationFile); - return -1; + return false; } offset += copyBufSize; @@ -254,12 +306,12 @@ int fcopy(const char *sourcePath, const char *destinationPath) { fclose(sourceFile); fclose(destinationFile); - return 1; + return true; break; } } - return -1; + return false; } } diff --git a/arm9/source/fileOperations.h b/arm9/source/fileOperations.h index 7a19fb8..e474f77 100644 --- a/arm9/source/fileOperations.h +++ b/arm9/source/fileOperations.h @@ -24,7 +24,7 @@ extern std::string getBytes(off_t bytes); extern off_t getFileSize(const char *fileName); extern bool calculateSHA1(const char *fileName, u8 *sha1); extern int trimNds(const char *fileName); -extern int fcopy(const char *sourcePath, const char *destinationPath); +extern bool fcopy(const char *sourcePath, const char *destinationPath); void changeFileAttribs(const DirEntry *entry); #endif // FILE_COPY diff --git a/arm9/source/file_browse.cpp b/arm9/source/file_browse.cpp index 8e8033c..ac36234 100644 --- a/arm9/source/file_browse.cpp +++ b/arm9/source/file_browse.cpp @@ -76,7 +76,7 @@ bool dirEntryPredicate (const DirEntry& lhs, const DirEntry& rhs) { return strcasecmp(lhs.name.c_str(), rhs.name.c_str()) < 0; } -void getDirectoryContents(std::vector& dirContents) { +bool getDirectoryContents(std::vector& dirContents) { dirContents.clear(); DIR *pdir = opendir ("."); @@ -84,6 +84,7 @@ void getDirectoryContents(std::vector& dirContents) { if (pdir == nullptr) { font->print(0, 0, true, STR_UNABLE_TO_OPEN_DIRECTORY); font->update(true); + return false; } else { while (true) { dirent *pent = readdir(pdir); @@ -109,6 +110,8 @@ void getDirectoryContents(std::vector& dirContents) { // Add ".." to top of list dirContents.insert(dirContents.begin(), {"..", 0, true, false}); + + return true; } void showDirectoryContents(std::vector &dirContents, int fileOffset, int startRow) { @@ -559,18 +562,18 @@ bool fileBrowse_paste(char dest[256]) { } void recRemove(const char *path, std::vector dirContents) { - chdir (path); - getDirectoryContents(dirContents); - for (int i = 1; i < ((int)dirContents.size()); i++) { - DirEntry &entry = dirContents[i]; - if (entry.isDirectory) - recRemove(entry.name.c_str(), dirContents); - if (!(FAT_getAttr(entry.name.c_str()) & ATTR_READONLY)) { - remove(entry.name.c_str()); + if(chdir(path) == 0 && getDirectoryContents(dirContents)) { + for (int i = 1; i < ((int)dirContents.size()); i++) { + DirEntry &entry = dirContents[i]; + if (entry.isDirectory) + recRemove(entry.name.c_str(), dirContents); + if (!(FAT_getAttr(entry.name.c_str()) & ATTR_READONLY)) { + remove(entry.name.c_str()); + } } + chdir(".."); + remove(path); } - chdir (".."); - remove(path); } void fileBrowse_drawBottomScreen(DirEntry* entry) { diff --git a/arm9/source/file_browse.h b/arm9/source/file_browse.h index 68e95ad..1f03cb2 100644 --- a/arm9/source/file_browse.h +++ b/arm9/source/file_browse.h @@ -57,7 +57,7 @@ enum class FileOperation { bool extension(const std::string_view filename, const std::vector &extensions); std::string browseForFile (void); -void getDirectoryContents (std::vector& dirContents); +bool getDirectoryContents (std::vector& dirContents); diff --git a/arm9/source/language.inl b/arm9/source/language.inl index f04a655..d580607 100644 --- a/arm9/source/language.inl +++ b/arm9/source/language.inl @@ -37,6 +37,7 @@ STRING(START_FAILED_ERROR_N, "Start failed. Error %d") STRING(HEADER_TITLE, "Header Title: %s") STRING(TITLE_ID, "Title ID: %s") STRING(TITLE_IN_LANGUAGE, "Title: (\\DV %s)") +STRING(FILE_TOO_BIG, "%s is too large to copy to this drive. Please delete some files and try again.") // Drive labels STRING(SDCARD_LABEL, "[sd:] SDCARD (%s)") diff --git a/nitrofiles/languages/en-US/language.ini b/nitrofiles/languages/en-US/language.ini index 064ba85..0173ae9 100644 --- a/nitrofiles/languages/en-US/language.ini +++ b/nitrofiles/languages/en-US/language.ini @@ -37,6 +37,7 @@ START_FAILED_ERROR_N=Start failed. Error %d HEADER_TITLE=Header Title: %s TITLE_ID=Title ID: %s TITLE_IN_LANGUAGE=Title: (\DV %s) +FILE_TOO_BIG=%s is too large to copy to this drive. Please delete some files and try again. SDCARD_LABEL=[sd:] SDCARD (%s) FLASHCARD_LABEL=[fat:] FLASHCARD (%s)