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 (auto name(2)) / Cancel; Remember choice checkbox makes the action sticky for the batch; New / Existing rows 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_Object directly — no host roundtrip; transparent fallback to host-mediated download → upload if 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_Filetypes per session and routes uploads to a filetype the device accepts (Sony Xperia rejects Undefined; 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).

FlagDefaultEffect
-DMTP_SYSTEM_LIBUSBONON → link system libusb-1.0 (Debian/Ubuntu policy); OFF → vendored static
-DMTP_SYSTEM_LIBMTPOFFON → 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=NOskip 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

  1. Open from Alt+F1 / Alt+F2 → MTP.
  2. Pick a device, press Enter — opens the storage list (single-storage devices skip this and jump straight to the file view).
  3. Navigate folders, copy/move/delete with standard keys.
  4. Shift+F5 in-place copy: prompts for a new name with the full storage path prefilled; multi-select auto-suffixes .copy.
  5. Shift+F6 rename: same prompt; type ../ or ./sub/ to also move.
  6. Cross-panel F5/F6 between two MTP panels on the same device uses Copy_Object / Move_Object directly — no host roundtrip.
  7. 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

KeyAction
EnterEnter directory / connect to device
..Up; on storage root → device selector; on selector → close plugin
F3View file (downloaded to temp, chmod 0644)
F5 / F6Copy / Move (host↔device or same-device)
Shift+F5In-place copy with prompt (rename or relocate)
Shift+F6Rename / move with prompt
F7Make directory
F8Delete
EscAbort current transfer
F10Close 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.