pub struct Storage { /* private fields */ }Expand description
A storage location on an MTP device.
Storage holds an Arc<MtpDeviceInner> 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.
This method handles various device quirks:
- Root listing tries parent=0xFFFFFFFF first (fast path for Android, Kindle, etc.)
- Falls back to parent=0 only when the device rejects 0xFFFFFFFF
- Samsung devices: return InvalidObjectHandle for parent=0, so we fall back to recursive
- Fuji devices: return all objects for root, so we filter by parent handle
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
GetObjectInfo per-handle loop dominates wall-clock time.
Pass None for backwards-compatible behavior identical to
list_objects.
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 GetObjectHandles completes. The total count
is then known via ObjectListing::total(), and each call to
ObjectListing::next() fetches one object’s metadata from USB.
For root listings (parent=None), tries parent=0xFFFFFFFF first — this
returns only root-level handles on Android, Kindle, and many other devices.
Falls back to parent=0 only when the device rejects 0xFFFFFFFF with an
error. An empty result from 0xFFFFFFFF is treated as an empty storage,
not as a reason to fall back.
This enables progress reporting (e.g., “Loading 42 of 500…”) during
what would otherwise be a single blocking list_objects() call.
Handles the same device quirks as list_objects().
§Example
use mtp_rs::mtp::MtpDevice;
let mut listing = storage.list_objects_stream(None).await?;
println!("Found {} items", listing.total());
while let Some(result) = listing.next().await {
let info = result?;
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
GetObjectInfo USB 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.
This method automatically detects Android devices and uses manual traversal
for them, since Android’s MTP implementation doesn’t support the native
ObjectHandle::ALL recursive listing.
For non-Android devices, it tries native recursive listing first and falls back to manual traversal if the results look incomplete.
Sourcepub async fn list_objects_recursive_native(
&self,
parent: Option<ObjectHandle>,
) -> Result<Vec<ObjectInfo>, Error>
pub async fn list_objects_recursive_native( &self, parent: Option<ObjectHandle>, ) -> Result<Vec<ObjectInfo>, Error>
List objects recursively using native MTP recursive listing.
Sourcepub async fn list_objects_recursive_manual(
&self,
parent: Option<ObjectHandle>,
) -> Result<Vec<ObjectInfo>, Error>
pub async fn list_objects_recursive_manual( &self, parent: Option<ObjectHandle>, ) -> Result<Vec<ObjectInfo>, Error>
List objects recursively using manual folder traversal.
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 via
GetObjectPropValue(ObjectSize); the standard ObjectInfo dataset
only encodes a u32 size which saturates at 4 GB - 1.
Sourcepub async fn download(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error>
pub async fn download(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error>
Download a 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_stream().
Sourcepub async fn download_partial(
&self,
handle: ObjectHandle,
offset: u64,
size: u32,
) -> Result<Vec<u8>, Error>
pub async fn download_partial( &self, handle: ObjectHandle, offset: u64, size: u32, ) -> Result<Vec<u8>, Error>
Download a partial file (byte range).
Uses the standard GetPartialObject operation, which has a 32-bit offset.
Offsets beyond 4 GB will be silently truncated — for files larger than 4 GB,
use download_partial_64() instead.
Sourcepub async fn download_partial_64(
&self,
handle: ObjectHandle,
offset: u64,
size: u32,
) -> Result<Vec<u8>, Error>
pub async fn download_partial_64( &self, handle: ObjectHandle, offset: u64, size: u32, ) -> Result<Vec<u8>, Error>
Download a partial file (byte range) with 64-bit offset support.
Uses the Android/MTP extension GetPartialObject64, which supports offsets
beyond 4 GB. Only works on devices that advertise support for it (most modern
Android devices do); others return OperationNotSupported.
pub async fn download_thumbnail( &self, handle: ObjectHandle, ) -> Result<Vec<u8>, Error>
Sourcepub async fn download_stream(
&self,
handle: ObjectHandle,
) -> Result<FileDownload, Error>
pub async fn download_stream( &self, handle: ObjectHandle, ) -> Result<FileDownload, Error>
Download a file as a stream (true USB streaming).
Unlike download(), this method yields data chunks
directly from USB as they arrive, without buffering the entire file
in memory. Ideal for large files or when piping data to disk.
§Important
The MTP session is locked while the download is active. You must either
consume the entire download or call FileDownload::cancel() before
dropping it.
§Example
use mtp_rs::mtp::MtpDevice;
use mtp_rs::ObjectHandle;
use tokio::io::AsyncWriteExt;
let mut download = storage.download_stream(handle).await?;
println!("Downloading {} bytes...", download.size());
let mut file = tokio::fs::File::create("output.bin").await?;
while let Some(chunk) = download.next_chunk().await {
let bytes = chunk?;
file.write_all(&bytes).await?;
println!("Progress: {:.1}%", download.progress() * 100.0);
}Sourcepub async fn upload<S>(
&self,
parent: Option<ObjectHandle>,
info: NewObjectInfo,
data: S,
) -> Result<ObjectHandle, UploadError>
pub async fn upload<S>( &self, parent: Option<ObjectHandle>, info: NewObjectInfo, data: S, ) -> Result<ObjectHandle, UploadError>
Upload a file from a stream.
The data streams directly to USB in chunks; the protocol only needs the
total size upfront (provided via info), not the whole file in memory.
§Arguments
parent- Parent folder handle (None for root)info- Object metadata including filename and sizedata- Stream of data chunks to upload
§Errors
Returns UploadError on failure. PTP uploads are two-phase:
SendObjectInfo creates the object on the device (yielding a handle),
then SendObject streams the bytes. If the data phase fails, the device
is left holding a partial (possibly empty or truncated) 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. See UploadError for the full contract.
Sourcepub async fn upload_with_progress<S, F>(
&self,
parent: Option<ObjectHandle>,
info: NewObjectInfo,
data: S,
on_progress: F,
) -> Result<ObjectHandle, UploadError>
pub async fn upload_with_progress<S, F>( &self, parent: Option<ObjectHandle>, info: NewObjectInfo, data: S, on_progress: F, ) -> Result<ObjectHandle, UploadError>
Upload a file with progress callback.
Progress is reported as data is read from the stream. Return
ControlFlow::Break(()) from the callback to cancel the upload.
§Errors
Returns UploadError on failure or cancellation. When the failure
happens after the object was created (any error or cancellation during
the data phase), UploadError::partial carries the handle of the
possibly-partial object the device still holds, so you can
delete it or retry the data phase to resume. The library
does not auto-delete it. Cancellation surfaces as
Error::Cancelled in
UploadError::source. See UploadError for the full contract.
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 PTP DeleteObject request when the token is set.
The PTP DeleteObject is a single fast transaction (no internal loop),
so the meaningful cancel point is between recursive iterations on the
caller side. This entry point lets callers thread the same token through
list and delete without juggling two API shapes.
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.