many more optimisations. cleaned up fs code. bug fixes etc (see below).

- fix usb using the wrong year when polling the timestamp.
- fs file/dir has been re-written to allow for simplified calling and remove the need of manually closing.
- add SetSize for stdio by using ftruncate.
- don't truncate the file when opened in stdio.
- add getcount api for stdio.
- display file/dir count in filebrowser for non-native fs.
- allow hash to be used on non-native fs.
- slightly optimise nro parsing by manually calculating nro size rather than doing an os call.
- slightly optimise nro parsing by keeping the fs struct alive between calls, rather than creating a new one on the stack.
- fix filebrowser peeking into zip files that are stored on non-sd fs.
- set the timestamp of a file moved to a stdio location (cut/paste).
- slightly optimise daybreak update folder detection by skipping opening/polling the dir size.
- set the fullpath of the file thats being hashed in progress box.
This commit is contained in:
ITotalJustice
2025-05-26 17:06:04 +01:00
parent 3e3ec71329
commit a9931a975d
23 changed files with 390 additions and 387 deletions

View File

@@ -221,6 +221,11 @@ Result GetFileTimeStampRaw(FsFileSystem* fs, const FsPath& path, FsTimeStampRaw
return fsFsGetFileTimeStampRaw(fs, path, out);
}
Result SetTimestamp(FsFileSystem* fs, const FsPath& path, const FsTimeStampRaw* ts) {
// unsuported.
R_SUCCEED();
}
bool FileExists(FsFileSystem* fs, const FsPath& path) {
FsDirEntryType type;
R_TRY_RESULT(GetEntryType(fs, path, &type), false);
@@ -237,16 +242,16 @@ Result read_entire_file(FsFileSystem* _fs, const FsPath& path, std::vector<u8>&
FsNative fs{_fs, false};
R_TRY(fs.GetFsOpenResult());
FsFile f;
File f;
R_TRY(fs.OpenFile(path, FsOpenMode_Read, &f));
ON_SCOPE_EXIT(fsFileClose(&f));
ON_SCOPE_EXIT(f.Close());
s64 size;
R_TRY(fsFileGetSize(&f, &size));
R_TRY(f.GetSize(&size));
out.resize(size);
u64 bytes_read;
R_TRY(fsFileRead(&f, 0, out.data(), out.size(), FsReadOption_None, &bytes_read));
R_TRY(f.Read(0, out.data(), out.size(), FsReadOption_None, &bytes_read));
R_UNLESS(bytes_read == out.size(), 1);
R_SUCCEED();
@@ -262,12 +267,12 @@ Result write_entire_file(FsFileSystem* _fs, const FsPath& path, const std::vecto
return rc;
}
FsFile f;
File f;
R_TRY(fs.OpenFile(path, FsOpenMode_Write, &f));
ON_SCOPE_EXIT(fsFileClose(&f));
ON_SCOPE_EXIT(f.Close());
R_TRY(fsFileSetSize(&f, in.size()));
R_TRY(fsFileWrite(&f, 0, in.data(), in.size(), FsWriteOption_None));
R_TRY(f.SetSize(in.size()));
R_TRY(f.Write(0, in.data(), in.size(), FsWriteOption_None));
R_SUCCEED();
}
@@ -292,7 +297,12 @@ Result CreateFile(const FsPath& path, u64 size, u32 option, bool ignore_read_onl
R_TRY(fsdevGetLastResult());
return Fs::ResultUnknownStdioError;
}
close(fd);
ON_SCOPE_EXIT(close(fd));
if (size) {
R_UNLESS(!ftruncate(fd, size), Fs::ResultUnknownStdioError);
}
R_SUCCEED();
}
@@ -405,6 +415,20 @@ Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out) {
R_SUCCEED();
}
Result SetTimestamp(const FsPath& path, const FsTimeStampRaw* ts) {
if (ts->is_valid) {
timeval val[2]{};
val[0].tv_sec = ts->accessed;
val[1].tv_sec = ts->modified;
if (utimes(path, val)) {
log_write("utimes() failed: %d %s\n", errno, strerror(errno));
}
}
R_SUCCEED();
}
bool FileExists(const FsPath& path) {
FsDirEntryType type;
R_TRY_RESULT(GetEntryType(path, &type), false);
@@ -458,92 +482,95 @@ Result copy_entire_file(const FsPath& dst, const FsPath& src, bool ignore_read_o
}
Result OpenFile(fs::Fs* fs, const fs::FsPath& path, u32 mode, File* f) {
*f = {};
f->m_fs = fs;
if (f->m_fs->IsNative()) {
auto fs = (fs::FsNative*)f->m_fs;
R_TRY(fs->OpenFile(path, mode, &f->m_native));
R_TRY(fsFsOpenFile(&fs->m_fs, path, mode, &f->m_native));
} else {
if ((mode & FsOpenMode_Read) && (mode & FsOpenMode_Write)) {
// todo:
R_THROW(0x1);
f->m_stdio = std::fopen(path, "rb+");
} else if (mode & FsOpenMode_Read) {
f->m_stdio = std::fopen(path, "rb");
} else if (mode & FsOpenMode_Write) {
f->m_stdio = std::fopen(path, "wb");
// not possible to open file with just write and not append
// or create or truncate. So rw it is!
f->m_stdio = std::fopen(path, "rb+");
}
R_UNLESS(f->m_stdio, 0x1);
R_UNLESS(f->m_stdio, Fs::ResultUnknownStdioError);
std::strcpy(f->m_path, path);
}
std::strcpy(f->m_path, path);
R_SUCCEED();
}
Result FileRead(File* f, s64 off, void* buf, u64 read_size, u32 option, u64* bytes_read) {
if (f->m_fs->IsNative()) {
R_TRY(fsFileRead(&f->m_native, off, buf, read_size, option, bytes_read));
File::~File() {
Close();
}
Result File::Read( s64 off, void* buf, u64 read_size, u32 option, u64* bytes_read) {
if (m_fs->IsNative()) {
R_TRY(fsFileRead(&m_native, off, buf, read_size, option, bytes_read));
} else {
if (f->m_stdio_off != off) {
f->m_stdio_off = off;
std::fseek(f->m_stdio, off, SEEK_SET);
if (m_stdio_off != off) {
m_stdio_off = off;
std::fseek(m_stdio, off, SEEK_SET);
}
*bytes_read = std::fread(buf, 1, read_size, f->m_stdio);
*bytes_read = std::fread(buf, 1, read_size, m_stdio);
// if we read less bytes than expected, check if there was an error (ignoring eof).
if (*bytes_read < read_size) {
if (!std::feof(f->m_stdio) && std::ferror(f->m_stdio)) {
R_THROW(0x1);
if (!std::feof(m_stdio) && std::ferror(m_stdio)) {
R_THROW(Fs::ResultUnknownStdioError);
}
}
f->m_stdio_off += *bytes_read;
m_stdio_off += *bytes_read;
}
R_SUCCEED();
}
Result FileWrite(File* f, s64 off, const void* buf, u64 write_size, u32 option) {
if (f->m_fs->IsNative()) {
R_TRY(fsFileWrite(&f->m_native, off, buf, write_size, option));
Result File::Write(s64 off, const void* buf, u64 write_size, u32 option) {
if (m_fs->IsNative()) {
R_TRY(fsFileWrite(&m_native, off, buf, write_size, option));
} else {
if (f->m_stdio_off != off) {
if (m_stdio_off != off) {
log_write("[FS] diff seek\n");
f->m_stdio_off = off;
std::fseek(f->m_stdio, off, SEEK_SET);
m_stdio_off = off;
std::fseek(m_stdio, off, SEEK_SET);
}
const auto result = std::fwrite(buf, 1, write_size, f->m_stdio);
const auto result = std::fwrite(buf, 1, write_size, m_stdio);
// log_write("[FS] fwrite res: %zu vs %zu\n", result, write_size);
R_UNLESS(result == write_size, 0x1);
R_UNLESS(result == write_size, Fs::ResultUnknownStdioError);
f->m_stdio_off += write_size;
m_stdio_off += write_size;
}
R_SUCCEED();
}
Result FileSetSize(File* f, s64 sz) {
if (f->m_fs->IsNative()) {
R_TRY(fsFileSetSize(&f->m_native, sz));
Result File::SetSize(s64 sz) {
if (m_fs->IsNative()) {
R_TRY(fsFileSetSize(&m_native, sz));
} else {
R_SUCCEED();
// const auto fd = fileno(f->m_stdio);
// R_UNLESS(fd > 0, 0x1);
// R_UNLESS(!ftruncate(fd, sz), 0x1);
const auto fd = fileno(m_stdio);
R_UNLESS(fd > 0, Fs::ResultUnknownStdioError);
R_UNLESS(!ftruncate(fd, sz), Fs::ResultUnknownStdioError);
}
R_SUCCEED();
}
Result FileGetSize(File* f, s64* out) {
if (f->m_fs->IsNative()) {
R_TRY(fsFileGetSize(&f->m_native, out));
Result File::GetSize(s64* out) {
if (m_fs->IsNative()) {
R_TRY(fsFileGetSize(&m_native, out));
} else {
struct stat st;
const auto fd = fileno(f->m_stdio);
const auto fd = fileno(m_stdio);
bool did_stat{};
if (fd && !fstat(fd, &st)) {
@@ -551,7 +578,7 @@ Result FileGetSize(File* f, s64* out) {
}
if (!did_stat) {
R_UNLESS(!lstat(f->m_path, &st), 0x1);
R_UNLESS(!lstat(m_path, &st), Fs::ResultUnknownStdioError);
}
*out = st.st_size;
@@ -560,68 +587,142 @@ Result FileGetSize(File* f, s64* out) {
R_SUCCEED();
}
void FileClose(File* f) {
if (f->m_fs->IsNative()) {
fsFileClose(&f->m_native);
void File::Close() {
if (m_fs->IsNative()) {
if (serviceIsActive(&m_native.s)) {
fsFileClose(&m_native);
m_native = {};
}
} else {
std::fclose(f->m_stdio);
if (m_stdio) {
std::fclose(m_stdio);
m_stdio = {};
}
}
*f = {};
}
Result OpenDirectory(fs::Fs* fs, const fs::FsPath& path, u32 mode, Dir* d) {
*d = {};
d->m_fs = fs;
d->m_mode = mode;
if (d->m_fs->IsNative()) {
auto fs = (fs::FsNative*)d->m_fs;
R_TRY(fs->OpenDirectory(path, mode, &d->m_native));
R_TRY(fsFsOpenDirectory(&fs->m_fs, path, mode, &d->m_native));
} else {
d->m_stdio = opendir(path);
R_UNLESS(d->m_stdio, 0x1);
R_UNLESS(d->m_stdio, Fs::ResultUnknownStdioError);
}
R_SUCCEED();
}
Result DirReadAll(Dir* d, std::vector<FsDirectoryEntry>& buf) {
Result DirGetEntryCount(fs::Fs* m_fs, const fs::FsPath& path, s64* count, u32 mode) {
s64 file_count, dir_count;
R_TRY(DirGetEntryCount(m_fs, path, &file_count, &dir_count, mode));
*count = file_count + dir_count;
R_SUCCEED();
}
Result DirGetEntryCount(fs::Fs* m_fs, const fs::FsPath& path, s64* file_count, s64* dir_count, u32 mode) {
*file_count = *dir_count = 0;
if (m_fs->IsNative()) {
if (mode & FsDirOpenMode_ReadDirs){
fs::Dir dir;
R_TRY(m_fs->OpenDirectory(path, FsDirOpenMode_ReadDirs|FsDirOpenMode_NoFileSize, &dir));
R_TRY(dir.GetEntryCount(file_count));
}
if (mode & FsDirOpenMode_ReadFiles){
fs::Dir dir;
R_TRY(m_fs->OpenDirectory(path, FsDirOpenMode_ReadFiles|FsDirOpenMode_NoFileSize, &dir));
R_TRY(dir.GetEntryCount(file_count));
}
} else {
fs::Dir dir;
R_TRY(m_fs->OpenDirectory(path, mode, &dir));
while (auto d = readdir(dir.m_stdio)) {
if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) {
continue;
}
if (d->d_type == DT_DIR) {
if (!(mode & FsDirOpenMode_ReadDirs)) {
continue;
}
(*dir_count)++;
} else if (d->d_type == DT_REG) {
if (!(mode & FsDirOpenMode_ReadFiles)) {
continue;
}
(*file_count)++;
}
}
}
R_SUCCEED();
}
Dir::~Dir() {
Close();
}
Result Dir::GetEntryCount(s64* out) {
*out = 0;
if (m_fs->IsNative()) {
R_TRY(fsDirGetEntryCount(&m_native, out));
} else {
while (auto d = readdir(m_stdio)) {
if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) {
continue;
}
(*out)++;
}
// NOTE: this will *not* work for native mounted folders!!!
rewinddir(m_stdio);
}
R_SUCCEED();
}
Result Dir::ReadAll(std::vector<FsDirectoryEntry>& buf) {
buf.clear();
if (d->m_fs->IsNative()) {
auto fs = (fs::FsNative*)d->m_fs;
if (m_fs->IsNative()) {
s64 count;
R_TRY(fs->DirGetEntryCount(&d->m_native, &count));
R_TRY(GetEntryCount(&count));
buf.resize(count);
R_TRY(fs->DirRead(&d->m_native, &count, buf.size(), buf.data()));
R_TRY(fsDirRead(&m_native, &count, buf.size(), buf.data()));
buf.resize(count);
} else {
buf.reserve(1000);
struct dirent* dirent;
while ((dirent = readdir(d->m_stdio))) {
if (!std::strcmp(dirent->d_name, ".") || !std::strcmp(dirent->d_name, "..")) {
while (auto d = readdir(m_stdio)) {
if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) {
continue;
}
FsDirectoryEntry entry{};
if (dirent->d_type == DT_DIR) {
if (!(d->m_mode & FsDirOpenMode_ReadDirs)) {
if (d->d_type == DT_DIR) {
if (!(m_mode & FsDirOpenMode_ReadDirs)) {
continue;
}
entry.type = FsDirEntryType_Dir;
} else if (dirent->d_type == DT_REG) {
if (!(d->m_mode & FsDirOpenMode_ReadFiles)) {
} else if (d->d_type == DT_REG) {
if (!(m_mode & FsDirOpenMode_ReadFiles)) {
continue;
}
entry.type = FsDirEntryType_File;
} else {
log_write("[FS] WARNING: unknown type when reading dir: %u\n", d->d_type);
continue;
}
std::strcpy(entry.name, dirent->d_name);
std::strcpy(entry.name, d->d_name);
buf.emplace_back(entry);
}
}
@@ -629,14 +730,18 @@ Result DirReadAll(Dir* d, std::vector<FsDirectoryEntry>& buf) {
R_SUCCEED();
}
void DirClose(Dir* d) {
if (d->m_fs->IsNative()) {
fsDirClose(&d->m_native);
void Dir::Close() {
if (m_fs->IsNative()) {
if (serviceIsActive(&m_native.s)) {
fsDirClose(&m_native);
m_native = {};
}
} else {
closedir(d->m_stdio);
if (m_stdio) {
closedir(m_stdio);
m_stdio = {};
}
}
*d = {};
}
Result FileGetSizeAndTimestamp(fs::Fs* m_fs, const FsPath& path, FsTimeStampRaw* ts, s64* size) {
@@ -649,9 +754,9 @@ Result FileGetSizeAndTimestamp(fs::Fs* m_fs, const FsPath& path, FsTimeStampRaw*
File f;
R_TRY(m_fs->OpenFile(path, FsOpenMode_Read, &f));
ON_SCOPE_EXIT(fs->FileClose(&f));
ON_SCOPE_EXIT(f.Close());
R_TRY(m_fs->FileGetSize(&f, size));
R_TRY(f.GetSize(size));
} else {
struct stat st;
R_UNLESS(!lstat(path, &st), 0x1);
@@ -673,16 +778,15 @@ Result IsDirEmpty(fs::Fs* m_fs, const fs::FsPath& path, bool* out) {
auto fs = (fs::FsNative*)m_fs;
s64 count;
R_TRY(fs->DirGetEntryCount(path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles | FsDirOpenMode_NoFileSize, &count));
R_TRY(fs->DirGetEntryCount(path, &count, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles));
*out = !count;
} else {
auto dir = opendir(path);
R_UNLESS(dir, 0x1);
ON_SCOPE_EXIT(closedir(dir));
struct dirent* dirent;
while ((dirent = readdir(dir))) {
if (!std::strcmp(dirent->d_name, ".") || !std::strcmp(dirent->d_name, "..")) {
while (auto d = readdir(dir)) {
if (!std::strcmp(d->d_name, ".") || !std::strcmp(d->d_name, "..")) {
continue;
}