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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user