Add safety checks for low SD card space (#90)

* Some attempt.

* Enable some-safety-freespace-work nightlies

* Upload elf with nightly

* *Derp fixes.*

* Bye Bye testing things.

* Revert "Upload elf with nightly"

This reverts commit 303968cd78e466a3fcc010915565d8265acaa76a.

* Add safety checks to fcopy

Co-authored-by: StackZ <47382115+SuperSaiyajinStackZ@users.noreply.github.com>
This commit is contained in:
Pk11 2021-05-26 05:47:51 -05:00 committed by GitHub
commit baa14561eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 145 additions and 105 deletions

View file

@ -34,5 +34,6 @@ Result openFile(Handle *fileHandle, const char *path, bool write);
Result deleteFile(const char *path);
Result removeDir(const char *path);
Result removeDirRecursive(const char *path);
u64 getAvailableSpace();
#endif

View file

@ -34,7 +34,7 @@
namespace StringUtils {
std::string lower_case(const std::string &str);
std::string FetchStringsFromVector(const std::vector<std::string> &fetch);
std::string formatBytes(int bytes);
std::string formatBytes(u64 bytes);
std::string GetMarkString(int marks);
std::vector<std::string> GetMarks(int marks);
std::string format(const char *fmt_str, ...);

View file

@ -196,10 +196,6 @@ Result Init::MainLoop() {
if (!exiting) Gui::ScreenLogic(hDown, hHeld, touch, true, false);
if (aptCheckHomePressRejected()) {
if (Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS"))) aptSetHomeAllowed(true);
};
if (exiting) {
if (hDown & KEY_START) fullExit = true; // Make it optionally faster.

View file

@ -25,6 +25,7 @@
*/
#include "common.hpp"
#include "files.hpp"
#include "storeUtils.hpp"
#include "structs.hpp"

View file

@ -272,8 +272,7 @@ static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int
Overlays::ShowCredits();
} else if (touching(touch, mainButtons[6])) {
if (QueueRuns) exiting = Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS"));
else exiting = true;
if (!QueueRuns) exiting = true;
}
}
@ -313,8 +312,7 @@ static void SettingsHandleMain(int &page, bool &dspSettings, int &storeMode, int
break;
case 6:
if (QueueRuns) exiting = Msg::promptMsg(Lang::get("FEATURE_SIDE_EFFECTS"));
else exiting = true;
if (!QueueRuns) exiting = true;
break;
}
}

View file

@ -123,19 +123,25 @@ Result Title::Install(const char *ciaPath, bool updatingSelf) {
ret = FSFILE_GetSize(fileHandle, &size);
if (R_FAILED(ret)) {
printf("Error in:\nFSFILE_GetSize\n");
FSFILE_Close(fileHandle);
return ret;
}
if (getAvailableSpace() >= size) {
ret = AM_StartCiaInstall(media, &ciaHandle);
if (R_FAILED(ret)) {
printf("Error in:\nAM_StartCiaInstall\n");
FSFILE_Close(fileHandle);
return ret;
}
u32 toRead = 0x200000;
u8 *buf = new u8[toRead];
if (!buf) return -1;
if (!buf) {
FSFILE_Close(fileHandle);
return -1;
}
installSize = size;
do {
@ -148,8 +154,10 @@ Result Title::Install(const char *ciaPath, bool updatingSelf) {
ret = AM_FinishCiaInstall(ciaHandle);
if (R_FAILED(ret)) {
printf("Error in:\nAM_FinishCiaInstall\n");
FSFILE_Close(fileHandle);
return ret;
}
}
ret = FSFILE_Close(fileHandle);
if (R_FAILED(ret)) {

View file

@ -103,11 +103,14 @@ static void commitToFileThreadFunc(void *args) {
}
static size_t file_handle_data(char *ptr, size_t size, size_t nmemb, void *userdata) {
if (getAvailableSpace() < (u64)downloadTotal) return 0; // Out of space.
if (writeError) return 0;
if (QueueSystem::CancelCallback) return 0;
(void)userdata;
const size_t bsz = size * nmemb;
size_t tofill = 0;
if (writeError) return 0;
if (QueueSystem::CancelCallback) return 0;
if (!g_buffers[g_index]) {
LightEvent_Init(&waitCommit, RESET_STICKY);
@ -593,6 +596,7 @@ bool DownloadUniStore(const std::string &URL, int currentRev, std::string &fl, b
return false;
}
if (getAvailableSpace() >= result_written) {
if (nlohmann::json::accept(result_buf)) {
nlohmann::json parsedAPI = nlohmann::json::parse(result_buf);
@ -672,6 +676,7 @@ bool DownloadUniStore(const std::string &URL, int currentRev, std::string &fl, b
Msg::waitMsg(Lang::get("UNISTORE_INVALID_ERROR"));
}
}
}
socExit();
free(result_buf);
@ -733,6 +738,7 @@ bool DownloadSpriteSheet(const std::string &URL, const std::string &file) {
return false;
}
if (getAvailableSpace() >= result_written) {
C2D_SpriteSheet sheet = C2D_SpriteSheetLoadFromMem(result_buf, result_written);
if (sheet) {
@ -752,6 +758,7 @@ bool DownloadSpriteSheet(const std::string &URL, const std::string &file) {
return true;
}
}
}
socExit();
free(result_buf);

View file

@ -25,6 +25,7 @@
*/
#include "extract.hpp"
#include "files.hpp"
#include "queueSystem.hpp"
#include "scriptUtils.hpp"
#include <archive.hpp>
@ -65,6 +66,8 @@ Result getExtractedSize(const std::string &archivePath, const std::string &wante
}
Result extractArchive(const std::string &archivePath, const std::string &wantedFile, const std::string &outputPath) {
if (getAvailableSpace() < extractSize) return -1; // Out of space.
archive *a = archive_read_new();
archive_entry *entry;

View file

@ -25,6 +25,7 @@
*/
#include "fileBrowse.hpp"
#include "files.hpp"
#include "json.hpp"
#include "structs.hpp"
#include <3ds.h>
@ -236,6 +237,11 @@ int fcopy(const char *sourcePath, const char *destinationPath) {
return -1;
}
if(getAvailableSpace() < copySize) {
fclose(sourceFile);
return -1;
}
FILE *destinationFile = fopen(destinationPath, "wb");
if (!destinationFile) {
fclose(sourceFile);
@ -245,7 +251,15 @@ int fcopy(const char *sourcePath, const char *destinationPath) {
while(1) {
/* Copy file to destination path. */
int numr = fread(copyBuf, sizeof(u32), copyBufSize, sourceFile);
fwrite(copyBuf, sizeof(u32), numr, destinationFile);
int written = fwrite(copyBuf, sizeof(u32), numr, destinationFile);
if(written != numr) {
fclose(sourceFile);
fclose(destinationFile);
return -1;
}
copyOffset += copyBufSize * sizeof(u32);
if (copyOffset > copySize) {

View file

@ -25,6 +25,8 @@
*/
#include "files.hpp"
#include <sys/stat.h>
#include <sys/statvfs.h>
FS_Path getPathInfo(const char *path, FS_ArchiveID *archive) {
*archive = ARCHIVE_SDMC;
@ -128,3 +130,12 @@ Result removeDirRecursive(const char *path) {
return ret;
}
/* Code borrowed from GodMode9i:
https://github.com/DS-Homebrew/GodMode9i/blob/d68ac105e68b4a1fc2c706a08c7a394255c325c2/arm9/source/driveOperations.cpp#L166-L170
*/
u64 getAvailableSpace() {
struct statvfs st;
statvfs("sdmc:/", &st);
return (u64)st.f_bsize * (u64)st.f_bavail;
}

View file

@ -65,14 +65,15 @@ std::string StringUtils::FetchStringsFromVector(const std::vector<std::string> &
/*
adapted from GM9i's byte parsing.
*/
std::string StringUtils::formatBytes(int bytes) {
std::string StringUtils::formatBytes(u64 bytes) {
char out[32];
if (bytes == 1) snprintf(out, sizeof(out), "%d Byte", bytes);
else if (bytes < 1024) snprintf(out, sizeof(out), "%d Bytes", bytes);
else if (bytes < 1024 * 1024) snprintf(out, sizeof(out), "%.1f KiB", (float)bytes / 1024);
else if (bytes < 1024 * 1024 * 1024) snprintf(out, sizeof(out), "%.1f MiB", (float)bytes / 1024 / 1024);
else snprintf(out, sizeof(out), "%.1f GiB", (float)bytes / 1024 / 1024 / 1024);
if (bytes == 1) snprintf(out, sizeof(out), "%lld Byte", bytes);
else if (bytes < 1ull << 10) snprintf(out, sizeof(out), "%lld Bytes", bytes);
else if (bytes < 1ull << 20) snprintf(out, sizeof(out), "%.1f KiB", (float)bytes / 1024);
else if (bytes < 1ull << 30) snprintf(out, sizeof(out), "%.1f MiB", (float)bytes / 1024 / 1024);
else if (bytes < 1ull << 40) snprintf(out, sizeof(out), "%.1f GiB", (float)bytes / 1024 / 1024 / 1024);
else snprintf(out, sizeof(out), "%.1f TiB", (float)bytes / 1024 / 1024 / 1024 / 1024);
return out;
}