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

@@ -171,9 +171,14 @@ off_t devoptab_seek(struct _reent *r, void *fd, off_t pos, int dir) {
SCOPED_RWLOCK(&g_rwlock, false);
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;
return off;
return ret;
}
int devoptab_fstat(struct _reent *r, void *fd, struct stat *st) {
@@ -960,11 +965,17 @@ PushPullThreadData::PushPullThreadData(CURL* _curl) : curl{_curl} {
PushPullThreadData::~PushPullThreadData() {
Cancel();
threadWaitForExit(&thread);
if (started) {
threadWaitForExit(&thread);
}
threadClose(&thread);
}
Result PushPullThreadData::CreateAndStart() {
SCOPED_MUTEX(&mutex);
if (started) {
R_SUCCEED();
}
@@ -989,6 +1000,10 @@ bool PushPullThreadData::IsRunning() {
}
size_t PushPullThreadData::PullData(char* data, size_t total_size) {
if (!data || !total_size) {
return 0;
}
SCOPED_MUTEX(&mutex);
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) {
if (!data || !total_size) {
return 0;
}
SCOPED_MUTEX(&mutex);
ON_SCOPE_EXIT(condvarWakeOne(&can_pull));
size_t bytes_written = 0;
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) {
condvarWakeOne(&can_pull);
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) {
if (!ptr || !userdata || !size || !nmemb) {
return 0;
}
auto* data = static_cast<PushPullThreadData*>(userdata);
return data->PushData(ptr, size * nmemb);
}
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);
return data->PullData(ptr, size * nmemb);
}
@@ -1067,10 +1094,29 @@ PullThreadData::~PullThreadData() {
if (started) {
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()) {
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.
curl_easy_reset(curl);
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_FOLLOWLOCATION, 1L);
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_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) {
curl_easy_setopt(curl, CURLOPT_SHARE, m_curl_share);
}