Compare commits

..
2 Commits
Author SHA1 Message Date
owendswang 6a110f95ae v1.1 2026-08-03 23:35:41 +08:00
owendswang b463c3f86b Small optimization of directory deletion 2026-08-01 00:11:46 +08:00
8 changed files with 92 additions and 110 deletions

No files matched your search

+1 -1
View File
@@ -13,7 +13,7 @@ ifeq ($(MAKECMDGOALS),)
endif
endif
VERSION_TAG := v1.0
VERSION_TAG := v1.1
TITLE_ID := FMGR88888
PYTHON ?= python3
STRIP ?= $(PS5_PAYLOAD_SDK)/bin/prospero-strip
+1 -1
View File
@@ -87,7 +87,7 @@ window.WFM_LANG = {
newTextPrompt: "Text file name",
creatingText: "Creating text file...",
createTextFailed: "Failed to create text file: {error}",
unsavedSaveConfirm: "The text has unsaved changes. Save before closing?\n\nCancel discards the changes and closes.",
unsavedSaveConfirm: "The text has unsaved changes. Close without saving?\n\nCancel keeps the editor open.",
loadingText: "Loading text...",
savingText: "Saving...",
textSaved: "Text saved",
+1 -1
View File
@@ -87,7 +87,7 @@ window.WFM_LANG = {
newTextPrompt: "文本文件名",
creatingText: "正在新建文本...",
createTextFailed: "新建文本失败: {error}",
unsavedSaveConfirm: "文本有未保存的修改,是否保存后关闭?\n\n取消将放弃修改并关闭。",
unsavedSaveConfirm: "文本有未保存的修改,是否不保存并关闭?\n\n取消将留在编辑器中。",
loadingText: "正在读取文本...",
savingText: "正在保存...",
textSaved: "文本已保存",
+2 -2
View File
@@ -26,7 +26,7 @@ let downloadFrame = null;
let uploadXhr = null;
let L = {};
const APP_VERSION = "v1.0";
const APP_VERSION = "v1.1";
const LAST_PATH_KEY = "ps5-web-file-mgr:last-path";
const SORT_KEY = "ps5-web-file-mgr:list-sort";
const LOADING_DISPLAY_DELAY = 250;
@@ -609,7 +609,7 @@ function closeTextEditor() {
function requestCloseTextEditor() {
if (textEditorBusy) return;
if (textEditorEl.value !== textEditorOriginal &&
confirm(t("unsavedSaveConfirm"))) return saveTextEditor();
!confirm(t("unsavedSaveConfirm"))) return;
return closeTextEditor();
}
+2 -2
View File
@@ -401,8 +401,8 @@ prepare_download_task(file_task_t *task) {
task_update(task, TASK_RUNNING, "preparing", 0, NULL);
for(i = 0; i < task->src_count; i++) {
if(count_task_path_bytes(task, task->srcs[i], task->srcs[i], NULL,
&total, NULL, &file_count, &dir_count)) {
if(count_task_path_bytes(task, task->srcs[i], task->srcs[i],
&total, &file_count, &dir_count)) {
return -1;
}
}
+81 -89
View File
@@ -40,6 +40,7 @@ typedef struct task_completion {
} task_completion_t;
static int ensure_copy_dir(const char *path);
static int open_copy_temp(const char *dst, char *temp, size_t temp_size);
#if FILEMGR_PIPELINE_COPY
typedef struct copy_pipeline_slot {
char *data;
@@ -255,15 +256,13 @@ static int task_target_path(file_task_t *task, const char *src,
char *out, size_t size);
static int count_path_bytes_sync(file_task_t *task, const char *path,
const char *display, const char *target,
const char *display,
unsigned long long *total,
unsigned long long *reclaimable,
size_t *file_count, size_t *dir_count);
static int
count_dir_bytes_sync(file_task_t *task, const char *path, const char *display,
const char *target, unsigned long long *total,
unsigned long long *reclaimable, size_t *file_count,
unsigned long long *total, size_t *file_count,
size_t *dir_count) {
DIR *dir = opendir(path);
struct dirent *entry;
@@ -275,7 +274,6 @@ count_dir_bytes_sync(file_task_t *task, const char *path, const char *display,
while((entry = readdir(dir))) {
char child[PATH_MAX];
char display_child[PATH_MAX];
char target_child[PATH_MAX];
if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
}
@@ -285,11 +283,8 @@ count_dir_bytes_sync(file_task_t *task, const char *path, const char *display,
if(path_join(child, sizeof(child), path, entry->d_name) ||
(display && path_join(display_child, sizeof(display_child), display,
entry->d_name)) ||
(target && path_join(target_child, sizeof(target_child), target,
entry->d_name)) ||
count_path_bytes_sync(task, child, display ? display_child : NULL,
target ? target_child : NULL, total, reclaimable,
file_count, dir_count)) {
total, file_count, dir_count)) {
goto done;
}
}
@@ -301,12 +296,9 @@ done:
static int
count_path_bytes_sync(file_task_t *task, const char *path, const char *display,
const char *target, unsigned long long *total,
unsigned long long *reclaimable, size_t *file_count,
unsigned long long *total, size_t *file_count,
size_t *dir_count) {
struct stat st;
struct stat target_st;
int target_exists = 0;
if(task && task_cancel_requested(task)) {
return -1;
@@ -317,25 +309,13 @@ count_path_bytes_sync(file_task_t *task, const char *path, const char *display,
if(lstat(path, &st)) {
return -1;
}
if(target) {
if(!lstat(target, &target_st)) {
target_exists = 1;
} else if(errno != ENOENT) {
return -1;
}
}
if(S_ISDIR(st.st_mode)) {
if(dir_count) (*dir_count)++;
return count_dir_bytes_sync(task, path, display,
target_exists && S_ISDIR(target_st.st_mode) ?
target : NULL,
total, reclaimable, file_count, dir_count);
return count_dir_bytes_sync(task, path, display, total, file_count,
dir_count);
}
if(S_ISREG(st.st_mode)) {
*total += (unsigned long long)st.st_size;
if(reclaimable && target_exists && S_ISREG(target_st.st_mode)) {
*reclaimable += (unsigned long long)target_st.st_size;
}
if(file_count) (*file_count)++;
}
return 0;
@@ -345,9 +325,7 @@ count_path_bytes_sync(file_task_t *task, const char *path, const char *display,
typedef struct count_job {
char path[PATH_MAX];
char display[PATH_MAX];
char target[PATH_MAX];
int has_display;
int has_target;
struct count_job *next;
} count_job_t;
@@ -367,18 +345,15 @@ typedef struct count_queue {
int error_number;
int worker_count;
unsigned long long total;
unsigned long long reclaimable;
size_t file_count;
size_t dir_count;
} count_queue_t;
static void
count_queue_add(count_queue_t *queue, unsigned long long total,
unsigned long long reclaimable, size_t file_count,
count_queue_add(count_queue_t *queue, unsigned long long total, size_t file_count,
size_t dir_count) {
pthread_mutex_lock(&queue->lock);
queue->total += total;
queue->reclaimable += reclaimable;
queue->file_count += file_count;
queue->dir_count += dir_count;
pthread_mutex_unlock(&queue->lock);
@@ -391,7 +366,6 @@ count_queue_worker(void *arg) {
for(;;) {
count_job_t *job;
unsigned long long total = 0;
unsigned long long reclaimable = 0;
size_t file_count = 0;
size_t dir_count = 0;
int ret;
@@ -416,10 +390,9 @@ count_queue_worker(void *arg) {
ret = count_path_bytes_sync(queue->task, job->path,
job->has_display ? job->display : NULL,
job->has_target ? job->target : NULL,
&total, &reclaimable, &file_count, &dir_count);
&total, &file_count, &dir_count);
if(!ret) {
count_queue_add(queue, total, reclaimable, file_count, dir_count);
count_queue_add(queue, total, file_count, dir_count);
}
pthread_mutex_lock(&queue->lock);
@@ -481,8 +454,7 @@ count_queue_init(count_queue_t *queue, file_task_t *task) {
}
static int
count_queue_enqueue(count_queue_t *queue, const char *path, const char *display,
const char *target) {
count_queue_enqueue(count_queue_t *queue, const char *path, const char *display) {
count_job_t *job;
if(!(job = calloc(1, sizeof(*job)))) {
@@ -493,10 +465,6 @@ count_queue_enqueue(count_queue_t *queue, const char *path, const char *display,
snprintf(job->display, sizeof(job->display), "%s", display);
job->has_display = 1;
}
if(target) {
snprintf(job->target, sizeof(job->target), "%s", target);
job->has_target = 1;
}
pthread_mutex_lock(&queue->lock);
while(!queue->stopping && queue->queued >= FILE_TASK_QUEUE_LIMIT) {
@@ -565,14 +533,11 @@ count_queue_finish(count_queue_t *queue, int abort_pending) {
static int
count_path_bytes(file_task_t *task, const char *path, const char *display,
const char *target, unsigned long long *total,
unsigned long long *reclaimable, size_t *file_count,
unsigned long long *total, size_t *file_count,
size_t *dir_count) {
DIR *dir;
struct dirent *entry;
struct stat st;
struct stat target_st;
int target_exists = 0;
int ret = -1;
int queue_finished = 0;
count_queue_t queue;
@@ -584,19 +549,12 @@ count_path_bytes(file_task_t *task, const char *path, const char *display,
return -1;
}
if(!S_ISDIR(st.st_mode)) {
return count_path_bytes_sync(task, path, display, target, total,
reclaimable, file_count, dir_count);
return count_path_bytes_sync(task, path, display, total, file_count,
dir_count);
}
if(task) {
task_update(task, TASK_RUNNING, display ? display : path, 0, NULL);
}
if(target) {
if(!lstat(target, &target_st)) {
target_exists = S_ISDIR(target_st.st_mode);
} else if(errno != ENOENT) {
return -1;
}
}
if(dir_count) (*dir_count)++;
if(count_queue_init(&queue, task)) {
return -1;
@@ -609,7 +567,6 @@ count_path_bytes(file_task_t *task, const char *path, const char *display,
while((entry = readdir(dir))) {
char child[PATH_MAX];
char display_child[PATH_MAX];
char target_child[PATH_MAX];
if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
@@ -621,10 +578,7 @@ count_path_bytes(file_task_t *task, const char *path, const char *display,
if(path_join(child, sizeof(child), path, entry->d_name) ||
(display && path_join(display_child, sizeof(display_child), display,
entry->d_name)) ||
(target_exists && path_join(target_child, sizeof(target_child), target,
entry->d_name)) ||
count_queue_enqueue(&queue, child, display ? display_child : NULL,
target_exists ? target_child : NULL)) {
count_queue_enqueue(&queue, child, display ? display_child : NULL)) {
goto done;
}
}
@@ -633,9 +587,6 @@ count_path_bytes(file_task_t *task, const char *path, const char *display,
queue_finished = 1;
if(!ret) {
*total += queue.total;
if(reclaimable) {
*reclaimable += queue.reclaimable;
}
if(file_count) {
*file_count += queue.file_count;
}
@@ -656,16 +607,44 @@ done:
int
count_task_path_bytes(file_task_t *task, const char *path, const char *display,
const char *target, unsigned long long *total,
unsigned long long *reclaimable, size_t *file_count,
unsigned long long *total, size_t *file_count,
size_t *dir_count) {
return count_path_bytes(task, path, display, target, total, reclaimable,
file_count, dir_count);
return count_path_bytes(task, path, display, total, file_count, dir_count);
}
static int
open_copy_temp(const char *dst, char *temp, size_t temp_size) {
char parent[PATH_MAX];
char name[96];
int attempt;
if(path_dirname(dst, parent, sizeof(parent))) {
return -1;
}
for(attempt = 0; attempt < 32; attempt++) {
int fd;
snprintf(name, sizeof(name), ".wfm-copy-%ld-%lld-%d.tmp",
(long)getpid(), (long long)time(NULL), attempt);
if(path_join(temp, temp_size, parent, name)) {
return -1;
}
fd = open(temp, O_WRONLY | O_CREAT | O_EXCL, 0600);
if(fd >= 0) {
return fd;
}
if(errno != EEXIST) {
return -1;
}
}
errno = EEXIST;
return -1;
}
static int
copy_file_buffered(file_task_t *task, const char *src, const char *dst) {
char *buf = NULL;
char temp[PATH_MAX] = {0};
int in = -1;
int out = -1;
int ret = -1;
@@ -674,12 +653,13 @@ copy_file_buffered(file_task_t *task, const char *src, const char *dst) {
task_update(task, TASK_RUNNING, dst, 0, NULL);
if(task_cancel_requested(task)) {
errno = ECANCELED;
return -1;
}
if((in = open(src, O_RDONLY)) < 0) {
goto done;
}
if((out = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0) {
if((out = open_copy_temp(dst, temp, sizeof(temp))) < 0) {
goto done;
}
if(!(buf = malloc(COPY_BUFFER_SIZE))) {
@@ -691,6 +671,7 @@ copy_file_buffered(file_task_t *task, const char *src, const char *dst) {
ssize_t left = n;
char *p = buf;
if(task_cancel_requested(task)) {
errno = ECANCELED;
goto done;
}
while(left > 0) {
@@ -709,6 +690,10 @@ copy_file_buffered(file_task_t *task, const char *src, const char *dst) {
if(fchmod_0777(out)) {
goto done;
}
if(task_cancel_requested(task)) {
errno = ECANCELED;
goto done;
}
ret = 0;
done:
@@ -717,7 +702,16 @@ done:
if(out >= 0) {
if(close(out)) ret = -1;
}
if(ret) unlink(dst);
if(!ret && task_cancel_requested(task)) {
errno = ECANCELED;
ret = -1;
}
if(!ret && rename(temp, dst)) {
ret = -1;
}
if(ret && temp[0]) {
unlink(temp);
}
return ret;
}
@@ -774,6 +768,7 @@ static int
copy_file_pipeline(file_task_t *task, const char *src, const char *dst) {
copy_pipeline_t p;
pthread_t reader;
char temp[PATH_MAX] = {0};
int out = -1;
int ret = -1;
int reader_started = 0;
@@ -794,7 +789,7 @@ copy_file_pipeline(file_task_t *task, const char *src, const char *dst) {
if((p.in = open(src, O_RDONLY)) < 0) {
goto done;
}
if((out = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0) {
if((out = open_copy_temp(dst, temp, sizeof(temp))) < 0) {
goto done;
}
if(pthread_mutex_init(&p.lock, NULL)) {
@@ -873,6 +868,10 @@ copy_file_pipeline(file_task_t *task, const char *src, const char *dst) {
if(fchmod_0777(out)) {
goto done;
}
if(task_cancel_requested(task)) {
errno = ECANCELED;
goto done;
}
ret = 0;
done:
@@ -895,7 +894,16 @@ done:
if(out >= 0) {
if(close(out)) ret = -1;
}
if(ret) unlink(dst);
if(!ret && task_cancel_requested(task)) {
errno = ECANCELED;
ret = -1;
}
if(!ret && rename(temp, dst)) {
ret = -1;
}
if(ret && temp[0]) {
unlink(temp);
}
return ret;
}
#endif
@@ -1398,9 +1406,6 @@ remove_path(file_task_t *task, const char *path) {
closedir(dir);
return rmdir(path);
}
if(S_ISREG(st.st_mode)) {
task_update(task, TASK_RUNNING, path, (unsigned long long)st.st_size, NULL);
}
return unlink(path);
}
@@ -1560,7 +1565,6 @@ task_worker(void *arg) {
file_task_t *task = arg;
unsigned long long total = 0;
unsigned long long required = 0;
unsigned long long reclaimable = 0;
int ret = -1;
task_update(task, TASK_RUNNING, "preparing", 0, NULL);
@@ -1594,7 +1598,6 @@ task_worker(void *arg) {
unsigned long long before = total;
int needs_space = task->op == TASK_COPY;
char target[PATH_MAX];
const char *compare_target = NULL;
if(task->op == TASK_COPY || task->op == TASK_MOVE) {
if(task_target_path(task, task->srcs[i], target, sizeof(target))) {
@@ -1612,17 +1615,7 @@ task_worker(void *arg) {
continue;
}
}
if(needs_space) {
struct stat target_st;
if(!lstat(target, &target_st)) {
compare_target = target;
} else if(errno != ENOENT) {
task_update(task, TASK_FAILED, target, 0, strerror(errno));
return NULL;
}
}
if(count_path_bytes(task, task->srcs[i], task->srcs[i], compare_target,
&total, &reclaimable,
if(count_path_bytes(task, task->srcs[i], task->srcs[i], &total,
&task->file_count, &task->dir_count)) {
if(errno == ECANCELED || task_cancel_requested(task)) {
task_update(task, TASK_CANCELED, task->srcs[i], 0, "canceled");
@@ -1639,7 +1632,6 @@ task_worker(void *arg) {
}
}
task_set_total(task, total);
required = reclaimable >= required ? 0 : required - reclaimable;
if(task->op == TASK_COPY || task->op == TASK_MOVE) {
char error[128] = {0};
+1 -3
View File
@@ -103,9 +103,7 @@ int check_target_space(const char *target, unsigned long long required,
char *arg, size_t arg_size);
int target_available_space(const char *target, unsigned long long *available);
int count_task_path_bytes(file_task_t *task, const char *path,
const char *display, const char *target,
unsigned long long *total,
unsigned long long *reclaimable,
const char *display, unsigned long long *total,
size_t *file_count, size_t *dir_count);
enum MHD_Result api_upload_prepare(struct MHD_Connection *conn,
+3 -11
View File
@@ -74,8 +74,7 @@ upload_task_from_conn(struct MHD_Connection *conn) {
static int
check_upload_manifest_space(const char *base, const char *rels,
const char *sizes, int overwrite,
unsigned long long fallback_total,
const char *sizes, unsigned long long fallback_total,
char *error, size_t error_size,
char *code, size_t code_size,
char *arg, size_t arg_size) {
@@ -107,9 +106,7 @@ check_upload_manifest_space(const char *base, const char *rels,
size_text = strtok_r(sizes_copy, "\n", &size_save);
while(rel || size_text) {
char target[PATH_MAX];
struct stat st;
unsigned long long size;
unsigned long long reclaim = 0;
if(!rel || !size_text || path_join_relative(target, sizeof(target), base, rel)) {
snprintf(error, error_size, "invalid path");
@@ -130,10 +127,7 @@ check_upload_manifest_space(const char *base, const char *rels,
goto done;
}
if(overwrite && !lstat(target, &st) && S_ISREG(st.st_mode) && st.st_size > 0) {
reclaim = (unsigned long long)st.st_size;
}
available = available - size + reclaim;
available -= size;
rel = strtok_r(NULL, "\n", &rel_save);
size_text = strtok_r(NULL, "\n", &size_save);
@@ -188,9 +182,7 @@ api_upload_prepare(struct MHD_Connection *conn, const char *body,
}
pthread_mutex_unlock(&g_tasks_lock);
if(check_upload_manifest_space(path, rels, sizes,
overwrite && !strcmp(overwrite, "1"),
total, error, sizeof(error),
if(check_upload_manifest_space(path, rels, sizes, total, error, sizeof(error),
code, sizeof(code), arg, sizeof(arg))) {
free_task(task);
free(path); free(src); free(total_text); free(count_text);