Repository navigation
feat(terminal): upload files into selected distro - #40
mohit-kota wants to merge 3 commits into
Conversation
| internal fun safeFileName(sourceName: String?): String { | ||
| val sanitized = | ||
| sourceName | ||
| .orEmpty() | ||
| .substringAfterLast('/') | ||
| .substringAfterLast('\\') | ||
| .map { character -> | ||
| if (character.code < 32 || character.code == 127) '_' else character | ||
| }.joinToString("") | ||
| .trim() | ||
| .take(MAX_FILE_NAME_CHARS) | ||
| return sanitized.takeUnless { it.isBlank() || it == "." || it == ".." } ?: "upload" | ||
| } |
There was a problem hiding this comment.
Any specific reason MAX_FILE_NAME_CHARS is set? I think there is no need to trim the file names
There was a problem hiding this comment.
This implementation needs rewriting. Here, the import resolves the absolute path of rootfs / then proceeds to consider home as /root. If it does exist, then fall backs to / but at the end returns ~/Uploads/$fileName?
Here, the user can be logged in as any user; the return ~/ resolves to the home path of the currently logged-in user, which is not one of the possible places where this function stores the file, so unless the user is root and has /root the return would be invalid.
| check(!Files.exists(destination, LinkOption.NOFOLLOW_LINKS)) { | ||
| "~/Uploads/$fileName already exists" | ||
| } |
There was a problem hiding this comment.
The check for an existing file is done only before the part upload; this does not guarantee that it won't exist or will be created in between the time when files are being copied from Android to the Linux path and moved to Uploads path.
Description
What does this PR do?
Adds a visible Upload file action to the active terminal toolbar. The action opens Android’s system document picker and copies one selected file into
~/Uploadsinside the Linux distro associated with the terminal that initiated the upload.The upload runs outside the UI thread, displays progress and success/failure feedback, creates imported files with
0600permissions, avoids overwriting existing files, and removes incomplete files after normal I/O failures.Why is this change necessary?
Users need a simple way to import scripts, PEM files, configuration files, archives, and other files already stored on their Android device. Previously this required downloading the file again or using a separate transfer mechanism.
The initiating terminal’s root filesystem is captured before the picker opens, so switching tabs while choosing a file cannot redirect the upload into another distro.
Closes #37
Behavior and scope
This PR intentionally supports one file per upload. Folder uploads, batch uploads, exports, and a full file manager remain out of scope.
Reviewer guide
Suggested review order:
TerminalFileImporter.kt— filename handling, permissions, collision behavior, and safe copyMainActivity.kt— document picker, captured distro target, and background executionTerminalPage.kt— visible upload action, progress indicator, and result messageTerminalFileImporterTest.kt— isolation, cleanup, permissions, and overwrite protectionNo new dependency, Android storage permission, service, or cross-distro mount is introduced.
How Has This Been Tested?
Automated Tests
./gradlew :app:testDebugUnitTest :app:lintDebug0600permissions, failed-copy cleanup, and overwrite protection.Manual Verification
udroid-upload-test.shthrough Android DocumentsUI~/Uploads-rw-------Screenshots
Checklist