From 3cfb5ededbf482732b2337d82b5e05f96fc898de Mon Sep 17 00:00:00 2001 From: Agando Date: Fri, 23 Oct 2026 15:28:57 +0200 Subject: fix(newos4): define VirtualFS.emptyTrash() — empty-trash threw since 2026-10-18 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Report RPT-20261018-164646-89352963 ("this.fs.emptyTrash is not a function") was filed by the auto-filer and never fixed: terminal.js:1777 called a method VirtualFS never defined, so 'empty-trash --confirm' threw instead of emptying. Added emptyTrash() returning true only when it removed something. Verified live on v4.6.54: put -> rm -> empty-trash --confirm => 'Trash emptied.'; second run => 'Trash is already empty.'; .trash entries 0. --- modules/core/core-bundle.js | 13 +++++++++++++ modules/core/module-loader.js | 2 +- modules/core/virtual-fs.js | 27 +++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) (limited to 'modules/core') diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js index 331e090..212573d 100644 --- a/modules/core/core-bundle.js +++ b/modules/core/core-bundle.js @@ -632,6 +632,19 @@ class VirtualFileSystem { } return false; } + // Reported 2026-10-18 ("this.fs.emptyTrash is not a function") and verified 2026-10-23: + // terminal.js:1777 called this method but nothing ever defined it, so `empty-trash --confirm` + // threw instead of emptying. Returns true only when something was actually removed. + emptyTrash() { + const trash = this.root.content && this.root.content['.trash']; + if (!trash || !trash.content) return false; + const names = Object.keys(trash.content); + if (!names.length) return false; + names.forEach(n => { delete trash.content[n]; }); + this.saveToStorage(); + this._emitChange('/.trash'); + return true; + } _pruneTrash(maxEntries = 50) { // Bounded trash: deletions are moves-to-trash, so without a cap / .trash/ was an // unbounded second accumulator. Names start with a millis timestamp → sort = oldest first. diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js index f22576a..a3b3a6f 100644 --- a/modules/core/module-loader.js +++ b/modules/core/module-loader.js @@ -4,7 +4,7 @@ // Core module bundle loaded synchronously in main.html. // This loader only handles version cache-busting, splash, terminal init, and optional ext modules. - const LATEST_VER = 'v4.6.53'; + const LATEST_VER = 'v4.6.54'; const CACHE = '?v=' + LATEST_VER; const stored = localStorage.getItem('webx11_cache_ver'); if (stored !== LATEST_VER) { diff --git a/modules/core/virtual-fs.js b/modules/core/virtual-fs.js index 8f11d25..c9eb7a3 100644 --- a/modules/core/virtual-fs.js +++ b/modules/core/virtual-fs.js @@ -595,6 +595,7 @@ class VirtualFileSystem { const trash = this.root.content['.trash']; const trashName = ts + '-' + name; trash.content[trashName] = JSON.parse(JSON.stringify(node)); + this._pruneTrash(); const resolved = this._resolvePath(path); if (resolved) delete resolved.dir.content[resolved.name]; this.saveToStorage(); @@ -620,6 +621,7 @@ class VirtualFileSystem { let ctr = 0; while (trash.content[unique]) { unique = baseName + '-' + (++ctr); } trash.content[unique] = JSON.parse(JSON.stringify(node)); + this._pruneTrash(); delete resolved.dir.content[resolved.name]; this.saveToStorage(); this._emitChange(path); @@ -628,6 +630,31 @@ class VirtualFileSystem { } return false; } + // Reported 2026-10-18 ("this.fs.emptyTrash is not a function") and verified 2026-10-23: + // terminal.js:1777 called this method but nothing ever defined it, so `empty-trash --confirm` + // threw instead of emptying. Returns true only when something was actually removed. + emptyTrash() { + const trash = this.root.content && this.root.content['.trash']; + if (!trash || !trash.content) return false; + const names = Object.keys(trash.content); + if (!names.length) return false; + names.forEach(n => { delete trash.content[n]; }); + this.saveToStorage(); + this._emitChange('/.trash'); + return true; + } + _pruneTrash(maxEntries = 50) { + // Bounded trash: deletions are moves-to-trash, so without a cap / .trash/ was an + // unbounded second accumulator. Names start with a millis timestamp → sort = oldest first. + const trash = this.root.content['.trash']; + if (!trash) return 0; + const keys = Object.keys(trash.content); + if (keys.length <= maxEntries) return 0; + keys.sort(); + const drop = keys.slice(0, keys.length - maxEntries); + drop.forEach(k => { delete trash.content[k]; }); + return drop.length; + } deleteDirRecursive(path) { return this.trashDir(path); } -- cgit v1.2.3