far2l MTP plugin
May 26, 2026 · View on GitHub
Browse and manage files on MTP-class devices (Android, cameras, media players) over USB.
Features
- Auto-detect connected MTP devices; enumerate manufacturer, product, serial
- Two-level navigation: device → storage → folders/files
- F3/F5/F6/F7/F8 — view, copy, move, mkdir, delete (progress + Esc-abort)
- Shared progress dialog with byte and total bars; debounced repaints
- Overwrite dialog —
Overwrite/Skip/Newer(mtime gate) /Rename(autoname(2)) /Cancel;Remember choicecheckbox makes the action sticky for the batch;New/Existingrows show size + mtime and open the corresponding file in the viewer when clicked - Cross-panel F5/F6 between two MTP panels on the same device uses libmtp's
Copy_Object/Move_Objectdirectly — no host roundtrip; transparent fallback to host-mediateddownload → uploadif the responder rejects - Unified destination prompt for Shift+F5 / Shift+F6 / cross-panel F5 / F6 — accepts a basename, relative path (
./sub/,../), or storage-relative path (Internal/Temp/foo) - Capability-driven (no vendor/product tables): plugin queries
Check_Capability+Get_Supported_Filetypesper session and routes uploads to a filetype the device accepts (Sony Xperia rejectsUndefined; the plugin picks a neutral advertised type instead) - Galaxy "blank-filename for new objects" quirk patched via a session-wide
{handle: name}cache
Build
From the far2l build directory:
cmake --build . --target mtp
Output: install/Plugins/mtp/plug/mtp.far-plug-wide plus language and help files.
Library linkage
libmtp 1.1.23 and libusb 1.0.30 are vendored under mtp/libmtp/ and mtp/libusb/ (refresh: mtp/libusb/VENDORING.md).
| Flag | Default | Effect |
|---|---|---|
-DMTP_SYSTEM_LIBUSB | ON | ON → link system libusb-1.0 (Debian/Ubuntu policy); OFF → vendored static |
-DMTP_SYSTEM_LIBMTP | OFF | ON → link system libmtp; disables the fast depth-1 listing (libmtp's internal PTP symbols are hidden by libmtp.sym), enumeration falls back to per-handle |
-DMTP=NO | — | skip plugin |
Missing pkg-config libs → plugin is skipped with a WARNING ("install libusb-1.0-0-dev" / "install libmtp-dev"). MTP_SYSTEM_LIBMTP=ON requires MTP_SYSTEM_LIBUSB=ON (otherwise two libusb instances in one process).
Install
Copy install/Plugins/mtp/ into far2l's Plugins folder:
- macOS:
/Applications/far2l.app/Contents/MacOS/Plugins/ - Linux (system):
/usr/lib/far2l/Plugins/ - Linux (user):
~/.local/lib/far2l/Plugins/
Restart far2l. The plugin appears in Alt+F1 / Alt+F2 → MTP.
Prerequisites
Linux
User must be in the plugdev group (or equivalent) for non-root USB access. If libmtp is installed system-wide, its udev rules cover MTP/PTP device permissions; otherwise copy a ruleset from upstream libmtp's udev-rules/ (also vendored under mtp/libmtp/).
Hotplug events use the kernel netlink uevent socket (libusb built with --disable-udev semantics) — no libudev dependency.
macOS
The system icdd (Image Capture daemon) and ptpcamerad claim MTP-class devices on plug-in with kIOUSBExclusiveAccess, blocking libmtp's open. The plugin works around this automatically: writes the per-device "Connecting this device opens: No application" preference, then SIGKILLs icdd / mscamerad-xpc / ptpcamerad so launchd's respawn picks up the new preference and skips the claim. No GUI step or sudo required.
Set MTP_NO_ICDD_BYPASS=1 to disable the bypass.
Device
Connect via USB, unlock the device, switch USB mode to File transfer (MTP). Some devices show an "Allow file transfer" prompt the first time — accept it. Until accepted, listings may be empty and uploads may fail with 0x2002; the plugin's Get_Storage retry loop covers the few seconds before the user taps.
Usage
- Open from Alt+F1 / Alt+F2 → MTP.
- Pick a device, press Enter — opens the storage list (single-storage devices skip this and jump straight to the file view).
- Navigate folders, copy/move/delete with standard keys.
- Shift+F5 in-place copy: prompts for a new name with the full storage path prefilled; multi-select auto-suffixes
.copy. - Shift+F6 rename: same prompt; type
../or./sub/to also move. - Cross-panel F5/F6 between two MTP panels on the same device uses
Copy_Object/Move_Objectdirectly — no host roundtrip. - Drives menu (Alt+F1 / Alt+F2 → "Other panel" entry) — when one panel is already on MTP, picking the suggested
{/Storage/Path}on the other panel adopts the same device automatically and navigates to that path; no need to re-pick the device.
Key bindings
| Key | Action |
|---|---|
| Enter | Enter directory / connect to device |
.. | Up; on storage root → device selector; on selector → close plugin |
| F3 | View file (downloaded to temp, chmod 0644) |
| F5 / F6 | Copy / Move (host↔device or same-device) |
| Shift+F5 | In-place copy with prompt (rename or relocate) |
| Shift+F6 | Rename / move with prompt |
| F7 | Make directory |
| F8 | Delete |
| Esc | Abort current transfer |
| F10 | Close plugin |
Localization
All user-visible strings (panel titles, column headers, dialog titles, buttons, progress labels, error pop-ups, confirmations) go through GetMsg() and ship in English (mtpEng.lng) and Russian (mtpRus.lng); the active language follows far2l's UI language. Help files (.hlf) are also localized — pressing F1 in the plugin shows Russian help under Russian far2l. To add a language: copy mtpEng.lng to mtp<XX>.lng, translate the strings, keep the line order; same for the .hlf.
Diagnostics
Plugin-side logs (mtp.log) and libmtp wire traces (mtp_libmtp.log) land next to the plugin binary. In Debug builds (-DCMAKE_BUILD_TYPE=Debug) both files are written by default with USB+PTP traces. In Release builds nothing is logged — set MTP_LIBMTP_DEBUG=usb,ptp (or all, data, etc.) before launching far2l to enable.