mtp: bump to 6e24502, fixes freezing if write blocks for too long, simplify stream install for mtp and ftp.
see: https://github.com/ITotalJustice/libhaze/issues/1
This commit is contained in:
@@ -399,7 +399,7 @@ endif()
|
|||||||
if (ENABLE_LIBHAZE)
|
if (ENABLE_LIBHAZE)
|
||||||
FetchContent_Declare(libhaze
|
FetchContent_Declare(libhaze
|
||||||
GIT_REPOSITORY https://github.com/ITotalJustice/libhaze.git
|
GIT_REPOSITORY https://github.com/ITotalJustice/libhaze.git
|
||||||
GIT_TAG d60ba60
|
GIT_TAG 6e24502
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(libhaze)
|
FetchContent_MakeAvailable(libhaze)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace sphaira::haze {
|
namespace sphaira::libhaze {
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
bool IsInit();
|
bool IsInit();
|
||||||
@@ -15,4 +15,4 @@ using OnInstallClose = std::function<void()>;
|
|||||||
void InitInstallMode(const OnInstallStart& on_start, const OnInstallWrite& on_write, const OnInstallClose& on_close);
|
void InitInstallMode(const OnInstallStart& on_start, const OnInstallWrite& on_write, const OnInstallClose& on_close);
|
||||||
void DisableInstallMode();
|
void DisableInstallMode();
|
||||||
|
|
||||||
} // namespace sphaira::haze
|
} // namespace sphaira::libhaze
|
||||||
|
|||||||
@@ -952,9 +952,9 @@ void App::SetMtpEnable(bool enable) {
|
|||||||
|
|
||||||
#ifdef ENABLE_LIBHAZE
|
#ifdef ENABLE_LIBHAZE
|
||||||
if (enable) {
|
if (enable) {
|
||||||
haze::Init();
|
libhaze::Init();
|
||||||
} else {
|
} else {
|
||||||
haze::Exit();
|
libhaze::Exit();
|
||||||
}
|
}
|
||||||
#endif // ENABLE_LIBHAZE
|
#endif // ENABLE_LIBHAZE
|
||||||
}
|
}
|
||||||
@@ -1632,7 +1632,7 @@ App::App(const char* argv0) {
|
|||||||
#ifdef ENABLE_LIBHAZE
|
#ifdef ENABLE_LIBHAZE
|
||||||
if (App::GetMtpEnable()) {
|
if (App::GetMtpEnable()) {
|
||||||
SCOPED_TIMESTAMP("mtp init");
|
SCOPED_TIMESTAMP("mtp init");
|
||||||
haze::Init();
|
libhaze::Init();
|
||||||
}
|
}
|
||||||
#endif // ENABLE_LIBHAZE
|
#endif // ENABLE_LIBHAZE
|
||||||
|
|
||||||
@@ -2336,7 +2336,7 @@ App::~App() {
|
|||||||
#ifdef ENABLE_LIBHAZE
|
#ifdef ENABLE_LIBHAZE
|
||||||
{
|
{
|
||||||
SCOPED_TIMESTAMP("mtp exit");
|
SCOPED_TIMESTAMP("mtp exit");
|
||||||
haze::Exit();
|
libhaze::Exit();
|
||||||
}
|
}
|
||||||
#endif // ENABLE_LIBHAZE
|
#endif // ENABLE_LIBHAZE
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <haze.h>
|
#include <haze.h>
|
||||||
|
|
||||||
namespace sphaira::haze {
|
namespace sphaira::libhaze {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct InstallSharedData {
|
struct InstallSharedData {
|
||||||
@@ -56,7 +56,7 @@ void on_thing() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FsProxyBase : ::haze::FileSystemProxyImpl {
|
struct FsProxyBase : haze::FileSystemProxyImpl {
|
||||||
FsProxyBase(const char* name, const char* display_name) : m_name{name}, m_display_name{display_name} {
|
FsProxyBase(const char* name, const char* display_name) : m_name{name}, m_display_name{display_name} {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -65,8 +65,13 @@ struct FsProxyBase : ::haze::FileSystemProxyImpl {
|
|||||||
fs::FsPath buf;
|
fs::FsPath buf;
|
||||||
const auto len = std::strlen(GetName());
|
const auto len = std::strlen(GetName());
|
||||||
|
|
||||||
if (len && !strncasecmp(path + 1, GetName(), len)) {
|
// if (!base || !base[0]) {
|
||||||
std::snprintf(buf, sizeof(buf), "%s/%s", base, path + 1 + len);
|
// std::strcpy(buf, path);
|
||||||
|
// return buf;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (len && !strncasecmp(path, GetName(), len)) {
|
||||||
|
std::snprintf(buf, sizeof(buf), "%s/%s", base, path + len);
|
||||||
} else {
|
} else {
|
||||||
std::snprintf(buf, sizeof(buf), "%s/%s", base, path);
|
std::snprintf(buf, sizeof(buf), "%s/%s", base, path);
|
||||||
// std::strcpy(buf, path);
|
// std::strcpy(buf, path);
|
||||||
@@ -89,6 +94,10 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct FsProxy final : FsProxyBase {
|
struct FsProxy final : FsProxyBase {
|
||||||
|
using File = fs::File;
|
||||||
|
using Dir = fs::Dir;
|
||||||
|
using DirEntry = FsDirectoryEntry;
|
||||||
|
|
||||||
FsProxy(std::unique_ptr<fs::Fs>&& fs, const char* name, const char* display_name)
|
FsProxy(std::unique_ptr<fs::Fs>&& fs, const char* name, const char* display_name)
|
||||||
: FsProxyBase{name, display_name}
|
: FsProxyBase{name, display_name}
|
||||||
, m_fs{std::forward<decltype(fs)>(fs)} {
|
, m_fs{std::forward<decltype(fs)>(fs)} {
|
||||||
@@ -111,131 +120,173 @@ struct FsProxy final : FsProxyBase {
|
|||||||
auto fs = (fs::FsNative*)m_fs.get();
|
auto fs = (fs::FsNative*)m_fs.get();
|
||||||
return fsFsGetTotalSpace(&fs->m_fs, FixPath(path), out);
|
return fsFsGetTotalSpace(&fs->m_fs, FixPath(path), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: use statvfs.
|
||||||
|
// then fallback to 256gb if not available.
|
||||||
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetFreeSpace(const char *path, s64 *out) override {
|
Result GetFreeSpace(const char *path, s64 *out) override {
|
||||||
if (m_fs->IsNative()) {
|
if (m_fs->IsNative()) {
|
||||||
auto fs = (fs::FsNative*)m_fs.get();
|
auto fs = (fs::FsNative*)m_fs.get();
|
||||||
return fsFsGetFreeSpace(&fs->m_fs, FixPath(path), out);
|
return fsFsGetFreeSpace(&fs->m_fs, FixPath(path), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: use statvfs.
|
||||||
|
// then fallback to 256gb if not available.
|
||||||
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result GetEntryType(const char *path, FsDirEntryType *out_entry_type) override {
|
|
||||||
const auto rc = m_fs->GetEntryType(FixPath(path), out_entry_type);
|
Result GetEntryType(const char *path, haze::FileAttrType *out_entry_type) override {
|
||||||
log_write("[HAZE] GetEntryType(%s) 0x%X\n", path, rc);
|
FsDirEntryType type;
|
||||||
return rc;
|
R_TRY(m_fs->GetEntryType(FixPath(path), &type));
|
||||||
|
*out_entry_type = (type == FsDirEntryType_Dir) ? haze::FileAttrType_DIR : haze::FileAttrType_FILE;
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result CreateFile(const char* path, s64 size, u32 option) override {
|
|
||||||
|
Result GetEntryAttributes(const char *path, haze::FileAttr *out) override {
|
||||||
|
FsDirEntryType type;
|
||||||
|
R_TRY(m_fs->GetEntryType(FixPath(path), &type));
|
||||||
|
|
||||||
|
if (type == FsDirEntryType_File) {
|
||||||
|
out->type = haze::FileAttrType_FILE;
|
||||||
|
|
||||||
|
// it doesn't matter if this fails.
|
||||||
|
s64 size{};
|
||||||
|
FsTimeStampRaw timestamp{};
|
||||||
|
R_TRY(m_fs->FileGetSizeAndTimestamp(FixPath(path), ×tamp, &size));
|
||||||
|
|
||||||
|
out->size = size;
|
||||||
|
if (timestamp.is_valid) {
|
||||||
|
out->ctime = timestamp.created;
|
||||||
|
out->mtime = timestamp.modified;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out->type = haze::FileAttrType_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsReadOnly()) {
|
||||||
|
out->flag |= haze::FileAttrFlag_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CreateFile(const char* path, s64 size) override {
|
||||||
log_write("[HAZE] CreateFile(%s)\n", path);
|
log_write("[HAZE] CreateFile(%s)\n", path);
|
||||||
return m_fs->CreateFile(FixPath(path), size, option);
|
return m_fs->CreateFile(FixPath(path), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeleteFile(const char* path) override {
|
Result DeleteFile(const char* path) override {
|
||||||
log_write("[HAZE] DeleteFile(%s)\n", path);
|
log_write("[HAZE] DeleteFile(%s)\n", path);
|
||||||
return m_fs->DeleteFile(FixPath(path));
|
return m_fs->DeleteFile(FixPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result RenameFile(const char *old_path, const char *new_path) override {
|
Result RenameFile(const char *old_path, const char *new_path) override {
|
||||||
log_write("[HAZE] RenameFile(%s -> %s)\n", old_path, new_path);
|
log_write("[HAZE] RenameFile(%s -> %s)\n", old_path, new_path);
|
||||||
return m_fs->RenameFile(FixPath(old_path), FixPath(new_path));
|
return m_fs->RenameFile(FixPath(old_path), FixPath(new_path));
|
||||||
}
|
}
|
||||||
Result OpenFile(const char *path, u32 mode, FsFile *out_file) override {
|
|
||||||
log_write("[HAZE] OpenFile(%s)\n", path);
|
|
||||||
auto fptr = new fs::File();
|
|
||||||
const auto rc = m_fs->OpenFile(FixPath(path), mode, fptr);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
Result OpenFile(const char *path, haze::FileOpenMode mode, haze::File *out_file) override {
|
||||||
std::memcpy(&out_file->s, &fptr, sizeof(fptr));
|
log_write("[HAZE] OpenFile(%s)\n", path);
|
||||||
} else {
|
|
||||||
delete fptr;
|
u32 flags = FsOpenMode_Read;
|
||||||
|
if (mode == haze::FileOpenMode_WRITE) {
|
||||||
|
flags = FsOpenMode_Write | FsOpenMode_Append;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
auto f = new File();
|
||||||
|
const auto rc = m_fs->OpenFile(FixPath(path), flags, f);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
log_write("[HAZE] OpenFile(%s) failed: 0x%X\n", path, rc);
|
||||||
|
delete f;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
out_file->impl = f;
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result GetFileSize(FsFile *file, s64 *out_size) override {
|
|
||||||
log_write("[HAZE] GetFileSize()\n");
|
Result GetFileSize(haze::File *file, s64 *out_size) override {
|
||||||
fs::File* f;
|
auto f = static_cast<File*>(file->impl);
|
||||||
std::memcpy(&f, &file->s, sizeof(f));
|
|
||||||
return f->GetSize(out_size);
|
return f->GetSize(out_size);
|
||||||
}
|
}
|
||||||
Result SetFileSize(FsFile *file, s64 size) override {
|
|
||||||
log_write("[HAZE] SetFileSize(%zd)\n", size);
|
Result SetFileSize(haze::File *file, s64 size) override {
|
||||||
fs::File* f;
|
auto f = static_cast<File*>(file->impl);
|
||||||
std::memcpy(&f, &file->s, sizeof(f));
|
|
||||||
return f->SetSize(size);
|
return f->SetSize(size);
|
||||||
}
|
}
|
||||||
Result ReadFile(FsFile *file, s64 off, void *buf, u64 read_size, u32 option, u64 *out_bytes_read) override {
|
|
||||||
log_write("[HAZE] ReadFile(%zd, %zu)\n", off, read_size);
|
Result ReadFile(haze::File *file, s64 off, void *buf, u64 read_size, u64 *out_bytes_read) override {
|
||||||
fs::File* f;
|
auto f = static_cast<File*>(file->impl);
|
||||||
std::memcpy(&f, &file->s, sizeof(f));
|
return f->Read(off, buf, read_size, FsReadOption_None, out_bytes_read);
|
||||||
return f->Read(off, buf, read_size, option, out_bytes_read);
|
|
||||||
}
|
}
|
||||||
Result WriteFile(FsFile *file, s64 off, const void *buf, u64 write_size, u32 option) override {
|
|
||||||
log_write("[HAZE] WriteFile(%zd, %zu)\n", off, write_size);
|
Result WriteFile(haze::File *file, s64 off, const void *buf, u64 write_size) override {
|
||||||
fs::File* f;
|
auto f = static_cast<File*>(file->impl);
|
||||||
std::memcpy(&f, &file->s, sizeof(f));
|
return f->Write(off, buf, write_size, FsWriteOption_None);
|
||||||
return f->Write(off, buf, write_size, option);
|
|
||||||
}
|
}
|
||||||
void CloseFile(FsFile *file) override {
|
|
||||||
log_write("[HAZE] CloseFile()\n");
|
void CloseFile(haze::File *file) override {
|
||||||
fs::File* f;
|
auto f = static_cast<File*>(file->impl);
|
||||||
std::memcpy(&f, &file->s, sizeof(f));
|
|
||||||
if (f) {
|
if (f) {
|
||||||
delete f;
|
delete f;
|
||||||
|
file->impl = nullptr;
|
||||||
}
|
}
|
||||||
std::memset(file, 0, sizeof(*file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CreateDirectory(const char* path) override {
|
Result CreateDirectory(const char* path) override {
|
||||||
log_write("[HAZE] DeleteFile(%s)\n", path);
|
|
||||||
return m_fs->CreateDirectory(FixPath(path));
|
return m_fs->CreateDirectory(FixPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeleteDirectoryRecursively(const char* path) override {
|
Result DeleteDirectoryRecursively(const char* path) override {
|
||||||
log_write("[HAZE] DeleteDirectoryRecursively(%s)\n", path);
|
|
||||||
return m_fs->DeleteDirectoryRecursively(FixPath(path));
|
return m_fs->DeleteDirectoryRecursively(FixPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result RenameDirectory(const char *old_path, const char *new_path) override {
|
Result RenameDirectory(const char *old_path, const char *new_path) override {
|
||||||
log_write("[HAZE] RenameDirectory(%s -> %s)\n", old_path, new_path);
|
|
||||||
return m_fs->RenameDirectory(FixPath(old_path), FixPath(new_path));
|
return m_fs->RenameDirectory(FixPath(old_path), FixPath(new_path));
|
||||||
}
|
}
|
||||||
Result OpenDirectory(const char *path, u32 mode, FsDir *out_dir) override {
|
|
||||||
auto fptr = new fs::Dir();
|
|
||||||
const auto rc = m_fs->OpenDirectory(FixPath(path), mode, fptr);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
Result OpenDirectory(const char *path, haze::Dir *out_dir) override {
|
||||||
std::memcpy(&out_dir->s, &fptr, sizeof(fptr));
|
auto dir = new Dir();
|
||||||
} else {
|
const auto rc = m_fs->OpenDirectory(FixPath(path), FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles | FsDirOpenMode_NoFileSize, dir);
|
||||||
delete fptr;
|
if (R_FAILED(rc)) {
|
||||||
|
log_write("[HAZE] OpenDirectory(%s) failed: 0x%X\n", path, rc);
|
||||||
|
delete dir;
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_write("[HAZE] OpenDirectory(%s) 0x%X\n", path, rc);
|
out_dir->impl = dir;
|
||||||
return rc;
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result ReadDirectory(FsDir *d, s64 *out_total_entries, size_t max_entries, FsDirectoryEntry *buf) override {
|
|
||||||
fs::Dir* f;
|
Result ReadDirectory(haze::Dir *d, s64 *out_total_entries, size_t max_entries, haze::DirEntry *buf) override {
|
||||||
std::memcpy(&f, &d->s, sizeof(f));
|
auto dir = static_cast<Dir*>(d->impl);
|
||||||
const auto rc = f->Read(out_total_entries, max_entries, buf);
|
|
||||||
log_write("[HAZE] ReadDirectory(%zd) 0x%X\n", *out_total_entries, rc);
|
std::vector<FsDirectoryEntry> entries(max_entries);
|
||||||
return rc;
|
R_TRY(dir->Read(out_total_entries, entries.size(), entries.data()));
|
||||||
}
|
|
||||||
Result GetDirectoryEntryCount(FsDir *d, s64 *out_count) override {
|
for (s64 i = 0; i < *out_total_entries; i++) {
|
||||||
fs::Dir* f;
|
std::strcpy(buf[i].name, entries[i].name);
|
||||||
std::memcpy(&f, &d->s, sizeof(f));
|
|
||||||
const auto rc = f->GetEntryCount(out_count);
|
|
||||||
log_write("[HAZE] GetDirectoryEntryCount(%zd) 0x%X\n", *out_count, rc);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
void CloseDirectory(FsDir *d) override {
|
|
||||||
log_write("[HAZE] CloseDirectory()\n");
|
|
||||||
fs::Dir* f;
|
|
||||||
std::memcpy(&f, &d->s, sizeof(f));
|
|
||||||
if (f) {
|
|
||||||
delete f;
|
|
||||||
}
|
}
|
||||||
std::memset(d, 0, sizeof(*d));
|
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
virtual bool MultiThreadTransfer(s64 size, bool read) override {
|
|
||||||
return !App::IsFileBaseEmummc();
|
Result GetDirectoryEntryCount(haze::Dir *d, s64 *out_count) override {
|
||||||
|
auto dir = static_cast<Dir*>(d->impl);
|
||||||
|
return dir->GetEntryCount(out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseDirectory(haze::Dir *d) override {
|
||||||
|
auto dir = static_cast<Dir*>(d->impl);
|
||||||
|
if (dir) {
|
||||||
|
delete dir;
|
||||||
|
d->impl = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -245,6 +296,15 @@ private:
|
|||||||
// fake fs that allows for files to create r/w on the root.
|
// fake fs that allows for files to create r/w on the root.
|
||||||
// folders are not yet supported.
|
// folders are not yet supported.
|
||||||
struct FsProxyVfs : FsProxyBase {
|
struct FsProxyVfs : FsProxyBase {
|
||||||
|
struct File {
|
||||||
|
u64 index{};
|
||||||
|
haze::FileOpenMode mode{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dir {
|
||||||
|
u64 pos{};
|
||||||
|
};
|
||||||
|
|
||||||
using FsProxyBase::FsProxyBase;
|
using FsProxyBase::FsProxyBase;
|
||||||
virtual ~FsProxyVfs() = default;
|
virtual ~FsProxyVfs() = default;
|
||||||
|
|
||||||
@@ -260,9 +320,9 @@ struct FsProxyVfs : FsProxyBase {
|
|||||||
return file_name + 1;
|
return file_name + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result GetEntryType(const char *path, FsDirEntryType *out_entry_type) {
|
virtual Result GetEntryType(const char *path, haze::FileAttrType *out_entry_type) {
|
||||||
if (FixPath(path) == "/") {
|
if (FixPath(path) == "/") {
|
||||||
*out_entry_type = FsDirEntryType_Dir;
|
*out_entry_type = haze::FileAttrType_DIR;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
} else {
|
} else {
|
||||||
const auto file_name = GetFileName(path);
|
const auto file_name = GetFileName(path);
|
||||||
@@ -273,11 +333,12 @@ struct FsProxyVfs : FsProxyBase {
|
|||||||
});
|
});
|
||||||
R_UNLESS(it != m_entries.end(), FsError_PathNotFound);
|
R_UNLESS(it != m_entries.end(), FsError_PathNotFound);
|
||||||
|
|
||||||
*out_entry_type = FsDirEntryType_File;
|
*out_entry_type = haze::FileAttrType_FILE;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual Result CreateFile(const char* path, s64 size, u32 option) {
|
|
||||||
|
virtual Result CreateFile(const char* path, s64 size) {
|
||||||
const auto file_name = GetFileName(path);
|
const auto file_name = GetFileName(path);
|
||||||
R_UNLESS(file_name, FsError_PathNotFound);
|
R_UNLESS(file_name, FsError_PathNotFound);
|
||||||
|
|
||||||
@@ -294,6 +355,7 @@ struct FsProxyVfs : FsProxyBase {
|
|||||||
m_entries.emplace_back(entry);
|
m_entries.emplace_back(entry);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result DeleteFile(const char* path) {
|
virtual Result DeleteFile(const char* path) {
|
||||||
const auto file_name = GetFileName(path);
|
const auto file_name = GetFileName(path);
|
||||||
R_UNLESS(file_name, FsError_PathNotFound);
|
R_UNLESS(file_name, FsError_PathNotFound);
|
||||||
@@ -306,6 +368,7 @@ struct FsProxyVfs : FsProxyBase {
|
|||||||
m_entries.erase(it);
|
m_entries.erase(it);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RenameFile(const char *old_path, const char *new_path) {
|
virtual Result RenameFile(const char *old_path, const char *new_path) {
|
||||||
const auto file_name = GetFileName(old_path);
|
const auto file_name = GetFileName(old_path);
|
||||||
R_UNLESS(file_name, FsError_PathNotFound);
|
R_UNLESS(file_name, FsError_PathNotFound);
|
||||||
@@ -326,7 +389,8 @@ struct FsProxyVfs : FsProxyBase {
|
|||||||
std::strcpy(it->name, file_name_new);
|
std::strcpy(it->name, file_name_new);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
virtual Result OpenFile(const char *path, u32 mode, FsFile *out_file) {
|
|
||||||
|
virtual Result OpenFile(const char *path, haze::FileOpenMode mode, haze::File *out_file) {
|
||||||
const auto file_name = GetFileName(path);
|
const auto file_name = GetFileName(path);
|
||||||
R_UNLESS(file_name, FsError_PathNotFound);
|
R_UNLESS(file_name, FsError_PathNotFound);
|
||||||
|
|
||||||
@@ -335,65 +399,89 @@ struct FsProxyVfs : FsProxyBase {
|
|||||||
});
|
});
|
||||||
R_UNLESS(it != m_entries.end(), FsError_PathNotFound);
|
R_UNLESS(it != m_entries.end(), FsError_PathNotFound);
|
||||||
|
|
||||||
out_file->s.object_id = std::distance(m_entries.begin(), it);
|
auto f = new File();
|
||||||
out_file->s.own_handle = mode;
|
f->index = std::distance(m_entries.begin(), it);
|
||||||
|
f->mode = mode;
|
||||||
|
out_file->impl = f;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
virtual Result GetFileSize(FsFile *file, s64 *out_size) {
|
|
||||||
auto& e = m_entries[file->s.object_id];
|
virtual Result GetFileSize(haze::File *file, s64 *out_size) {
|
||||||
*out_size = e.file_size;
|
auto f = static_cast<File*>(file->impl);
|
||||||
|
*out_size = m_entries[f->index].file_size;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
virtual Result SetFileSize(FsFile *file, s64 size) {
|
|
||||||
auto& e = m_entries[file->s.object_id];
|
virtual Result SetFileSize(haze::File *file, s64 size) {
|
||||||
e.file_size = size;
|
auto f = static_cast<File*>(file->impl);
|
||||||
|
m_entries[f->index].file_size = size;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
virtual Result ReadFile(FsFile *file, s64 off, void *buf, u64 read_size, u32 option, u64 *out_bytes_read) {
|
|
||||||
|
virtual Result ReadFile(haze::File *file, s64 off, void *buf, u64 read_size, u64 *out_bytes_read) {
|
||||||
// stub for now as it may confuse users who think that the returned file is valid.
|
// stub for now as it may confuse users who think that the returned file is valid.
|
||||||
// the code below can be used to benchmark mtp reads.
|
// the code below can be used to benchmark mtp reads.
|
||||||
R_THROW(FsError_NotImplemented);
|
R_THROW(FsError_NotImplemented);
|
||||||
// auto& e = m_entries[file->s.object_id];
|
|
||||||
// read_size = std::min<s64>(e.file_size - off, read_size);
|
|
||||||
// std::memset(buf, 0, read_size);
|
|
||||||
// *out_bytes_read = read_size;
|
|
||||||
// R_SUCCEED();
|
|
||||||
}
|
}
|
||||||
virtual Result WriteFile(FsFile *file, s64 off, const void *buf, u64 write_size, u32 option) {
|
|
||||||
auto& e = m_entries[file->s.object_id];
|
virtual Result WriteFile(haze::File *file, s64 off, const void *buf, u64 write_size) {
|
||||||
|
auto f = static_cast<File*>(file->impl);
|
||||||
|
auto& e = m_entries[f->index];
|
||||||
e.file_size = std::max<s64>(e.file_size, off + write_size);
|
e.file_size = std::max<s64>(e.file_size, off + write_size);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
virtual void CloseFile(FsFile *file) {
|
|
||||||
std::memset(file, 0, sizeof(*file));
|
virtual void CloseFile(haze::File *file) {
|
||||||
|
auto f = static_cast<File*>(file->impl);
|
||||||
|
if (f) {
|
||||||
|
delete f;
|
||||||
|
file->impl = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CreateDirectory(const char* path) override {
|
Result CreateDirectory(const char* path) override {
|
||||||
R_THROW(FsError_NotImplemented);
|
R_THROW(FsError_NotImplemented);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeleteDirectoryRecursively(const char* path) override {
|
Result DeleteDirectoryRecursively(const char* path) override {
|
||||||
R_THROW(FsError_NotImplemented);
|
R_THROW(FsError_NotImplemented);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result RenameDirectory(const char *old_path, const char *new_path) override {
|
Result RenameDirectory(const char *old_path, const char *new_path) override {
|
||||||
R_THROW(FsError_NotImplemented);
|
R_THROW(FsError_NotImplemented);
|
||||||
}
|
}
|
||||||
Result OpenDirectory(const char *path, u32 mode, FsDir *out_dir) override {
|
|
||||||
std::memset(out_dir, 0, sizeof(*out_dir));
|
Result OpenDirectory(const char *path, haze::Dir *out_dir) override {
|
||||||
|
auto dir = new Dir();
|
||||||
|
out_dir->impl = dir;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result ReadDirectory(FsDir *d, s64 *out_total_entries, size_t max_entries, FsDirectoryEntry *buf) override {
|
|
||||||
max_entries = std::min<s64>(m_entries.size()- d->s.object_id, max_entries);
|
Result ReadDirectory(haze::Dir *d, s64 *out_total_entries, size_t max_entries, haze::DirEntry *buf) override {
|
||||||
std::memcpy(buf, m_entries.data() + d->s.object_id, max_entries * sizeof(*buf));
|
auto dir = static_cast<Dir*>(d->impl);
|
||||||
d->s.object_id += max_entries;
|
|
||||||
|
max_entries = std::min<s64>(m_entries.size() - dir->pos, max_entries);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < max_entries; i++) {
|
||||||
|
std::strcpy(buf[i].name, m_entries[dir->pos + i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
dir->pos += max_entries;
|
||||||
*out_total_entries = max_entries;
|
*out_total_entries = max_entries;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result GetDirectoryEntryCount(FsDir *d, s64 *out_count) override {
|
|
||||||
|
Result GetDirectoryEntryCount(haze::Dir *d, s64 *out_count) override {
|
||||||
*out_count = m_entries.size();
|
*out_count = m_entries.size();
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
void CloseDirectory(FsDir *d) override {
|
|
||||||
std::memset(d, 0, sizeof(*d));
|
void CloseDirectory(haze::Dir *d) override {
|
||||||
|
auto dir = static_cast<Dir*>(d->impl);
|
||||||
|
if (dir) {
|
||||||
|
delete dir;
|
||||||
|
d->impl = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -407,13 +495,11 @@ struct FsDevNullProxy final : FsProxyVfs {
|
|||||||
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetFreeSpace(const char *path, s64 *out) override {
|
Result GetFreeSpace(const char *path, s64 *out) override {
|
||||||
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
*out = 1024ULL * 1024ULL * 1024ULL * 256ULL;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
bool MultiThreadTransfer(s64 size, bool read) override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FsInstallProxy final : FsProxyVfs {
|
struct FsInstallProxy final : FsProxyVfs {
|
||||||
@@ -456,6 +542,7 @@ struct FsInstallProxy final : FsProxyVfs {
|
|||||||
return fs::FsNativeContentStorage(FsContentStorageId_User).GetTotalSpace("/", out);
|
return fs::FsNativeContentStorage(FsContentStorageId_User).GetTotalSpace("/", out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetFreeSpace(const char *path, s64 *out) override {
|
Result GetFreeSpace(const char *path, s64 *out) override {
|
||||||
if (App::GetApp()->m_install_sd.Get()) {
|
if (App::GetApp()->m_install_sd.Get()) {
|
||||||
return fs::FsNativeContentStorage(FsContentStorageId_SdCard).GetFreeSpace("/", out);
|
return fs::FsNativeContentStorage(FsContentStorageId_SdCard).GetFreeSpace("/", out);
|
||||||
@@ -464,27 +551,30 @@ struct FsInstallProxy final : FsProxyVfs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetEntryType(const char *path, FsDirEntryType *out_entry_type) override {
|
Result GetEntryType(const char *path, haze::FileAttrType *out_entry_type) override {
|
||||||
R_TRY(FsProxyVfs::GetEntryType(path, out_entry_type));
|
R_TRY(FsProxyVfs::GetEntryType(path, out_entry_type));
|
||||||
if (*out_entry_type == FsDirEntryType_File) {
|
if (*out_entry_type == haze::FileAttrType_FILE) {
|
||||||
R_TRY(FailedIfNotEnabled());
|
R_TRY(FailedIfNotEnabled());
|
||||||
}
|
}
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result CreateFile(const char* path, s64 size, u32 option) override {
|
|
||||||
|
Result CreateFile(const char* path, s64 size) override {
|
||||||
R_TRY(FailedIfNotEnabled());
|
R_TRY(FailedIfNotEnabled());
|
||||||
R_TRY(IsValidFileType(path));
|
R_TRY(IsValidFileType(path));
|
||||||
R_TRY(FsProxyVfs::CreateFile(path, size, option));
|
R_TRY(FsProxyVfs::CreateFile(path, size));
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result OpenFile(const char *path, u32 mode, FsFile *out_file) override {
|
|
||||||
|
Result OpenFile(const char *path, haze::FileOpenMode mode, haze::File *out_file) override {
|
||||||
R_TRY(FailedIfNotEnabled());
|
R_TRY(FailedIfNotEnabled());
|
||||||
R_TRY(IsValidFileType(path));
|
R_TRY(IsValidFileType(path));
|
||||||
R_TRY(FsProxyVfs::OpenFile(path, mode, out_file));
|
R_TRY(FsProxyVfs::OpenFile(path, mode, out_file));
|
||||||
log_write("[MTP] done file open: %s mode: 0x%X\n", path, mode);
|
log_write("[MTP] done file open: %s mode: 0x%X\n", path, mode);
|
||||||
|
|
||||||
if (mode & FsOpenMode_Write) {
|
if (mode == haze::FileOpenMode_WRITE) {
|
||||||
const auto& e = m_entries[out_file->s.object_id];
|
auto f = static_cast<File*>(out_file->impl);
|
||||||
|
const auto& e = m_entries[f->index];
|
||||||
|
|
||||||
// check if we already have this file queued.
|
// check if we already have this file queued.
|
||||||
log_write("[MTP] checking if empty\n");
|
log_write("[MTP] checking if empty\n");
|
||||||
@@ -497,7 +587,8 @@ struct FsInstallProxy final : FsProxyVfs {
|
|||||||
log_write("[MTP] got file: %s\n", path);
|
log_write("[MTP] got file: %s\n", path);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
Result WriteFile(FsFile *file, s64 off, const void *buf, u64 write_size, u32 option) override {
|
|
||||||
|
Result WriteFile(haze::File *file, s64 off, const void *buf, u64 write_size) override {
|
||||||
SCOPED_MUTEX(&g_shared_data.mutex);
|
SCOPED_MUTEX(&g_shared_data.mutex);
|
||||||
if (!g_shared_data.enabled) {
|
if (!g_shared_data.enabled) {
|
||||||
log_write("[MTP] failing as not enabled\n");
|
log_write("[MTP] failing as not enabled\n");
|
||||||
@@ -509,14 +600,20 @@ struct FsInstallProxy final : FsProxyVfs {
|
|||||||
R_THROW(FsError_NotImplemented);
|
R_THROW(FsError_NotImplemented);
|
||||||
}
|
}
|
||||||
|
|
||||||
R_TRY(FsProxyVfs::WriteFile(file, off, buf, write_size, option));
|
R_TRY(FsProxyVfs::WriteFile(file, off, buf, write_size));
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
void CloseFile(FsFile *file) override {
|
|
||||||
|
void CloseFile(haze::File *file) override {
|
||||||
|
auto f = static_cast<File*>(file->impl);
|
||||||
|
if (!f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool update{};
|
bool update{};
|
||||||
{
|
{
|
||||||
SCOPED_MUTEX(&g_shared_data.mutex);
|
SCOPED_MUTEX(&g_shared_data.mutex);
|
||||||
if (file->s.own_handle & FsOpenMode_Write) {
|
if (f->mode == haze::FileOpenMode_WRITE) {
|
||||||
log_write("[MTP] closing current file\n");
|
log_write("[MTP] closing current file\n");
|
||||||
if (g_shared_data.on_close) {
|
if (g_shared_data.on_close) {
|
||||||
g_shared_data.on_close();
|
g_shared_data.on_close();
|
||||||
@@ -534,40 +631,36 @@ struct FsInstallProxy final : FsProxyVfs {
|
|||||||
|
|
||||||
FsProxyVfs::CloseFile(file);
|
FsProxyVfs::CloseFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
// installs are already multi-threaded via yati.
|
|
||||||
bool MultiThreadTransfer(s64 size, bool read) override {
|
|
||||||
App::IsFileBaseEmummc();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
::haze::FsEntries g_fs_entries{};
|
haze::FsEntries g_fs_entries{};
|
||||||
|
|
||||||
void haze_callback(const ::haze::CallbackData *data) {
|
void haze_callback(const haze::CallbackData *data) {
|
||||||
auto& e = *data;
|
auto& e = *data;
|
||||||
|
|
||||||
|
#if 0
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case ::haze::CallbackType_OpenSession: log_write("[LIBHAZE] Opening Session\n"); break;
|
case haze::CallbackType_OpenSession: log_write("[LIBHAZE] Opening Session\n"); break;
|
||||||
case ::haze::CallbackType_CloseSession: log_write("[LIBHAZE] Closing Session\n"); break;
|
case haze::CallbackType_CloseSession: log_write("[LIBHAZE] Closing Session\n"); break;
|
||||||
|
|
||||||
case ::haze::CallbackType_CreateFile: log_write("[LIBHAZE] Creating File: %s\n", e.file.filename); break;
|
case haze::CallbackType_CreateFile: log_write("[LIBHAZE] Creating File: %s\n", e.file.filename); break;
|
||||||
case ::haze::CallbackType_DeleteFile: log_write("[LIBHAZE] Deleting File: %s\n", e.file.filename); break;
|
case haze::CallbackType_DeleteFile: log_write("[LIBHAZE] Deleting File: %s\n", e.file.filename); break;
|
||||||
|
|
||||||
case ::haze::CallbackType_RenameFile: log_write("[LIBHAZE] Rename File: %s -> %s\n", e.rename.filename, e.rename.newname); break;
|
case haze::CallbackType_RenameFile: log_write("[LIBHAZE] Rename File: %s -> %s\n", e.rename.filename, e.rename.newname); break;
|
||||||
case ::haze::CallbackType_RenameFolder: log_write("[LIBHAZE] Rename Folder: %s -> %s\n", e.rename.filename, e.rename.newname); break;
|
case haze::CallbackType_RenameFolder: log_write("[LIBHAZE] Rename Folder: %s -> %s\n", e.rename.filename, e.rename.newname); break;
|
||||||
|
|
||||||
case ::haze::CallbackType_CreateFolder: log_write("[LIBHAZE] Creating Folder: %s\n", e.file.filename); break;
|
case haze::CallbackType_CreateFolder: log_write("[LIBHAZE] Creating Folder: %s\n", e.file.filename); break;
|
||||||
case ::haze::CallbackType_DeleteFolder: log_write("[LIBHAZE] Deleting Folder: %s\n", e.file.filename); break;
|
case haze::CallbackType_DeleteFolder: log_write("[LIBHAZE] Deleting Folder: %s\n", e.file.filename); break;
|
||||||
|
|
||||||
case ::haze::CallbackType_ReadBegin: log_write("[LIBHAZE] Reading File Begin: %s \n", e.file.filename); break;
|
case haze::CallbackType_ReadBegin: log_write("[LIBHAZE] Reading File Begin: %s \n", e.file.filename); break;
|
||||||
case ::haze::CallbackType_ReadProgress: log_write("\t[LIBHAZE] Reading File: offset: %lld size: %lld\n", e.progress.offset, e.progress.size); break;
|
case haze::CallbackType_ReadProgress: log_write("\t[LIBHAZE] Reading File: offset: %lld size: %lld\n", e.progress.offset, e.progress.size); break;
|
||||||
case ::haze::CallbackType_ReadEnd: log_write("[LIBHAZE] Reading File Finished: %s\n", e.file.filename); break;
|
case haze::CallbackType_ReadEnd: log_write("[LIBHAZE] Reading File Finished: %s\n", e.file.filename); break;
|
||||||
|
|
||||||
case ::haze::CallbackType_WriteBegin: log_write("[LIBHAZE] Writing File Begin: %s \n", e.file.filename); break;
|
case haze::CallbackType_WriteBegin: log_write("[LIBHAZE] Writing File Begin: %s \n", e.file.filename); break;
|
||||||
case ::haze::CallbackType_WriteProgress: log_write("\t[LIBHAZE] Writing File: offset: %lld size: %lld\n", e.progress.offset, e.progress.size); break;
|
case haze::CallbackType_WriteProgress: log_write("\t[LIBHAZE] Writing File: offset: %lld size: %lld\n", e.progress.offset, e.progress.size); break;
|
||||||
case ::haze::CallbackType_WriteEnd: log_write("[LIBHAZE] Writing File Finished: %s\n", e.file.filename); break;
|
case haze::CallbackType_WriteEnd: log_write("[LIBHAZE] Writing File Finished: %s\n", e.file.filename); break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
App::NotifyFlashLed();
|
App::NotifyFlashLed();
|
||||||
}
|
}
|
||||||
@@ -588,7 +681,7 @@ bool Init() {
|
|||||||
g_fs_entries.emplace_back(std::make_shared<FsInstallProxy>("install", "Install (NSP, XCI, NSZ, XCZ)"));
|
g_fs_entries.emplace_back(std::make_shared<FsInstallProxy>("install", "Install (NSP, XCI, NSZ, XCZ)"));
|
||||||
|
|
||||||
g_should_exit = false;
|
g_should_exit = false;
|
||||||
if (!::haze::Initialize(haze_callback, THREAD_PRIO, THREAD_CORE, g_fs_entries, App::GetApp()->m_mtp_vid.Get(), App::GetApp()->m_mtp_pid.Get())) {
|
if (!haze::Initialize(haze_callback, g_fs_entries, App::GetApp()->m_mtp_vid.Get(), App::GetApp()->m_mtp_pid.Get())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,7 +700,7 @@ void Exit() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
::haze::Exit();
|
haze::Exit();
|
||||||
g_is_running = false;
|
g_is_running = false;
|
||||||
g_should_exit = true;
|
g_should_exit = true;
|
||||||
g_fs_entries.clear();
|
g_fs_entries.clear();
|
||||||
@@ -628,4 +721,4 @@ void DisableInstallMode() {
|
|||||||
g_shared_data.enabled = false;
|
g_shared_data.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sphaira::haze
|
} // namespace sphaira::libhaze
|
||||||
|
|||||||
@@ -16,34 +16,26 @@ enum class InstallState {
|
|||||||
Finished,
|
Finished,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u64 MAX_BUFFER_SIZE = 1024ULL*1024ULL*8ULL;
|
constexpr u64 MAX_BUFFER_SIZE = 1024ULL*1024ULL*1ULL;
|
||||||
constexpr u64 MAX_BUFFER_RESERVE_SIZE = 1024ULL*1024ULL*32ULL;
|
|
||||||
std::atomic<InstallState> INSTALL_STATE{InstallState::None};
|
std::atomic<InstallState> INSTALL_STATE{InstallState::None};
|
||||||
|
|
||||||
// don't use condivar here as windows mtp is very broken.
|
|
||||||
// stalling for too longer (3s+) and having too varied transfer speeds
|
|
||||||
// results in windows stalling the transfer for 1m until it kills it via timeout.
|
|
||||||
// the workaround is to always accept new data, but stall for 1s.
|
|
||||||
// UPDATE: it seems possible to trigger this bug during normal file transfer
|
|
||||||
// including using stock haze.
|
|
||||||
// it seems random, and ive been unable to trigger it personally.
|
|
||||||
// for this reason, use condivar rather than trying to work around the issue.
|
|
||||||
#define USE_CONDI_VAR 1
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Stream::Stream(const fs::FsPath& path, std::stop_token token) {
|
Stream::Stream(const fs::FsPath& path, std::stop_token token) {
|
||||||
m_path = path;
|
m_path = path;
|
||||||
m_token = token;
|
m_token = token;
|
||||||
m_active = true;
|
m_active = true;
|
||||||
m_buffer.reserve(MAX_BUFFER_RESERVE_SIZE);
|
m_buffer.reserve(MAX_BUFFER_SIZE);
|
||||||
|
|
||||||
mutexInit(&m_mutex);
|
mutexInit(&m_mutex);
|
||||||
condvarInit(&m_can_read);
|
condvarInit(&m_can_read);
|
||||||
condvarInit(&m_can_write);
|
condvarInit(&m_can_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Stream::ReadChunk(void* buf, s64 size, u64* bytes_read) {
|
Result Stream::ReadChunk(void* _buf, s64 size, u64* bytes_read) {
|
||||||
|
auto buf = static_cast<u8*>(_buf);
|
||||||
|
*bytes_read = 0;
|
||||||
|
|
||||||
log_write("[Stream::ReadChunk] inside\n");
|
log_write("[Stream::ReadChunk] inside\n");
|
||||||
ON_SCOPE_EXIT(
|
ON_SCOPE_EXIT(
|
||||||
log_write("[Stream::ReadChunk] exiting\n");
|
log_write("[Stream::ReadChunk] exiting\n");
|
||||||
@@ -59,18 +51,30 @@ Result Stream::ReadChunk(void* buf, s64 size, u64* bytes_read) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = std::min<s64>(size, m_buffer.size());
|
const auto rsize = std::min<s64>(size, m_buffer.size());
|
||||||
std::memcpy(buf, m_buffer.data(), size);
|
std::memcpy(buf, m_buffer.data(), rsize);
|
||||||
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + size);
|
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + rsize);
|
||||||
*bytes_read = size;
|
condvarWakeOne(&m_can_write);
|
||||||
return condvarWakeOne(&m_can_write);
|
|
||||||
|
size -= rsize;
|
||||||
|
buf += rsize;
|
||||||
|
*bytes_read += rsize;
|
||||||
|
|
||||||
|
if (!size) {
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_write("[Stream::ReadChunk] failed to read\n");
|
log_write("[Stream::ReadChunk] failed to read\n");
|
||||||
R_THROW(Result_TransferCancelled);
|
R_THROW(Result_TransferCancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::Push(const void* buf, s64 size) {
|
bool Stream::Push(const void* _buf, s64 size) {
|
||||||
|
auto buf = static_cast<const u8*>(_buf);
|
||||||
|
if (!size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
log_write("[Stream::Push] inside\n");
|
log_write("[Stream::Push] inside\n");
|
||||||
ON_SCOPE_EXIT(
|
ON_SCOPE_EXIT(
|
||||||
log_write("[Stream::Push] exiting\n");
|
log_write("[Stream::Push] exiting\n");
|
||||||
@@ -83,31 +87,27 @@ bool Stream::Push(const void* buf, s64 size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SCOPED_MUTEX(&m_mutex);
|
SCOPED_MUTEX(&m_mutex);
|
||||||
#if USE_CONDI_VAR
|
|
||||||
if (m_active && m_buffer.size() >= MAX_BUFFER_SIZE) {
|
if (m_active && m_buffer.size() >= MAX_BUFFER_SIZE) {
|
||||||
R_TRY(condvarWait(std::addressof(m_can_write), std::addressof(m_mutex)));
|
R_TRY(condvarWait(std::addressof(m_can_write), std::addressof(m_mutex)));
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (m_active && m_buffer.size() >= MAX_BUFFER_SIZE) {
|
|
||||||
// unlock the mutex and wait for 1s to bring transfer speed down to 1MiB/s.
|
|
||||||
log_write("[Stream::Push] buffer is full, delaying\n");
|
|
||||||
mutexUnlock(&m_mutex);
|
|
||||||
ON_SCOPE_EXIT(mutexLock(&m_mutex));
|
|
||||||
|
|
||||||
svcSleepThread(1e+9);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!m_active) {
|
if (!m_active) {
|
||||||
log_write("[Stream::Push] file not active\n");
|
log_write("[Stream::Push] file not active\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto wsize = std::min<s64>(size, MAX_BUFFER_SIZE - m_buffer.size());
|
||||||
const auto offset = m_buffer.size();
|
const auto offset = m_buffer.size();
|
||||||
m_buffer.resize(offset + size);
|
m_buffer.resize(offset + wsize);
|
||||||
std::memcpy(m_buffer.data() + offset, buf, size);
|
|
||||||
|
std::memcpy(m_buffer.data() + offset, buf, wsize);
|
||||||
condvarWakeOne(&m_can_read);
|
condvarWakeOne(&m_can_read);
|
||||||
return true;
|
|
||||||
|
size -= wsize;
|
||||||
|
buf += wsize;
|
||||||
|
if (!size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_write("[Stream::Push] failed to push\n");
|
log_write("[Stream::Push] failed to push\n");
|
||||||
|
|||||||
@@ -10,13 +10,13 @@
|
|||||||
namespace sphaira::ui::menu::mtp {
|
namespace sphaira::ui::menu::mtp {
|
||||||
|
|
||||||
Menu::Menu(u32 flags) : stream::Menu{"MTP Install"_i18n, flags} {
|
Menu::Menu(u32 flags) : stream::Menu{"MTP Install"_i18n, flags} {
|
||||||
m_was_mtp_enabled = haze::IsInit();
|
m_was_mtp_enabled = libhaze::IsInit();
|
||||||
if (!m_was_mtp_enabled) {
|
if (!m_was_mtp_enabled) {
|
||||||
log_write("[MTP] wasn't enabled, forcefully enabling\n");
|
log_write("[MTP] wasn't enabled, forcefully enabling\n");
|
||||||
haze::Init();
|
libhaze::Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
haze::InitInstallMode(
|
libhaze::InitInstallMode(
|
||||||
[this](const char* path){ return OnInstallStart(path); },
|
[this](const char* path){ return OnInstallStart(path); },
|
||||||
[this](const void *buf, size_t size){ return OnInstallWrite(buf, size); },
|
[this](const void *buf, size_t size){ return OnInstallWrite(buf, size); },
|
||||||
[this](){ return OnInstallClose(); }
|
[this](){ return OnInstallClose(); }
|
||||||
@@ -25,11 +25,11 @@ Menu::Menu(u32 flags) : stream::Menu{"MTP Install"_i18n, flags} {
|
|||||||
|
|
||||||
Menu::~Menu() {
|
Menu::~Menu() {
|
||||||
// signal for thread to exit and wait.
|
// signal for thread to exit and wait.
|
||||||
haze::DisableInstallMode();
|
libhaze::DisableInstallMode();
|
||||||
|
|
||||||
if (!m_was_mtp_enabled) {
|
if (!m_was_mtp_enabled) {
|
||||||
log_write("[MTP] disabling on exit\n");
|
log_write("[MTP] disabling on exit\n");
|
||||||
haze::Exit();
|
libhaze::Exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Menu::OnDisableInstallMode() {
|
void Menu::OnDisableInstallMode() {
|
||||||
haze::DisableInstallMode();
|
libhaze::DisableInstallMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sphaira::ui::menu::mtp
|
} // namespace sphaira::ui::menu::mtp
|
||||||
|
|||||||
Reference in New Issue
Block a user