Skip to main content

Storage

Struct Storage 

Source
pub struct Storage { /* private fields */ }
Expand description

A storage location on an MTP device.

Storage holds a shared reference to the active backend so it can outlive the original MtpDevice and be used from multiple tasks.

Implementations§

Source§

impl Storage

Source

pub fn id(&self) -> StorageId

Source

pub fn info(&self) -> &StorageInfo

Storage information (cached, call refresh() to update).

Source

pub async fn refresh(&mut self) -> Result<(), Error>

Refresh storage info from device (updates free space, etc.).

Source

pub async fn list_objects( &self, parent: Option<ObjectHandle>, ) -> Result<Vec<ObjectInfo>, Error>

List objects in a folder (None = root), returning all results at once.

For progress reporting during large listings, use list_objects_stream() instead.

The backend handles device quirks (root-listing fast path and Android/Samsung/Fuji fallbacks).

A narrowly tolerated per-object metadata rejection does not hide valid siblings. Use collect_objects to retain its handle and diagnostic, or the streaming API to observe every item error directly. All errors that can compromise enumeration or session integrity remain fatal.

Source

pub async fn list_objects_with_cancel( &self, parent: Option<ObjectHandle>, cancel: Option<&CancelToken>, ) -> Result<Vec<ObjectInfo>, Error>

Like list_objects, but takes a cooperative cancellation token.

When cancel is Some(&token) and the token has been cancelled, the call bails between per-handle fetches with Err(Error::Cancelled). Useful for large folders (1k+ entries on Android), where the per-handle loop dominates wall-clock time.

Source

pub async fn collect_objects( &self, parent: Option<ObjectHandle>, ) -> Result<ObjectCollection, Error>

Read a folder, keeping both the objects and a record of the handles that couldn’t be read.

list_objects is the same read with the record thrown away. Use this one when you need to tell “the folder has 49 files” from “the folder has 49 files and a 50th we couldn’t see”, which is the difference between a correct file listing and a silent omission.

§What counts as skippable

A per-handle failure may be skipped only when all three hold:

  1. The handle list is already in hand, so the folder’s membership isn’t in doubt, only one entry’s metadata.
  2. The failing operation is read-only, so nothing on the device changed.
  3. The device answered with a protocol response code, which closes that transaction cleanly and leaves the session usable for the next handle.

Today exactly one case qualifies: a GeneralError response to GetObjectInfo (Sphaira on the Nintendo Switch does this for one handle out of 50). The rule is written down rather than the code, so adding a second response code is a one-line change once a real device justifies it. Nothing gets added speculatively.

Everything else stays fatal: transport and session failures, malformed responses, cancellation, stale handles, and any failure to enumerate the handles in the first place. And if every handle was skipped, that’s a device that answered nothing, so this reports the failure rather than an empty folder.

Source

pub async fn collect_objects_with_cancel( &self, parent: Option<ObjectHandle>, cancel: Option<&CancelToken>, ) -> Result<ObjectCollection, Error>

Like collect_objects, but with a cooperative cancellation token.

Source

pub async fn list_objects_stream( &self, parent: Option<ObjectHandle>, ) -> Result<ObjectListing, Error>

List objects in a folder as a streaming ObjectListing.

Returns immediately after the device returns the handle list. The total count is then known via ObjectListing::total(), and each call to ObjectListing::next() fetches one object’s metadata.

§Example
use mtp_rs::mtp::{ListingItem, MtpDevice};

let mut listing = storage.list_objects_stream(None).await?;
println!("Found {} items", listing.total());

while let Some(item) = listing.next().await {
    if let ListingItem::Object(info) = item? {
        println!("[{}/{}] {}", listing.fetched(), listing.total(), info.filename);
    }
}
Source

pub async fn list_objects_stream_with_cancel( &self, parent: Option<ObjectHandle>, cancel: Option<&CancelToken>, ) -> Result<ObjectListing, Error>

Like list_objects_stream, but the returned ObjectListing carries an optional CancelToken. Every call to ObjectListing::next checks the token before issuing the next metadata roundtrip, so a flipped token bails within one roundtrip’s worth of latency instead of running to completion.

Source

pub async fn list_objects_recursive( &self, parent: Option<ObjectHandle>, ) -> Result<Vec<ObjectInfo>, Error>

List objects recursively.

Walks the folder tree manually via collect_objects, which already applies the backend’s root/quirk handling. Works the same across all devices, including Android (whose native GetObjectHandles recursion is broken).

Unreadable handles are dropped. Over a whole tree that can add up quietly, so use collect_objects_recursive when you need to know.

Source

pub async fn collect_objects_recursive( &self, parent: Option<ObjectHandle>, ) -> Result<ObjectCollection, Error>

Walk a folder tree, keeping both the objects and every handle that couldn’t be read.

The recursive counterpart of collect_objects. One unreadable object per folder is easy to shrug off; across a few thousand folders it’s a silent omission nobody notices, so the skips are aggregated across the whole walk rather than dropped per folder.

Source

pub async fn get_object_info( &self, handle: ObjectHandle, ) -> Result<ObjectInfo, Error>

Get object metadata by handle.

Files larger than 4 GB have their u64 size auto-resolved by the backend.

Source

pub async fn download_to_vec( &self, handle: ObjectHandle, ) -> Result<Vec<u8>, Error>

Download a whole file and return all bytes.

For small to medium files where you want all the data in memory. For large files or streaming to disk, use download.

Source

pub async fn read_range( &self, handle: ObjectHandle, offset: u64, len: u32, ) -> Result<Vec<u8>, Error>

Read a bounded byte range into a Vec<u8> (single shot, buffered).

Uses the device’s 64-bit partial-read operation, so offsets beyond 4 GB work on devices that advertise it. len is capped at u32::MAX per call.

Source

pub async fn thumbnail(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error>

Fetch the thumbnail image bytes for an object.

Source

pub async fn download( &self, handle: ObjectHandle, range: ByteRange, ) -> Result<FileDownload, Error>

Download a file as a stream (true streaming), holding the session for the whole file.

Yields data chunks as they arrive without buffering the entire file in memory. This is the raw-speed path; it holds the device’s one session open for the whole file (see download docs). For a long read where the device must stay responsive to other work, use download_windowed instead.

§Resume on forward-only-seek devices

A ByteRange::From/ByteRange::Range resume assumes the device can seek to the offset cheaply. The Windows WPD backend’s Pixel-class devices return E_NOTIMPL from IStream::Seek, so the backend reaches the offset by reading and discarding the prefix: a resume is O(offset) and re-streams every byte before the offset. Resuming near the end of a large file re-reads almost the whole file, so prefer a single in-order pass over many small offset resumes there.

Source

pub async fn download_windowed( &self, handle: ObjectHandle, range: ByteRange, window_size: u32, ) -> Result<WindowedDownload, Error>

Read a large file as a sequence of bounded windows, freeing the session between every window so the device stays responsive.

Each next_window() is a single bounded read that completes and releases the device. Between two next_window() calls a consumer can interleave other device work (service a pending folder listing, navigate, check a cancel flag) without aborting the read.

window_size is the maximum bytes per window. DEFAULT_DOWNLOAD_WINDOW (8 MiB) is a documented suggestion; a window_size of 0 is clamped to 1.

§Resume on forward-only-seek devices

A windowed resume from an offset (ByteRange::From/Range) re-reads the skipped prefix on devices whose IStream::Seek is E_NOTIMPL (the Windows WPD backend’s Pixel-class devices), making the first window after the offset O(offset). The session-freeing benefit between windows still holds, but starting deep into a large file pays a full re-read of the prefix first; prefer covering the file from the start (ByteRange::Full) where possible.

Source

pub async fn download_windowed_default( &self, handle: ObjectHandle, ) -> Result<WindowedDownload, Error>

Read a large file in windows using the default window size (DEFAULT_DOWNLOAD_WINDOW, 8 MiB), covering the whole file.

Source

pub async fn upload<'a, S>( &'a self, parent: Option<ObjectHandle>, info: NewObjectInfo, data: S, ) -> Result<ObjectHandle, UploadError>
where S: Stream<Item = Result<Bytes, Error>> + Unpin + Send + 'a,

Upload a file from a stream.

The data streams directly to the device in chunks; the protocol only needs the total size upfront (provided via info), not the whole file in memory.

§Errors

Returns UploadError on failure. Uploads are two-phase: the object is created (yielding a handle), then the bytes are streamed. If the data phase fails, the device may keep a partial object, and UploadError::partial carries its handle so you can delete it or retry the data phase to resume. The library does not auto-delete it.

Source

pub async fn upload_with_progress<'a, S, F>( &'a self, parent: Option<ObjectHandle>, info: NewObjectInfo, data: S, on_progress: F, ) -> Result<ObjectHandle, UploadError>
where S: Stream<Item = Result<Bytes, Error>> + Unpin + Send + 'a, F: FnMut(Progress) -> ControlFlow<()> + Send + 'a,

Upload a file with a progress callback.

Progress is reported as data is read from the stream. Return ControlFlow::Break(()) from the callback to cancel the upload (which surfaces as Error::Cancelled in UploadError::source).

Source

pub async fn create_folder( &self, parent: Option<ObjectHandle>, name: &str, ) -> Result<ObjectHandle, Error>

Source

pub async fn delete(&self, handle: ObjectHandle) -> Result<(), Error>

Source

pub async fn delete_with_cancel( &self, handle: ObjectHandle, cancel: Option<&CancelToken>, ) -> Result<(), Error>

Like delete, but bails with Err(Error::Cancelled) before issuing the delete request when the token is set.

Source

pub async fn move_object( &self, handle: ObjectHandle, new_parent: ObjectHandle, new_storage: Option<StorageId>, ) -> Result<(), Error>

Move an object to a different folder (optionally a different storage).

Source

pub async fn copy_object( &self, handle: ObjectHandle, new_parent: ObjectHandle, new_storage: Option<StorageId>, ) -> Result<ObjectHandle, Error>

Source

pub async fn rename( &self, handle: ObjectHandle, new_name: &str, ) -> Result<(), Error>

Rename an object (file or folder).

Not all devices support renaming. Use MtpDevice::supports_rename() to check.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more