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
impl Storage
pub fn id(&self) -> StorageId
Sourcepub fn info(&self) -> &StorageInfo
pub fn info(&self) -> &StorageInfo
Storage information (cached, call refresh() to update).
Sourcepub async fn refresh(&mut self) -> Result<(), Error>
pub async fn refresh(&mut self) -> Result<(), Error>
Refresh storage info from device (updates free space, etc.).
Sourcepub async fn list_objects(
&self,
parent: Option<ObjectHandle>,
) -> Result<Vec<ObjectInfo>, Error>
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.
Sourcepub async fn list_objects_with_cancel(
&self,
parent: Option<ObjectHandle>,
cancel: Option<&CancelToken>,
) -> Result<Vec<ObjectInfo>, Error>
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.
Sourcepub async fn collect_objects(
&self,
parent: Option<ObjectHandle>,
) -> Result<ObjectCollection, Error>
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:
- The handle list is already in hand, so the folder’s membership isn’t in doubt, only one entry’s metadata.
- The failing operation is read-only, so nothing on the device changed.
- 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.
Sourcepub async fn collect_objects_with_cancel(
&self,
parent: Option<ObjectHandle>,
cancel: Option<&CancelToken>,
) -> Result<ObjectCollection, Error>
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.
Sourcepub async fn list_objects_stream(
&self,
parent: Option<ObjectHandle>,
) -> Result<ObjectListing, Error>
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);
}
}Sourcepub async fn list_objects_stream_with_cancel(
&self,
parent: Option<ObjectHandle>,
cancel: Option<&CancelToken>,
) -> Result<ObjectListing, Error>
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.
Sourcepub async fn list_objects_recursive(
&self,
parent: Option<ObjectHandle>,
) -> Result<Vec<ObjectInfo>, Error>
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.
Sourcepub async fn collect_objects_recursive(
&self,
parent: Option<ObjectHandle>,
) -> Result<ObjectCollection, Error>
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.
Sourcepub async fn get_object_info(
&self,
handle: ObjectHandle,
) -> Result<ObjectInfo, Error>
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.
Sourcepub async fn download_to_vec(
&self,
handle: ObjectHandle,
) -> Result<Vec<u8>, Error>
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.
Sourcepub async fn read_range(
&self,
handle: ObjectHandle,
offset: u64,
len: u32,
) -> Result<Vec<u8>, Error>
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.
Sourcepub async fn thumbnail(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error>
pub async fn thumbnail(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error>
Fetch the thumbnail image bytes for an object.
Sourcepub async fn download(
&self,
handle: ObjectHandle,
range: ByteRange,
) -> Result<FileDownload, Error>
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.
Sourcepub async fn download_windowed(
&self,
handle: ObjectHandle,
range: ByteRange,
window_size: u32,
) -> Result<WindowedDownload, Error>
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.
Sourcepub async fn download_windowed_default(
&self,
handle: ObjectHandle,
) -> Result<WindowedDownload, Error>
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.
Sourcepub async fn upload<'a, S>(
&'a self,
parent: Option<ObjectHandle>,
info: NewObjectInfo,
data: S,
) -> Result<ObjectHandle, UploadError>
pub async fn upload<'a, S>( &'a self, parent: Option<ObjectHandle>, info: NewObjectInfo, data: S, ) -> Result<ObjectHandle, UploadError>
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.
Sourcepub async fn upload_with_progress<'a, S, F>(
&'a self,
parent: Option<ObjectHandle>,
info: NewObjectInfo,
data: S,
on_progress: F,
) -> Result<ObjectHandle, UploadError>
pub async fn upload_with_progress<'a, S, F>( &'a self, parent: Option<ObjectHandle>, info: NewObjectInfo, data: S, on_progress: F, ) -> Result<ObjectHandle, UploadError>
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).
pub async fn create_folder( &self, parent: Option<ObjectHandle>, name: &str, ) -> Result<ObjectHandle, Error>
pub async fn delete(&self, handle: ObjectHandle) -> Result<(), Error>
Sourcepub async fn delete_with_cancel(
&self,
handle: ObjectHandle,
cancel: Option<&CancelToken>,
) -> Result<(), Error>
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.
Sourcepub async fn move_object(
&self,
handle: ObjectHandle,
new_parent: ObjectHandle,
new_storage: Option<StorageId>,
) -> Result<(), Error>
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).