Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions src/lib/openFolder.js
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,27 @@ function execOperation(type, action, url, $target, name) {
return;
}

// Prevent pasting a folder into itself or its subdirectories
if (helpers.isDir(clipBoard.$el.dataset.type)) {
const sourceUrl = Url.parse(clipBoard.url).url;
const targetUrl = Url.parse(url).url;

// Check if trying to paste folder into itself
if (sourceUrl === targetUrl) {
alert(strings.warning, "Cannot paste a folder into itself");
return;
}

// Check if trying to paste folder into one of its subdirectories
if (
targetUrl.startsWith(sourceUrl + "/") ||
targetUrl.startsWith(sourceUrl + "\\")
) {
alert(strings.warning, "Cannot paste a folder into its subdirectory");
return;
}
}

let CASE = "";
const $src = clipBoard.$el;
const srcType = $src.dataset.type;
Expand Down Expand Up @@ -559,8 +580,47 @@ function execOperation(type, action, url, $target, name) {
if (!confirmation) return;
}
let newUrl;
if (clipBoard.action === "cut") newUrl = await fs.moveTo(url);
else newUrl = await fs.copyTo(url);
if (clipBoard.action === "cut") {
// Special handling for Termux SAF folders - move manually due to SAF limitations
if (
clipBoard.url.startsWith("content://com.termux.documents/tree/") &&
IS_DIR
) {
const moveRecursively = async (sourceUrl, targetParentUrl) => {
const sourceFs = fsOperation(sourceUrl);
const sourceName = Url.basename(sourceUrl);
const targetUrl = Url.join(targetParentUrl, sourceName);

// Create target folder
await fsOperation(targetParentUrl).createDirectory(sourceName);

// Get all entries in source folder
const entries = await sourceFs.lsDir();

// Move all files and folders recursively
for (const entry of entries) {
if (entry.isDirectory) {
await moveRecursively(entry.url, targetUrl);
} else {
const fileContent = await fsOperation(entry.url).readFile();
const fileName = entry.name || Url.basename(entry.url);
await fsOperation(targetUrl).createFile(fileName, fileContent);
await fsOperation(entry.url).delete();
}
}

// Delete the now-empty source folder
await sourceFs.delete();
return targetUrl;
};

newUrl = await moveRecursively(clipBoard.url, url);
} else {
newUrl = await fs.moveTo(url);
}
} else {
newUrl = await fs.copyTo(url);
}
const { name: newName } = await fsOperation(newUrl).stat();
stopLoading();
/**
Expand Down
43 changes: 38 additions & 5 deletions src/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,12 +396,45 @@ export default {
currentUri.includes("com.termux.documents")
)
) {
if (isFile) {
uri = await fsOperation(uri).createFile(pathString);
} else {
uri = await fsOperation(uri).createDirectory(pathString);
// Handle nested paths for regular file:// URIs
const pathParts = pathString.split("/").filter(Boolean);
let currentPath = uri;
let firstCreatedPath = null;
let firstCreatedType = null;

for (let i = 0; i < pathParts.length; i++) {
const isLastPart = i === pathParts.length - 1;
const partName = pathParts[i];
const newPath = Url.join(currentPath, partName);

if (isLastPart && isFile) {
// Create file if it's the last part and we're creating a file
if (!(await fsOperation(newPath).exists())) {
await fsOperation(currentPath).createFile(partName);
if (firstCreatedPath === null) {
firstCreatedPath = newPath;
firstCreatedType = "file";
}
}
} else {
// Create directory for intermediate parts or when creating a folder
if (!(await fsOperation(newPath).exists())) {
await fsOperation(currentPath).createDirectory(partName);
if (firstCreatedPath === null) {
firstCreatedPath = newPath;
firstCreatedType = "folder";
}
}
}
currentPath = newPath;
}
return { uri: uri, type: isFile ? "file" : "folder" };

return {
uri: firstCreatedPath || Url.join(uri, pathParts[0]),
type:
firstCreatedType ||
(isFile && pathParts.length === 1 ? "file" : "folder"),
};
}

for (let i = 0; i < parts.length; i++) {
Expand Down