From 5f72db1db4b1c612ef1d7054ec34129c2fa61049 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 12 Aug 2026 17:11:50 -0700 Subject: [PATCH] fix: stop drops onto a not-yet-created folder row from mangling files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A row drawn ahead of its mkdir carries a predicted path, but it was still registered as a live drop target. Dropping a file on it called move_items() with a destination that does not exist yet, and move treats a non-existent destination as a rename target — so the dragged file was silently renamed to "New Folder" instead of moving into the folder. Reproduced against a slow mkdir: victim.txt became a 5-byte file named "New Folder". Sit the row out of the jQuery UI droppable (drop and the spring-load hover) until the real fsentry lands, matching the guards already on opening it, its menus and dragging it. The native-file dragster drop gets the same guard: it uploads into the same predicted path. --- src/gui/src/UI/Dashboard/TabFiles.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/gui/src/UI/Dashboard/TabFiles.js b/src/gui/src/UI/Dashboard/TabFiles.js index aee2e56e6..a53cf4de4 100644 --- a/src/gui/src/UI/Dashboard/TabFiles.js +++ b/src/gui/src/UI/Dashboard/TabFiles.js @@ -3046,6 +3046,12 @@ const TabFiles = { _this.folderDwellTimer = null; _this.folderDwellTarget = null; + // A row drawn ahead of its mkdir has a predicted path, not + // a real one. Moving into it would either fail or — because + // move treats a non-existent destination as a rename target + // — quietly rename the dragged file to "New Folder". + if ( isPending() ) return; + const draggedPath = $(ui.draggable).attr('data-path'); if ( event.ctrlKey && draggedPath?.startsWith(`${window.trash_path}/`) ) { return; @@ -3086,6 +3092,11 @@ const TabFiles = { over: function (_event, ui) { if ( $(ui.draggable).hasClass('row') ) { + // Still waiting on mkdir: don't offer it as a drop + // target, and don't spring-load into a path that may + // not exist yet (see the drop handler above). + if ( isPending() ) return; + $(el_item).addClass('selected'); const _this = TabFiles; @@ -3149,6 +3160,7 @@ const TabFiles = { if ( ! e.dataTransfer?.types?.includes('Files') ) { return; } + if ( isPending() ) return; const targetPath = $(el_item).attr('data-path'); @@ -3172,6 +3184,7 @@ const TabFiles = { if ( ! e.dataTransfer?.types?.includes('Files') ) { return; } + if ( isPending() ) return; const targetPath = $(el_item).attr('data-path');