fix: stop drops onto a not-yet-created folder row from mangling files

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.
This commit is contained in:
Nariman Jelveh
2026-08-12 17:11:50 -07:00
parent 62ae2a12f8
commit 5f72db1db4
+13
View File
@@ -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');