lots of changes, see description.

- enable sftp by default.
- add more descriptive stdio errors.
- disable devoptab timeout by default.
- handle errors for devoptab seek.
- add r/d/w progress events for threaded_file_transfer
- remove system album from file browser, only show sd card.
- do not clear game selection in games menu. useful for selecting games to backup, then delete after.
- change smb2 r/w to only send max amount, matches nfs behaviour. not sure if its needed as smb probably handles it for us.
This commit is contained in:
ITotalJustice
2025-09-13 13:16:18 +01:00
parent 931531e799
commit 8b2e541b1d
24 changed files with 254 additions and 122 deletions

View File

@@ -26,7 +26,7 @@ option(ENABLE_DEVOPTAB_WEBDAV "" ON)
# max speed is 8MiB/s, which is fine for wifi, but awful for ethernet. # max speed is 8MiB/s, which is fine for wifi, but awful for ethernet.
# other clients get 36-40MiB/s. # other clients get 36-40MiB/s.
# it also adds 230k to binary size, and i don't think anyone will use it. # it also adds 230k to binary size, and i don't think anyone will use it.
option(ENABLE_DEVOPTAB_SFTP "" OFF) option(ENABLE_DEVOPTAB_SFTP "" ON)
set(sphaira_VERSION 0.13.3) set(sphaira_VERSION 0.13.3)

View File

@@ -511,7 +511,22 @@ enum class SphairaResult : Result {
FsNewPathEmpty, FsNewPathEmpty,
FsLoadingCancelled, FsLoadingCancelled,
FsBrokenRoot, FsBrokenRoot,
FsUnknownStdioError, FsUnknownStdioError,
FsStdioFailedToSeek,
FsStdioFailedToRead,
FsStdioFailedToWrite,
FsStdioFailedToOpenFile,
FsStdioFailedToCreate,
FsStdioFailedToTruncate,
FsStdioFailedToFlush,
FsStdioFailedToCreateDirectory,
FsStdioFailedToDeleteFile,
FsStdioFailedToDeleteDirectory,
FsStdioFailedToOpenDirectory,
FsStdioFailedToRename,
FsStdioFailedToStat,
FsReadOnly, FsReadOnly,
FsNotActive, FsNotActive,
FsFailedStdioStat, FsFailedStdioStat,
@@ -680,6 +695,19 @@ enum : Result {
MAKE_SPHAIRA_RESULT_ENUM(FsLoadingCancelled), MAKE_SPHAIRA_RESULT_ENUM(FsLoadingCancelled),
MAKE_SPHAIRA_RESULT_ENUM(FsBrokenRoot), MAKE_SPHAIRA_RESULT_ENUM(FsBrokenRoot),
MAKE_SPHAIRA_RESULT_ENUM(FsUnknownStdioError), MAKE_SPHAIRA_RESULT_ENUM(FsUnknownStdioError),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToSeek),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToRead),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToWrite),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToOpenFile),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToCreate),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToTruncate),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToFlush),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToCreateDirectory),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToDeleteFile),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToDeleteDirectory),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToOpenDirectory),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToRename),
MAKE_SPHAIRA_RESULT_ENUM(FsStdioFailedToStat),
MAKE_SPHAIRA_RESULT_ENUM(FsReadOnly), MAKE_SPHAIRA_RESULT_ENUM(FsReadOnly),
MAKE_SPHAIRA_RESULT_ENUM(FsNotActive), MAKE_SPHAIRA_RESULT_ENUM(FsNotActive),
MAKE_SPHAIRA_RESULT_ENUM(FsFailedStdioStat), MAKE_SPHAIRA_RESULT_ENUM(FsFailedStdioStat),

View File

@@ -91,6 +91,8 @@ bool fix_path(const char* str, char* out, bool strip_leading_slash = false);
void update_devoptab_for_read_only(devoptab_t* devoptab, bool read_only); void update_devoptab_for_read_only(devoptab_t* devoptab, bool read_only);
struct PushPullThreadData { struct PushPullThreadData {
static constexpr size_t MAX_BUFFER_SIZE = 1024 * 64; // 64KB max buffer
PushPullThreadData(CURL* _curl); PushPullThreadData(CURL* _curl);
virtual ~PushPullThreadData(); virtual ~PushPullThreadData();
Result CreateAndStart(); Result CreateAndStart();
@@ -130,7 +132,7 @@ struct MountConfig {
std::string pass{}; std::string pass{};
std::string dump_path{}; std::string dump_path{};
std::optional<long> port{}; std::optional<long> port{};
int timeout{5000}; // 5 seconds. long timeout{};
bool read_only{}; bool read_only{};
bool no_stat_file{true}; bool no_stat_file{true};
bool no_stat_dir{true}; bool no_stat_dir{true};
@@ -164,7 +166,7 @@ struct MountDevice {
virtual int devoptab_close(void *fd) { return -EIO; } virtual int devoptab_close(void *fd) { return -EIO; }
virtual ssize_t devoptab_read(void *fd, char *ptr, size_t len) { return -EIO; } virtual ssize_t devoptab_read(void *fd, char *ptr, size_t len) { return -EIO; }
virtual ssize_t devoptab_write(void *fd, const char *ptr, size_t len) { return -EIO; } virtual ssize_t devoptab_write(void *fd, const char *ptr, size_t len) { return -EIO; }
virtual off_t devoptab_seek(void *fd, off_t pos, int dir) { return 0; } virtual ssize_t devoptab_seek(void *fd, off_t pos, int dir) { return 0; }
virtual int devoptab_fstat(void *fd, struct stat *st) { return -EIO; } virtual int devoptab_fstat(void *fd, struct stat *st) { return -EIO; }
virtual int devoptab_unlink(const char *path) { return -EIO; } virtual int devoptab_unlink(const char *path) { return -EIO; }
virtual int devoptab_rename(const char *oldName, const char *newName) { return -EIO; } virtual int devoptab_rename(const char *oldName, const char *newName) { return -EIO; }

View File

@@ -321,12 +321,12 @@ Result CreateFile(const FsPathReal& path, u64 size, u32 option, bool ignore_read
} }
R_TRY(fsdevGetLastResult()); R_TRY(fsdevGetLastResult());
return Result_FsUnknownStdioError; return Result_FsStdioFailedToCreate;
} }
ON_SCOPE_EXIT(close(fd)); ON_SCOPE_EXIT(close(fd));
if (size) { if (size) {
R_UNLESS(!ftruncate(fd, size), Result_FsUnknownStdioError); R_UNLESS(!ftruncate(fd, size), Result_FsStdioFailedToTruncate);
} }
R_SUCCEED(); R_SUCCEED();
@@ -341,7 +341,7 @@ Result CreateDirectory(const FsPathReal& path, bool ignore_read_only) {
} }
R_TRY(fsdevGetLastResult()); R_TRY(fsdevGetLastResult());
return Result_FsUnknownStdioError; return Result_FsStdioFailedToCreateDirectory;
} }
R_SUCCEED(); R_SUCCEED();
} }
@@ -363,7 +363,7 @@ Result DeleteFile(const FsPathReal& path, bool ignore_read_only) {
if (unlink(path)) { if (unlink(path)) {
R_TRY(fsdevGetLastResult()); R_TRY(fsdevGetLastResult());
return Result_FsUnknownStdioError; return Result_FsStdioFailedToDeleteFile;
} }
R_SUCCEED(); R_SUCCEED();
} }
@@ -373,7 +373,7 @@ Result DeleteDirectory(const FsPathReal& path, bool ignore_read_only) {
if (rmdir(path)) { if (rmdir(path)) {
R_TRY(fsdevGetLastResult()); R_TRY(fsdevGetLastResult());
return Result_FsUnknownStdioError; return Result_FsStdioFailedToDeleteDirectory;
} }
R_SUCCEED(); R_SUCCEED();
} }
@@ -405,7 +405,7 @@ Result RenameFile(const FsPathReal& src, const FsPathReal& dst, bool ignore_read
if (rename(src, dst)) { if (rename(src, dst)) {
R_TRY(fsdevGetLastResult()); R_TRY(fsdevGetLastResult());
return Result_FsUnknownStdioError; return Result_FsStdioFailedToRename;
} }
R_SUCCEED(); R_SUCCEED();
} }
@@ -421,7 +421,7 @@ Result GetEntryType(const FsPathReal& path, FsDirEntryType* out) {
struct stat st; struct stat st;
if (stat(path, &st)) { if (stat(path, &st)) {
R_TRY(fsdevGetLastResult()); R_TRY(fsdevGetLastResult());
return Result_FsUnknownStdioError; return Result_FsStdioFailedToStat;
} }
*out = S_ISREG(st.st_mode) ? FsDirEntryType_File : FsDirEntryType_Dir; *out = S_ISREG(st.st_mode) ? FsDirEntryType_File : FsDirEntryType_Dir;
R_SUCCEED(); R_SUCCEED();
@@ -431,7 +431,7 @@ Result GetFileTimeStampRaw(const FsPathReal& path, FsTimeStampRaw *out) {
struct stat st; struct stat st;
if (stat(path, &st)) { if (stat(path, &st)) {
R_TRY(fsdevGetLastResult()); R_TRY(fsdevGetLastResult());
return Result_FsUnknownStdioError; return Result_FsStdioFailedToStat;
} }
out->is_valid = true; out->is_valid = true;
@@ -489,7 +489,7 @@ Result OpenFile(fs::Fs* fs, const FsPathReal& path, u32 mode, File* f) {
f->m_stdio = std::fopen(path, "rb+"); f->m_stdio = std::fopen(path, "rb+");
} }
R_UNLESS(f->m_stdio, Result_FsUnknownStdioError); R_UNLESS(f->m_stdio, Result_FsStdioFailedToOpenFile);
// disable buffering to match native fs behavior. // disable buffering to match native fs behavior.
// this also causes problems with network io as it will do double reads. // this also causes problems with network io as it will do double reads.
@@ -515,9 +515,11 @@ Result File::Read( s64 off, void* buf, u64 read_size, u32 option, u64* bytes_rea
} else { } else {
R_UNLESS(m_stdio, Result_FsUnknownStdioError); R_UNLESS(m_stdio, Result_FsUnknownStdioError);
if (std::ftell(m_stdio) != off) { if (off != std::ftell(m_stdio)) {
const auto ret = std::fseek(m_stdio, off, SEEK_SET); const auto ret = std::fseek(m_stdio, off, SEEK_SET);
R_UNLESS(ret == 0, Result_FsUnknownStdioError); log_write("[FS] fseek to %ld ret: %d new_off: %zd\n", off, ret, std::ftell(m_stdio));
R_UNLESS(ret == 0, Result_FsStdioFailedToSeek);
R_UNLESS(off == std::ftell(m_stdio), Result_FsStdioFailedToSeek);
} }
*bytes_read = std::fread(buf, 1, read_size, m_stdio); *bytes_read = std::fread(buf, 1, read_size, m_stdio);
@@ -526,7 +528,7 @@ Result File::Read( s64 off, void* buf, u64 read_size, u32 option, u64* bytes_rea
if (*bytes_read < read_size) { if (*bytes_read < read_size) {
if (!std::feof(m_stdio) && std::ferror(m_stdio)) { if (!std::feof(m_stdio) && std::ferror(m_stdio)) {
log_write("[FS] fread error: %d\n", std::ferror(m_stdio)); log_write("[FS] fread error: %d\n", std::ferror(m_stdio));
R_THROW(Result_FsUnknownStdioError); R_THROW(Result_FsStdioFailedToRead);
} }
} }
} }
@@ -542,14 +544,15 @@ Result File::Write(s64 off, const void* buf, u64 write_size, u32 option) {
} else { } else {
R_UNLESS(m_stdio, Result_FsUnknownStdioError); R_UNLESS(m_stdio, Result_FsUnknownStdioError);
if (std::ftell(m_stdio) != off) { if (off != std::ftell(m_stdio)) {
const auto ret = std::fseek(m_stdio, off, SEEK_SET); const auto ret = std::fseek(m_stdio, off, SEEK_SET);
R_UNLESS(ret == 0, Result_FsUnknownStdioError); R_UNLESS(ret == 0, Result_FsStdioFailedToSeek);
R_UNLESS(off == std::ftell(m_stdio), Result_FsStdioFailedToSeek);
} }
const auto result = std::fwrite(buf, 1, write_size, 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); // log_write("[FS] fwrite res: %zu vs %zu\n", result, write_size);
R_UNLESS(result == write_size, Result_FsUnknownStdioError); R_UNLESS(result == write_size, Result_FsStdioFailedToWrite);
} }
R_SUCCEED(); R_SUCCEED();
@@ -563,8 +566,8 @@ Result File::SetSize(s64 sz) {
} else { } else {
R_UNLESS(m_stdio, Result_FsUnknownStdioError); R_UNLESS(m_stdio, Result_FsUnknownStdioError);
const auto fd = fileno(m_stdio); const auto fd = fileno(m_stdio);
R_UNLESS(fd > 0, Result_FsUnknownStdioError); R_UNLESS(fd > 0, Result_FsStdioFailedToTruncate);
R_UNLESS(!ftruncate(fd, sz), Result_FsUnknownStdioError); R_UNLESS(!ftruncate(fd, sz), Result_FsStdioFailedToTruncate);
} }
R_SUCCEED(); R_SUCCEED();
@@ -579,7 +582,7 @@ Result File::GetSize(s64* out) {
R_UNLESS(m_stdio, Result_FsUnknownStdioError); R_UNLESS(m_stdio, Result_FsUnknownStdioError);
struct stat st; struct stat st;
R_UNLESS(!fstat(fileno(m_stdio), &st), Result_FsUnknownStdioError); R_UNLESS(!fstat(fileno(m_stdio), &st), Result_FsStdioFailedToStat);
*out = st.st_size; *out = st.st_size;
} }
@@ -617,7 +620,7 @@ Result OpenDirectory(fs::Fs* fs, const FsPathReal& path, u32 mode, Dir* d) {
R_TRY(fsFsOpenDirectory(&fs->m_fs, path, mode, &d->m_native)); R_TRY(fsFsOpenDirectory(&fs->m_fs, path, mode, &d->m_native));
} else { } else {
d->m_stdio = opendir(path); d->m_stdio = opendir(path);
R_UNLESS(d->m_stdio, Result_FsUnknownStdioError); R_UNLESS(d->m_stdio, Result_FsStdioFailedToOpenDirectory);
} }
R_SUCCEED(); R_SUCCEED();

View File

@@ -82,6 +82,14 @@ struct ThreadData {
return read_running || decompress_running || write_running; return read_running || decompress_running || write_running;
} }
auto GetReadOffset() volatile const -> s64 {
return read_offset;
}
auto GetDecompressOffset() volatile const -> s64 {
return decompress_offset;
}
auto GetWriteOffset() volatile const -> s64 { auto GetWriteOffset() volatile const -> s64 {
return write_offset; return write_offset;
} }
@@ -94,8 +102,16 @@ struct ThreadData {
return &m_uevent_done; return &m_uevent_done;
} }
auto GetProgressEvent() { auto GetReadProgressEvent() {
return &m_uevent_progres; return &m_uevent_read_progress;
}
auto GetDecompressProgressEvent() {
return &m_uevent_decompress_progress;
}
auto GetWriteProgressEvent() {
return &m_uevent_write_progress;
} }
void SetReadResult(Result result) { void SetReadResult(Result result) {
@@ -174,7 +190,9 @@ private:
CondVar can_pull_write{}; CondVar can_pull_write{};
UEvent m_uevent_done{}; UEvent m_uevent_done{};
UEvent m_uevent_progres{}; UEvent m_uevent_read_progress{};
UEvent m_uevent_decompress_progress{};
UEvent m_uevent_write_progress{};
RingBuf<2> read_buffers{}; RingBuf<2> read_buffers{};
RingBuf<2> write_buffers{}; RingBuf<2> write_buffers{};
@@ -219,8 +237,10 @@ ThreadData::ThreadData(ui::ProgressBox* _pbox, s64 size, const ReadCallback& _rf
condvarInit(std::addressof(can_pull)); condvarInit(std::addressof(can_pull));
condvarInit(std::addressof(can_pull_write)); condvarInit(std::addressof(can_pull_write));
ueventCreate(&m_uevent_done, false); ueventCreate(GetDoneEvent(), false);
ueventCreate(&m_uevent_progres, true); ueventCreate(GetReadProgressEvent(), true);
ueventCreate(GetDecompressProgressEvent(), true);
ueventCreate(GetWriteProgressEvent(), true);
} }
auto ThreadData::GetResults() volatile -> Result { auto ThreadData::GetResults() volatile -> Result {
@@ -379,6 +399,7 @@ Result ThreadData::readFuncInternal() {
break; break;
} }
ueventSignal(GetReadProgressEvent());
auto buf_size = bytes_read; auto buf_size = bytes_read;
R_TRY(this->SetDecompressBuf(buf, buffer_offset, buf_size)); R_TRY(this->SetDecompressBuf(buf, buffer_offset, buf_size));
} }
@@ -423,25 +444,17 @@ Result ThreadData::decompressFuncInternal() {
} }
size -= rsize; size -= rsize;
this->decompress_offset += rsize;
data += rsize; data += rsize;
this->decompress_offset += rsize;
// const auto buf_off = temp_buf.size(); ueventSignal(GetDecompressProgressEvent());
// temp_buf.resize(buf_off + size);
// std::memcpy(temp_buf.data() + buf_off, data, size);
// this->decompress_offset += size;
// if (temp_buf.size() >= temp_buf_flush_max) {
// // log_write("flushing data: %zu %.2f MiB\n", temp_buf.size(), temp_buf.size() / 1024.0 / 1024.0);
// R_TRY(this->SetWriteBuf(temp_buf, temp_buf.size()));
// temp_buf.resize(0);
// }
} }
R_SUCCEED(); R_SUCCEED();
})); }));
} else { } else {
this->decompress_offset += buf.size(); this->decompress_offset += buf.size();
ueventSignal(GetDecompressProgressEvent());
R_TRY(this->SetWriteBuf(buf, buf.size())); R_TRY(this->SetWriteBuf(buf, buf.size()));
} }
} }
@@ -479,7 +492,7 @@ Result ThreadData::writeFuncInternal() {
} }
this->write_offset += size; this->write_offset += size;
ueventSignal(GetProgressEvent()); ueventSignal(GetWriteProgressEvent());
} }
log_write("finished write thread success!\n"); log_write("finished write thread success!\n");
@@ -586,7 +599,11 @@ Result TransferInternal(ui::ProgressBox* pbox, s64 size, const ReadCallback& rfu
R_TRY(start_threads()); R_TRY(start_threads());
log_write("[THREAD] started threads\n"); log_write("[THREAD] started threads\n");
const auto waiter_progress = waiterForUEvent(t_data.GetProgressEvent()); // use the read progress as the write output may be smaller due to compressing
// so read will show a more accurate progress.
// TODO: show progress bar for all 3 threads.
// NOTE: went back to using write progress for now.
const auto waiter_progress = waiterForUEvent(t_data.GetWriteProgressEvent());
const auto waiter_cancel = waiterForUEvent(pbox->GetCancelEvent()); const auto waiter_cancel = waiterForUEvent(pbox->GetCancelEvent());
const auto waiter_done = waiterForUEvent(t_data.GetDoneEvent()); const auto waiter_done = waiterForUEvent(t_data.GetDoneEvent());

View File

@@ -51,6 +51,19 @@ auto GetCodeMessage(Result rc) -> const char* {
case Result_FsLoadingCancelled: return "SphairaError_FsLoadingCancelled"; case Result_FsLoadingCancelled: return "SphairaError_FsLoadingCancelled";
case Result_FsBrokenRoot: return "SphairaError_FsBrokenRoot"; case Result_FsBrokenRoot: return "SphairaError_FsBrokenRoot";
case Result_FsUnknownStdioError: return "SphairaError_FsUnknownStdioError"; case Result_FsUnknownStdioError: return "SphairaError_FsUnknownStdioError";
case Result_FsStdioFailedToSeek: return "SphairaError_FsStdioFailedToSeek";
case Result_FsStdioFailedToRead: return "SphairaError_FsStdioFailedToRead";
case Result_FsStdioFailedToWrite: return "SphairaError_FsStdioFailedToWrite";
case Result_FsStdioFailedToOpenFile: return "SphairaError_FsStdioFailedToOpenFile";
case Result_FsStdioFailedToCreate: return "SphairaError_FsStdioFailedToCreate";
case Result_FsStdioFailedToTruncate: return "SphairaError_FsStdioFailedToTruncate";
case Result_FsStdioFailedToFlush: return "SphairaError_FsStdioFailedToFlush";
case Result_FsStdioFailedToCreateDirectory: return "SphairaError_FsStdioFailedToCreateDirectory";
case Result_FsStdioFailedToDeleteFile: return "SphairaError_FsStdioFailedToDeleteFile";
case Result_FsStdioFailedToDeleteDirectory: return "SphairaError_FsStdioFailedToDeleteDirectory";
case Result_FsStdioFailedToOpenDirectory: return "SphairaError_FsStdioFailedToOpenDirectory";
case Result_FsStdioFailedToRename: return "SphairaError_FsStdioFailedToRename";
case Result_FsStdioFailedToStat: return "SphairaError_FsStdioFailedToStat";
case Result_FsReadOnly: return "SphairaError_FsReadOnly"; case Result_FsReadOnly: return "SphairaError_FsReadOnly";
case Result_FsNotActive: return "SphairaError_FsNotActive"; case Result_FsNotActive: return "SphairaError_FsNotActive";
case Result_FsFailedStdioStat: return "SphairaError_FsFailedStdioStat"; case Result_FsFailedStdioStat: return "SphairaError_FsFailedStdioStat";

View File

@@ -81,8 +81,7 @@ constexpr FsEntry FS_ENTRY_DEFAULT{
constexpr FsEntry FS_ENTRIES[]{ constexpr FsEntry FS_ENTRIES[]{
FS_ENTRY_DEFAULT, FS_ENTRY_DEFAULT,
{ "Image System memory", "/", FsType::ImageNand }, { "Album", "/", FsType::ImageSd},
{ "Image microSD card", "/", FsType::ImageSd},
}; };
constexpr std::string_view AUDIO_EXTENSIONS[] = { constexpr std::string_view AUDIO_EXTENSIONS[] = {

View File

@@ -706,7 +706,6 @@ void Menu::ExportOptions(bool to_nsz) {
void Menu::DumpGames(u32 flags, bool to_nsz) { void Menu::DumpGames(u32 flags, bool to_nsz) {
auto targets = GetSelectedEntries(); auto targets = GetSelectedEntries();
ClearSelection();
std::vector<NspEntry> nsp_entries; std::vector<NspEntry> nsp_entries;
for (auto& e : targets) { for (auto& e : targets) {

View File

@@ -88,7 +88,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -134,7 +134,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return bytes_read; return bytes_read;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto& info = file->info; const auto& info = file->info;

View File

@@ -171,9 +171,14 @@ off_t devoptab_seek(struct _reent *r, void *fd, off_t pos, int dir) {
SCOPED_RWLOCK(&g_rwlock, false); SCOPED_RWLOCK(&g_rwlock, false);
SCOPED_MUTEX(&file->device->mutex); SCOPED_MUTEX(&file->device->mutex);
const auto off = file->device->mount_device->devoptab_seek(file->fd, pos, dir); const auto ret = file->device->mount_device->devoptab_seek(file->fd, pos, dir);
if (ret < 0) {
set_errno(r, -ret);
return 0;
}
r->_errno = 0; r->_errno = 0;
return off; return ret;
} }
int devoptab_fstat(struct _reent *r, void *fd, struct stat *st) { int devoptab_fstat(struct _reent *r, void *fd, struct stat *st) {
@@ -960,11 +965,17 @@ PushPullThreadData::PushPullThreadData(CURL* _curl) : curl{_curl} {
PushPullThreadData::~PushPullThreadData() { PushPullThreadData::~PushPullThreadData() {
Cancel(); Cancel();
if (started) {
threadWaitForExit(&thread); threadWaitForExit(&thread);
}
threadClose(&thread); threadClose(&thread);
} }
Result PushPullThreadData::CreateAndStart() { Result PushPullThreadData::CreateAndStart() {
SCOPED_MUTEX(&mutex);
if (started) { if (started) {
R_SUCCEED(); R_SUCCEED();
} }
@@ -989,6 +1000,10 @@ bool PushPullThreadData::IsRunning() {
} }
size_t PushPullThreadData::PullData(char* data, size_t total_size) { size_t PushPullThreadData::PullData(char* data, size_t total_size) {
if (!data || !total_size) {
return 0;
}
SCOPED_MUTEX(&mutex); SCOPED_MUTEX(&mutex);
ON_SCOPE_EXIT(condvarWakeOne(&can_push)); ON_SCOPE_EXIT(condvarWakeOne(&can_push));
@@ -1014,12 +1029,16 @@ size_t PushPullThreadData::PullData(char* data, size_t total_size) {
} }
size_t PushPullThreadData::PushData(const char* data, size_t total_size) { size_t PushPullThreadData::PushData(const char* data, size_t total_size) {
if (!data || !total_size) {
return 0;
}
SCOPED_MUTEX(&mutex); SCOPED_MUTEX(&mutex);
ON_SCOPE_EXIT(condvarWakeOne(&can_pull)); ON_SCOPE_EXIT(condvarWakeOne(&can_pull));
size_t bytes_written = 0; size_t bytes_written = 0;
while (bytes_written < total_size && !error && !finished) { while (bytes_written < total_size && !error && !finished) {
const size_t space_left = (1024 * 64) - buffer.size(); // 64K max buffer const size_t space_left = MAX_BUFFER_SIZE - buffer.size();
if (space_left == 0) { if (space_left == 0) {
condvarWakeOne(&can_pull); condvarWakeOne(&can_pull);
condvarWait(&can_push, &mutex); condvarWait(&can_push, &mutex);
@@ -1035,11 +1054,19 @@ size_t PushPullThreadData::PushData(const char* data, size_t total_size) {
} }
size_t PushPullThreadData::push_thread_callback(const char *ptr, size_t size, size_t nmemb, void *userdata) { size_t PushPullThreadData::push_thread_callback(const char *ptr, size_t size, size_t nmemb, void *userdata) {
if (!ptr || !userdata || !size || !nmemb) {
return 0;
}
auto* data = static_cast<PushPullThreadData*>(userdata); auto* data = static_cast<PushPullThreadData*>(userdata);
return data->PushData(ptr, size * nmemb); return data->PushData(ptr, size * nmemb);
} }
size_t PushPullThreadData::pull_thread_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { size_t PushPullThreadData::pull_thread_callback(char *ptr, size_t size, size_t nmemb, void *userdata) {
if (!ptr || !userdata || !size || !nmemb) {
return 0;
}
auto* data = static_cast<PushPullThreadData*>(userdata); auto* data = static_cast<PushPullThreadData*>(userdata);
return data->PullData(ptr, size * nmemb); return data->PullData(ptr, size * nmemb);
} }
@@ -1067,10 +1094,29 @@ PullThreadData::~PullThreadData() {
if (started) { if (started) {
SCOPED_MUTEX(&mutex); SCOPED_MUTEX(&mutex);
// for now, always wait until the dat is flushed.
// may enable a timeout later on, however i don't want to risk
// data loss for users that have slow hdd / connections.
#if 1
while (!finished && !error && !buffer.empty()) { while (!finished && !error && !buffer.empty()) {
condvarWakeOne(&can_pull); condvarWakeOne(&can_pull);
condvarWaitTimeout(&can_push, &mutex, 5e+9); condvarWait(&can_push, &mutex);
} }
#else
u64 timeout = 5e+9;
const auto deadline = armGetSystemTick() + armNsToTicks(timeout);
while (!finished && !error && !buffer.empty()) {
const s64 remaining = deadline - armGetSystemTick();
timeout = remaining > 0 ? armTicksToNs(remaining) : 0;
condvarWakeOne(&can_pull);
if (R_FAILED(condvarWaitTimeout(&can_push, &mutex, timeout))) {
log_write("[PullThreadData] condvarWaitTimeout() timed out flushing data: %zu\n", buffer.size());
break;
}
}
#endif
} }
} }
@@ -1276,11 +1322,6 @@ void MountCurlDevice::curl_set_common_options(CURL* curl, const std::string& url
// NOTE: port, user and pass are set in the curl_url. // NOTE: port, user and pass are set in the curl_url.
curl_easy_reset(curl); curl_easy_reset(curl);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// cancel if speed is less than 1 bytes/sec for timeout seconds.
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
// todo: change config to accept seconds rather than ms.
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, config.timeout / 1000L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, config.timeout);
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1L); curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 15L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 15L);
@@ -1291,6 +1332,14 @@ void MountCurlDevice::curl_set_common_options(CURL* curl, const std::string& url
curl_easy_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 1024L * 64L); curl_easy_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 1024L * 64L);
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
if (config.timeout > 0) {
// cancel if speed is less than 1 bytes/sec for timeout seconds.
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
// todo: change config to accept seconds rather than ms.
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, config.timeout / 1000L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, config.timeout);
}
if (m_curl_share) { if (m_curl_share) {
curl_easy_setopt(curl, CURLOPT_SHARE, m_curl_share); curl_easy_setopt(curl, CURLOPT_SHARE, m_curl_share);
} }

View File

@@ -97,7 +97,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -331,7 +331,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return total_bytes_read; return total_bytes_read;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto size = get_size_from_files(file); const auto size = get_size_from_files(file);

View File

@@ -38,7 +38,7 @@ private:
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override; ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_unlink(const char *path) override; int devoptab_unlink(const char *path) override;
int devoptab_rename(const char *oldName, const char *newName) override; int devoptab_rename(const char *oldName, const char *newName) override;
@@ -546,7 +546,7 @@ ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) {
return ret; return ret;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
if (dir == SEEK_CUR) { if (dir == SEEK_CUR) {

View File

@@ -51,7 +51,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -318,7 +318,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return ret; return ret;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
if (dir == SEEK_CUR) { if (dir == SEEK_CUR) {

View File

@@ -159,7 +159,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -207,7 +207,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return bytes_read; return bytes_read;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto& entry = file->entry; const auto& entry = file->entry;
@@ -343,9 +343,11 @@ Result MountNcaInternal(fs::Fs* fs, const std::shared_ptr<yati::source::Base>& s
// check if this is a ncz. // check if this is a ncz.
ncz::Header ncz_header{}; ncz::Header ncz_header{};
if (size >= NCZ_NORMAL_SIZE) {
R_TRY(source->Read2(&ncz_header, NCZ_NORMAL_SIZE, sizeof(ncz_header))); R_TRY(source->Read2(&ncz_header, NCZ_NORMAL_SIZE, sizeof(ncz_header)));
}
if (ncz_header.magic == NCZ_SECTION_MAGIC) { if (size >= NCZ_NORMAL_SIZE && ncz_header.magic == NCZ_SECTION_MAGIC) {
// read all the sections. // read all the sections.
s64 ncz_offset = NCZ_SECTION_OFFSET; s64 ncz_offset = NCZ_SECTION_OFFSET;
ncz::Sections ncz_sections(ncz_header.total_sections); ncz::Sections ncz_sections(ncz_header.total_sections);

View File

@@ -1,5 +1,3 @@
#ifdef ENABLE_DEVOPTAB_NFS
#include "utils/devoptab_common.hpp" #include "utils/devoptab_common.hpp"
#include "defines.hpp" #include "defines.hpp"
#include "log.hpp" #include "log.hpp"
@@ -25,7 +23,7 @@ private:
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override; ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_unlink(const char *path) override; int devoptab_unlink(const char *path) override;
int devoptab_rename(const char *oldName, const char *newName) override; int devoptab_rename(const char *oldName, const char *newName) override;
@@ -111,8 +109,10 @@ bool Device::Mount() {
} }
} }
if (this->config.timeout > 0) {
nfs_set_timeout(nfs, this->config.timeout); nfs_set_timeout(nfs, this->config.timeout);
nfs_set_readonly(nfs, this->config.read_only); nfs_set_readonly(nfs, this->config.read_only);
}
// nfs_set_mountport(nfs, url->port); // nfs_set_mountport(nfs, url->port);
} }
@@ -123,7 +123,7 @@ bool Device::Mount() {
url = "nfs://" + url; url = "nfs://" + url;
} }
auto nfs_url = nfs_parse_url_dir(nfs, url.c_str()); auto nfs_url = nfs_parse_url_full(nfs, url.c_str());
if (!nfs_url) { if (!nfs_url) {
log_write("[NFS] nfs_parse_url() failed for url: %s\n", url.c_str()); log_write("[NFS] nfs_parse_url() failed for url: %s\n", url.c_str());
return false; return false;
@@ -225,7 +225,7 @@ ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) {
return written; return written;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
u64 current_offset = 0; u64 current_offset = 0;
@@ -414,17 +414,3 @@ Result MountNfsAll() {
} }
} // namespace sphaira::devoptab } // namespace sphaira::devoptab
#else // ENABLE_DEVOPTAB_NFS
#include "defines.hpp"
namespace sphaira::devoptab {
Result MountNfsAll() {
R_SUCCEED();
}
} // namespace sphaira::devoptab
#endif // ENABLE_DEVOPTAB_NFS

View File

@@ -118,7 +118,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -166,7 +166,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return bytes_read; return bytes_read;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto& entry = file->entry; const auto& entry = file->entry;

View File

@@ -41,7 +41,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -90,7 +90,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return bytes_read; return bytes_read;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto& collection = file->collection; const auto& collection = file->collection;
@@ -171,7 +171,7 @@ int Device::devoptab_lstat(const char *path, struct stat *st) {
st->st_size = it->size; st->st_size = it->size;
} }
return -ENOENT; return 0;
} }
} // namespace } // namespace

View File

@@ -49,7 +49,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -101,7 +101,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return bytes_read; return bytes_read;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
if (dir == SEEK_CUR) { if (dir == SEEK_CUR) {

View File

@@ -40,7 +40,7 @@ private:
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override; ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_unlink(const char *path) override; int devoptab_unlink(const char *path) override;
int devoptab_rename(const char *oldName, const char *newName) override; int devoptab_rename(const char *oldName, const char *newName) override;
@@ -247,11 +247,14 @@ bool Device::Mount() {
libssh2_session_set_blocking(m_session, 1); libssh2_session_set_blocking(m_session, 1);
libssh2_session_flag(m_session, LIBSSH2_FLAG_COMPRESS, 1); libssh2_session_flag(m_session, LIBSSH2_FLAG_COMPRESS, 1);
if (this->config.timeout > 0) {
libssh2_session_set_timeout(m_session, this->config.timeout); libssh2_session_set_timeout(m_session, this->config.timeout);
// dkp libssh2 is too old for this. // dkp libssh2 is too old for this.
#if LIBSSH2_VERSION_NUM >= 0x010B00 #if LIBSSH2_VERSION_NUM >= 0x010B00
libssh2_session_set_read_timeout(m_session, this->config.timeout); libssh2_session_set_read_timeout(m_session, this->config.timeout);
#endif #endif
}
} }
if (this->config.user.empty() || this->config.pass.empty()) { if (this->config.user.empty() || this->config.pass.empty()) {
@@ -353,7 +356,7 @@ ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) {
return ret; return ret;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto current_pos = libssh2_sftp_tell64(file->fd); const auto current_pos = libssh2_sftp_tell64(file->fd);

View File

@@ -28,7 +28,7 @@ private:
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override; ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_unlink(const char *path) override; int devoptab_unlink(const char *path) override;
int devoptab_rename(const char *oldName, const char *newName) override; int devoptab_rename(const char *oldName, const char *newName) override;
@@ -118,8 +118,10 @@ bool Device::Mount() {
smb2_set_workstation(this->smb2, workstation->second.c_str()); smb2_set_workstation(this->smb2, workstation->second.c_str());
} }
if (config.timeout > 0) {
smb2_set_timeout(this->smb2, this->config.timeout); smb2_set_timeout(this->smb2, this->config.timeout);
} }
}
auto smb2_url = smb2_parse_url(this->smb2, this->config.url.c_str()); auto smb2_url = smb2_parse_url(this->smb2, this->config.url.c_str());
if (!smb2_url) { if (!smb2_url) {
@@ -160,28 +162,56 @@ int Device::devoptab_close(void *fd) {
ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) { ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto ret = smb2_read(this->smb2, file->fd, reinterpret_cast<uint8_t*>(ptr), len); const auto max_read = smb2_get_max_read_size(this->smb2);
size_t bytes_read = 0;
while (bytes_read < len) {
const auto to_read = std::min<size_t>(len - bytes_read, max_read);
const auto ret = smb2_read(this->smb2, file->fd, (u8*)ptr, to_read);
if (ret < 0) { if (ret < 0) {
log_write("[SMB2] smb2_read() failed: %s errno: %s\n", smb2_get_error(this->smb2), std::strerror(-ret)); log_write("[SMB2] smb2_read() failed: %s errno: %s\n", smb2_get_error(this->smb2), std::strerror(-ret));
return ret; return ret;
} }
return ret; ptr += ret;
bytes_read += ret;
if (ret < to_read) {
break;
}
}
return bytes_read;
} }
ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) { ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto ret = smb2_write(this->smb2, file->fd, reinterpret_cast<const uint8_t*>(ptr), len); const auto max_write = smb2_get_max_write_size(this->smb2);
size_t written = 0;
while (written < len) {
const auto to_write = std::min<size_t>(len - written, max_write);
const auto ret = smb2_write(this->smb2, file->fd, (const u8*)ptr, to_write);
if (ret < 0) { if (ret < 0) {
log_write("[SMB2] smb2_write() failed: %s errno: %s\n", smb2_get_error(this->smb2), std::strerror(-ret)); log_write("[SMB2] smb2_write() failed: %s errno: %s\n", smb2_get_error(this->smb2), std::strerror(-ret));
return ret; return ret;
} }
return ret; ptr += ret;
written += ret;
if (ret < to_write) {
break;
}
}
return written;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
u64 current_offset = 0; u64 current_offset = 0;

View File

@@ -34,7 +34,7 @@ private:
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override; ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_unlink(const char *path) override; int devoptab_unlink(const char *path) override;
int devoptab_rename(const char *oldName, const char *newName) override; int devoptab_rename(const char *oldName, const char *newName) override;
@@ -124,7 +124,7 @@ ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) {
return ret; return ret;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
return lseek(file->fd, pos, dir); return lseek(file->fd, pos, dir);

View File

@@ -58,7 +58,7 @@ private:
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override; ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_unlink(const char *path) override; int devoptab_unlink(const char *path) override;
int devoptab_rename(const char *oldName, const char *newName) override; int devoptab_rename(const char *oldName, const char *newName) override;
@@ -188,6 +188,7 @@ int Device::webdav_dirlist(const std::string& path, DirEntries& out) {
continue; continue;
} }
// todo: fix requested path still being displayed.
const auto href = url_decode(href_x.node().text().as_string()); const auto href = url_decode(href_x.node().text().as_string());
if (href.empty() || href == requested_path || href == requested_path + '/') { if (href.empty() || href == requested_path || href == requested_path + '/') {
continue; continue;
@@ -483,7 +484,7 @@ ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) {
return ret; return ret;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
if (dir == SEEK_CUR) { if (dir == SEEK_CUR) {

View File

@@ -39,7 +39,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -90,7 +90,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return bytes_read; return bytes_read;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
const auto& collection = file->collection; const auto& collection = file->collection;

View File

@@ -199,7 +199,7 @@ private:
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
int devoptab_close(void *fd) override; int devoptab_close(void *fd) override;
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
off_t devoptab_seek(void *fd, off_t pos, int dir) override; ssize_t devoptab_seek(void *fd, off_t pos, int dir) override;
int devoptab_fstat(void *fd, struct stat *st) override; int devoptab_fstat(void *fd, struct stat *st) override;
int devoptab_diropen(void* fd, const char *path) override; int devoptab_diropen(void* fd, const char *path) override;
int devoptab_dirreset(void* fd) override; int devoptab_dirreset(void* fd) override;
@@ -338,7 +338,7 @@ ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
return len; return len;
} }
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { ssize_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
auto file = static_cast<File*>(fd); auto file = static_cast<File*>(fd);
// seek like normal. // seek like normal.