libmtp_rs/
storage.rs

1//! Module with `Storage` and `StoragePool` that are able to manage the storage of
2//! an specific device, and perform certain operations like sending and getting
3//! files, tracks, etc.
4
5pub mod files;
6pub mod folders;
7
8use derivative::Derivative;
9use files::{File, FileMetadata};
10use libmtp_sys as ffi;
11use num_derive::FromPrimitive;
12use num_traits::FromPrimitive;
13
14use std::borrow::Cow;
15use std::collections::HashMap;
16use std::ffi::CStr;
17use std::fmt::{self, Debug};
18use std::path::Path;
19
20#[cfg(unix)]
21use std::os::unix::io::AsRawFd;
22
23use crate::device::MtpDevice;
24use crate::object::AsObjectId;
25use crate::storage::folders::Folder;
26use crate::storage::folders::{create_folder, get_folder_list, get_folder_list_storage};
27use crate::util::{CallbackReturn, HandlerReturn};
28use crate::Result;
29
30/// Internal function to retrieve files and folders from a single storage or the whole storage pool.
31fn files_and_folders<'a>(mtpdev: &'a MtpDevice, storage_id: u32, parent: Parent) -> Vec<File<'a>> {
32    let parent_id = parent.faf_id();
33
34    let mut head =
35        unsafe { ffi::LIBMTP_Get_Files_And_Folders(mtpdev.inner, storage_id, parent_id) };
36
37    let mut files = Vec::new();
38    while !head.is_null() {
39        files.push(File {
40            inner: head,
41            owner: mtpdev,
42        });
43
44        head = unsafe { (*head).next };
45    }
46
47    files
48}
49
50/// Represents the parent folder of an object, the top-most parent is called the "root" as in
51/// *nix like systems.
52#[derive(Debug, Copy, Clone)]
53pub enum Parent {
54    Root,
55    Folder(u32),
56}
57
58impl Parent {
59    pub(crate) fn faf_id(self) -> u32 {
60        match self {
61            Parent::Root => ffi::LIBMTP_FILES_AND_FOLDERS_ROOT,
62            Parent::Folder(id) => id,
63        }
64    }
65
66    pub(crate) fn to_id(self) -> u32 {
67        match self {
68            Parent::Root => 0,
69            Parent::Folder(id) => id,
70        }
71    }
72}
73
74#[derive(Debug, Copy, Clone, FromPrimitive)]
75pub enum StorageType {
76    Undefined = 0,
77    FixedRom,
78    RemovableRom,
79    FixedRam,
80    RemovableRam,
81}
82
83#[derive(Debug, Copy, Clone, FromPrimitive)]
84pub enum FilesystemType {
85    Undefined = 0,
86    GenericFlat,
87    GenericHierarchical,
88    DesignCameraFilesystem,
89}
90
91#[derive(Debug, Copy, Clone, FromPrimitive)]
92pub enum AccessCapability {
93    ReadWrite = 0,
94    ReadOnly,
95    ReadOnlyWithObjectDeletion,
96}
97
98/// Storage descriptor of some MTP device, note that updating the storage and
99/// keeping a old copy of this struct is impossible.
100pub struct Storage<'a> {
101    pub(crate) inner: *mut ffi::LIBMTP_devicestorage_t,
102    pub(crate) owner: &'a MtpDevice,
103}
104
105impl Debug for Storage<'_> {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        f.debug_struct("Storage")
108            .field("id", &self.id())
109            .field("storage_type", &self.storage_type())
110            .field("filesystem_type", &self.filesystem_type())
111            .field("access_capability", &self.access_capability())
112            .field("maximum_capacity", &self.maximum_capacity())
113            .field("free_space_in_bytes", &self.free_space_in_bytes())
114            .field("free_space_in_objects", &self.free_space_in_objects())
115            .field("volume_identifier", &self.volume_identifier())
116            .field("description", &self.description())
117            .finish()
118    }
119}
120
121impl<'a> Storage<'a> {
122    /// Retrieves the id of this storage.
123    pub fn id(&self) -> u32 {
124        unsafe { (*self.inner).id }
125    }
126
127    /// Returns the `MtpDevice` that owns this storage
128    pub fn device(&self) -> &MtpDevice {
129        self.owner
130    }
131
132    /// Returns the storage type
133    pub fn storage_type(&self) -> StorageType {
134        let stype = unsafe { (*self.inner).StorageType };
135        StorageType::from_u16(stype).unwrap_or_else(|| StorageType::Undefined)
136    }
137
138    /// Returns the file system type
139    pub fn filesystem_type(&self) -> FilesystemType {
140        let ftype = unsafe { (*self.inner).FilesystemType };
141        FilesystemType::from_u16(ftype).unwrap_or_else(|| FilesystemType::Undefined)
142    }
143
144    /// Returns the access capability
145    pub fn access_capability(&self) -> AccessCapability {
146        let cap = unsafe { (*self.inner).AccessCapability };
147        AccessCapability::from_u16(cap).expect("Unknown access capability")
148    }
149
150    /// Returns the maximum capacity
151    pub fn maximum_capacity(&self) -> u64 {
152        unsafe { (*self.inner).MaxCapacity }
153    }
154
155    /// Returns the free space in bytes
156    pub fn free_space_in_bytes(&self) -> u64 {
157        unsafe { (*self.inner).FreeSpaceInBytes }
158    }
159
160    /// Returns the free space in objects
161    pub fn free_space_in_objects(&self) -> u64 {
162        unsafe { (*self.inner).FreeSpaceInObjects }
163    }
164
165    /// Returns the storage description
166    pub fn description(&self) -> Option<&str> {
167        unsafe {
168            if (*self.inner).StorageDescription.is_null() {
169                None
170            } else {
171                let cstr = CStr::from_ptr((*self.inner).StorageDescription);
172                Some(cstr.to_str().expect("Invalid UTF-8"))
173            }
174        }
175    }
176
177    /// Returns the volume identifier
178    pub fn volume_identifier(&self) -> Option<&str> {
179        unsafe {
180            if (*self.inner).VolumeIdentifier.is_null() {
181                None
182            } else {
183                let cstr = CStr::from_ptr((*self.inner).VolumeIdentifier);
184                Some(cstr.to_str().expect("Invalid UTF-8"))
185            }
186        }
187    }
188
189    /// Formats this storage (if its device supports the operation).
190    ///
191    /// **WARNING:** This **WILL DELETE ALL DATA** from the device, make sure
192    /// you've got confirmation from the user before calling this function.
193    pub fn format_storage(&self) -> Result<()> {
194        let res = unsafe { ffi::LIBMTP_Format_Storage(self.owner.inner, self.inner) };
195
196        if res != 0 {
197            Err(self.owner.latest_error().unwrap_or_default())
198        } else {
199            Ok(())
200        }
201    }
202
203    /// Retrieves the contents of a certain folder (`parent`) in this storage, the result contains
204    /// both files and folders, note that this request will always perform I/O with the device.
205    pub fn files_and_folders(&self, parent: Parent) -> Vec<File<'a>> {
206        let storage_id = unsafe { (*self.inner).id };
207        files_and_folders(self.owner, storage_id, parent)
208    }
209
210    /// Optionally returns a `Folder`, with this struct you can build a tree
211    /// structure (see `Folder` for more info)
212    pub fn folder_list(&self) -> Option<Folder<'a>> {
213        unsafe { get_folder_list_storage(self.owner, (*self.inner).id) }
214    }
215
216    /// Tries to create a new folder in this storage for the relevant `MtpDevice`, returns the id
217    /// of the new folder and its name, note that the name may be different due to device file
218    /// system restrictions.
219    pub fn create_folder<'b>(&self, name: &'b str, parent: Parent) -> Result<(u32, Cow<'b, str>)> {
220        unsafe { create_folder(self.owner, name, parent, (*self.inner).id) }
221    }
222
223    /// Retrieves a file from the device storage to a local file identified by a filename. Note
224    /// that `get_file_to_path` on `Storage` and `StoragePool` are semantically the same because
225    /// objects have unique ids across all the device.
226    pub fn get_file_to_path(&self, file: impl AsObjectId, path: impl AsRef<Path>) -> Result<()> {
227        files::get_file_to_path(self.owner, file, path)
228    }
229
230    /// Retrieves a file from the device storage to a local file identified by a filename. Note
231    /// that `get_file_to_path` on `Storage` and `StoragePool` are semantically the same because
232    /// objects have unique ids across all the device.
233    ///
234    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
235    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
236    /// want to cancel operation you just return `CallbackReturn::Cancel`.
237    pub fn get_file_to_path_with_callback<C>(
238        &self,
239        file: impl AsObjectId,
240        path: impl AsRef<Path>,
241        callback: C,
242    ) -> Result<()>
243    where
244        C: FnMut(u64, u64) -> CallbackReturn,
245    {
246        files::get_file_to_path_with_callback(self.owner, file, path, callback)
247    }
248
249    /// Retrieves a file from the device storage to a local file identified by a descriptor. Note
250    /// that `get_file_to_descriptor` on `Storage` and `StoragePool` are semantically the same because
251    /// objects have unique ids across all the device.
252    #[cfg(unix)]
253    pub fn get_file_to_descriptor(
254        &self,
255        file: impl AsObjectId,
256        descriptor: impl AsRawFd,
257    ) -> Result<()> {
258        files::get_file_to_descriptor(self.owner, file, descriptor)
259    }
260
261    /// Retrieves a file from the device storage to a local file identified by a descriptor. Note
262    /// that `get_file_to_descriptor` on `Storage` and `StoragePool` are semantically the same because
263    /// objects have unique ids across all the device.
264    ///
265    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
266    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
267    /// want to cancel operation you just return `CallbackReturn::Cancel`.
268    #[cfg(unix)]
269    pub fn get_file_to_descriptor_with_callback<C>(
270        &self,
271        file: impl AsObjectId,
272        descriptor: impl AsRawFd,
273        callback: C,
274    ) -> Result<()>
275    where
276        C: FnMut(u64, u64) -> CallbackReturn,
277    {
278        files::get_file_to_descriptor_with_callback(self.owner, file, descriptor, callback)
279    }
280
281    /// Retrieves a file from the device storage and calls handler with chunks of data. Note
282    /// that `get_file_to_descriptor` on `Storage` and `StoragePool` are semantically the same because
283    /// objects have unique ids across all the device.
284    ///
285    /// The `handler` parameter is a function that receives the chunks of data with the following
286    /// signature `(data: &[u8]) -> HandlerReturn`, you should return `HandlerReturn::Ok(readed_bytes)`
287    /// if there weren't errors with the amount of bytes you read from `data`.
288    pub fn get_file_to_handler<H>(&self, file: impl AsObjectId, handler: H) -> Result<()>
289    where
290        H: FnMut(&[u8]) -> HandlerReturn,
291    {
292        files::get_file_to_handler(self.owner, file, handler)
293    }
294
295    /// Retrieves a file from the device storage and calls handler with chunks of data. Note
296    /// that `get_file_to_descriptor` on `Storage` and `StoragePool` are semantically the same because
297    /// objects have unique ids across all the device.
298    ///
299    /// The `handler` parameter is a function that receives the chunks of data with the following
300    /// signature `(data: &[u8]) -> HandlerReturn`, you should return `HandlerReturn::Ok(readed_bytes)`
301    /// if there weren't errors with the amount of bytes you read from `data`.
302    ///
303    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
304    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
305    /// want to cancel operation you just return `CallbackReturn::Cancel`.
306    pub fn get_file_to_handler_with_callback<H, C>(
307        &self,
308        file: impl AsObjectId,
309        handler: H,
310        callback: C,
311    ) -> Result<()>
312    where
313        H: FnMut(&[u8]) -> HandlerReturn,
314        C: FnMut(u64, u64) -> CallbackReturn,
315    {
316        files::get_file_to_handler_with_callback(self.owner, file, handler, callback)
317    }
318
319    /// Sends a local file to the MTP device who this storage belongs to.
320    pub fn send_file_from_path<C>(
321        &self,
322        path: impl AsRef<Path>,
323        parent: Parent,
324        metadata: FileMetadata<'_>,
325    ) -> Result<File<'a>>
326    where
327        C: FnMut(u64, u64) -> CallbackReturn,
328    {
329        let storage_id = self.id();
330        files::send_file_from_path(self.owner, storage_id, path, parent, metadata)
331    }
332
333    /// Sends a local file to the MTP device who this storage belongs to.
334    ///
335    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
336    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
337    /// want to cancel operation you just return `CallbackReturn::Cancel`.
338    pub fn send_file_from_path_with_callback<C>(
339        &self,
340        path: impl AsRef<Path>,
341        parent: Parent,
342        metadata: FileMetadata<'_>,
343        callback: C,
344    ) -> Result<File<'a>>
345    where
346        C: FnMut(u64, u64) -> CallbackReturn,
347    {
348        let storage_id = self.id();
349        files::send_file_from_path_with_callback(
350            self.owner, storage_id, path, parent, metadata, callback,
351        )
352    }
353
354    /// Sends a local file via descriptor to the MTP device who this storage belongs to.
355    #[cfg(unix)]
356    pub fn send_file_from_descriptor(
357        &self,
358        descriptor: impl AsRawFd,
359        parent: Parent,
360        metadata: FileMetadata<'_>,
361    ) -> Result<File<'a>> {
362        let storage_id = self.id();
363        files::send_file_from_descriptor(self.owner, storage_id, descriptor, parent, metadata)
364    }
365
366    /// Sends a local file via descriptor to the MTP device who this storage belongs to.
367    ///
368    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
369    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
370    /// want to cancel operation you just return `CallbackReturn::Cancel`.
371    #[cfg(unix)]
372    pub fn send_file_from_descriptor_with_callback<C>(
373        &self,
374        descriptor: impl AsRawFd,
375        parent: Parent,
376        metadata: FileMetadata<'_>,
377        callback: C,
378    ) -> Result<File<'a>>
379    where
380        C: FnMut(u64, u64) -> CallbackReturn,
381    {
382        let storage_id = self.id();
383        files::send_file_from_descriptor_with_callback(
384            self.owner, storage_id, descriptor, parent, metadata, callback,
385        )
386    }
387
388    /// Sends a bunch of data to the MTP device who this storage belongs to.
389    ///
390    /// The `handler` parameter is a function that gives you a chunk to write data with the
391    /// following signature `(data: &mut [u8]) -> HandlerReturn`, you should return
392    /// `HandlerReturn::Ok(written_bytes)` if there weren't errors with the amount of bytes you
393    /// wrote to `data`.
394    pub fn send_file_from_handler<H>(
395        &self,
396        handler: H,
397        parent: Parent,
398        metadata: FileMetadata<'_>,
399    ) -> Result<File<'a>>
400    where
401        H: FnMut(&mut [u8]) -> HandlerReturn,
402    {
403        let storage_id = self.id();
404        files::send_file_from_handler(self.owner, storage_id, parent, metadata, handler)
405    }
406
407    /// Sends a bunch of data to the MTP device who this storage belongs to.
408    ///
409    /// The `handler` parameter is a function that gives you a chunk to write data with the
410    /// following signature `(data: &mut [u8]) -> HandlerReturn`, you should return
411    /// `HandlerReturn::Ok(written_bytes)` if there weren't errors with the amount of bytes you
412    /// wrote to `data`.
413    ///
414    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
415    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
416    /// want to cancel operation you just return `CallbackReturn::Cancel`.
417    pub fn send_file_from_handler_with_callback<H, C>(
418        &self,
419        handler: H,
420        parent: Parent,
421        metadata: FileMetadata<'_>,
422        callback: C,
423    ) -> Result<File<'a>>
424    where
425        H: FnMut(&mut [u8]) -> HandlerReturn,
426        C: FnMut(u64, u64) -> CallbackReturn,
427    {
428        let storage_id = self.id();
429        files::send_file_from_handler_with_callback(
430            self.owner, storage_id, parent, metadata, handler, callback,
431        )
432    }
433}
434
435/// Represents all the storage "pool" of one MTP device, contain all the storage entries
436/// of one MTP device, and contains some methods to send or get files from the primary storage.
437#[derive(Derivative)]
438#[derivative(Debug)]
439pub struct StoragePool<'a> {
440    order: Vec<u32>,
441    pool: HashMap<u32, Storage<'a>>,
442
443    #[derivative(Debug = "ignore")]
444    owner: &'a MtpDevice,
445}
446
447/// Iterator that allows us to get each `Storage` with its id.
448pub struct StoragePoolIter<'a> {
449    pool: &'a HashMap<u32, Storage<'a>>,
450    itr: usize,
451    order: &'a [u32],
452}
453
454impl<'a> Iterator for StoragePoolIter<'a> {
455    type Item = (u32, &'a Storage<'a>);
456
457    fn next(&mut self) -> Option<Self::Item> {
458        if self.itr >= self.pool.len() {
459            None
460        } else {
461            let next_id = self.order[self.itr];
462            let next_val = self.pool.get(&next_id)?;
463
464            self.itr += 1;
465
466            Some((next_id, next_val))
467        }
468    }
469}
470
471impl<'a> StoragePool<'a> {
472    /// Build a StoragePool from a raw ptr of devicestorage_t
473    pub(crate) fn from_raw(
474        owner: &'a MtpDevice,
475        mut ptr: *mut ffi::LIBMTP_devicestorage_t,
476    ) -> Self {
477        unsafe {
478            let mut pool = HashMap::new();
479            let mut order = Vec::new();
480            while !ptr.is_null() {
481                let id = (*ptr).id;
482                order.push(id);
483                pool.insert(id, Storage { inner: ptr, owner });
484
485                ptr = (*ptr).next;
486            }
487
488            Self { order, pool, owner }
489        }
490    }
491
492    /// Returns the `MtpDevice` that owns this storage pool
493    pub fn device(&self) -> &MtpDevice {
494        self.owner
495    }
496
497    /// Returns the storage that has the given id, if there's one.
498    pub fn by_id(&self, id: u32) -> Option<&Storage<'a>> {
499        self.pool.get(&id)
500    }
501
502    /// Returns an iterator over the storages, this is a HashMap iterator.
503    pub fn iter(&'a self) -> StoragePoolIter<'a> {
504        StoragePoolIter {
505            pool: &self.pool,
506            itr: 0,
507            order: &self.order,
508        }
509    }
510
511    /// Retrieves the contents of a certain folder (`parent`) in all storages, the result contains
512    /// both files and folders, note that this request will always perform I/O with the device.
513    pub fn files_and_folders(&self, parent: Parent) -> Vec<File<'a>> {
514        files_and_folders(self.owner, 0, parent)
515    }
516
517    /// Optionally returns a `Folder`, with this struct you can build a tree
518    /// structure (see `Folder` for more info)
519    pub fn folder_list(&self) -> Option<Folder<'_>> {
520        get_folder_list(self.owner)
521    }
522
523    /// Tries to create a new folder in the default storage of the relevant `MtpDevice`, returns
524    /// the id of the new folder and its name, note that the name may be different due to device
525    /// file system restrictions.
526    pub fn create_folder<'b>(&self, name: &'b str, parent: Parent) -> Result<(u32, Cow<'b, str>)> {
527        create_folder(self.owner, name, parent, 0)
528    }
529
530    /// Retrieves a file from the device storage to a local file identified by a filename. Note
531    /// that `get_file_to_path` on `Storage` and `StoragePool` are semantically the same because
532    /// objects have unique ids across all the device.
533    pub fn get_file_to_path(&self, file: impl AsObjectId, path: impl AsRef<Path>) -> Result<()> {
534        files::get_file_to_path(self.owner, file, path)
535    }
536
537    /// Retrieves a file from the device storage to a local file identified by a filename. Note
538    /// that `get_file_to_path` on `Storage` and `StoragePool` are semantically the same because
539    /// objects have unique ids across all the device.
540    ///
541    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
542    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
543    /// want to cancel operation you just return `CallbackReturn::Cancel`.
544    pub fn get_file_to_path_with_callback<C>(
545        &self,
546        file: impl AsObjectId,
547        path: impl AsRef<Path>,
548        callback: C,
549    ) -> Result<()>
550    where
551        C: FnMut(u64, u64) -> CallbackReturn,
552    {
553        files::get_file_to_path_with_callback(self.owner, file, path, callback)
554    }
555
556    /// Retrieves a file from the device storage to a local file identified by a descriptor. Note
557    /// that `get_file_to_descriptor` on `Storage` and `StoragePool` are semantically the same because
558    /// objects have unique ids across all the device.
559    #[cfg(unix)]
560    pub fn get_file_to_descriptor(
561        &self,
562        file: impl AsObjectId,
563        descriptor: impl AsRawFd,
564    ) -> Result<()> {
565        files::get_file_to_descriptor(self.owner, file, descriptor)
566    }
567
568    /// Retrieves a file from the device storage to a local file identified by a descriptor. Note
569    /// that `get_file_to_descriptor` on `Storage` and `StoragePool` are semantically the same because
570    /// objects have unique ids across all the device.
571    ///
572    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
573    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
574    /// want to cancel operation you just return `CallbackReturn::Cancel`.
575    #[cfg(unix)]
576    pub fn get_file_to_descriptor_with_callback<C>(
577        &self,
578        file: impl AsObjectId,
579        descriptor: impl AsRawFd,
580        callback: C,
581    ) -> Result<()>
582    where
583        C: FnMut(u64, u64) -> CallbackReturn,
584    {
585        files::get_file_to_descriptor_with_callback(self.owner, file, descriptor, callback)
586    }
587
588    /// Retrieves a file from the device storage and calls handler with chunks of data. Note
589    /// that `get_file_to_handler` on `Storage` and `StoragePool` are semantically the same because
590    /// objects have unique ids across all the device.
591    ///
592    /// The `handler` parameter is a function that receives the chunks of data with the following
593    /// signature `(data: &[u8]) -> HandlerReturn`, you should return `HandlerReturn::Ok(readed_bytes)`
594    /// if there weren't errors with the amount of bytes you read from `data`.
595    pub fn get_file_to_handler<H>(&self, file: impl AsObjectId, handler: H) -> Result<()>
596    where
597        H: FnMut(&[u8]) -> HandlerReturn,
598    {
599        files::get_file_to_handler(self.owner, file, handler)
600    }
601
602    /// Retrieves a file from the device storage and calls handler with chunks of data. Note
603    /// that `get_file_to_handler` on `Storage` and `StoragePool` are semantically the same because
604    /// objects have unique ids across all the device.
605    ///
606    /// The `handler` parameter is a function that receives the chunks of data with the following
607    /// signature `(data: &[u8]) -> HandlerReturn`, you should return `HandlerReturn::Ok(readed_bytes)`
608    /// if there weren't errors with the amount of bytes you read from `data`.
609    ///
610    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
611    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
612    /// want to cancel operation you just return `CallbackReturn::Cancel`.
613    pub fn get_file_to_handler_with_callback<H, C>(
614        &self,
615        file: impl AsObjectId,
616        handler: H,
617        callback: C,
618    ) -> Result<()>
619    where
620        H: FnMut(&[u8]) -> HandlerReturn,
621        C: FnMut(u64, u64) -> CallbackReturn,
622    {
623        files::get_file_to_handler_with_callback(self.owner, file, handler, callback)
624    }
625
626    /// Sends a local file to the MTP device who this storage belongs to, note that this method
627    /// will send the file to the primary storage.
628    pub fn send_file_from_path<C>(
629        &self,
630        path: impl AsRef<Path>,
631        parent: Parent,
632        metadata: FileMetadata<'_>,
633    ) -> Result<File<'a>>
634    where
635        C: FnMut(u64, u64) -> CallbackReturn,
636    {
637        let storage_id = 0;
638        files::send_file_from_path(self.owner, storage_id, path, parent, metadata)
639    }
640
641    /// Sends a local file to the MTP device who this storage belongs to, note that this method
642    /// will send the file to the primary storage.
643    ///
644    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
645    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
646    /// want to cancel operation you just return `CallbackReturn::Cancel`.
647    pub fn send_file_from_path_with_callback<C>(
648        &self,
649        path: impl AsRef<Path>,
650        parent: Parent,
651        metadata: FileMetadata<'_>,
652        callback: C,
653    ) -> Result<File<'a>>
654    where
655        C: FnMut(u64, u64) -> CallbackReturn,
656    {
657        let storage_id = 0;
658        files::send_file_from_path_with_callback(
659            self.owner, storage_id, path, parent, metadata, callback,
660        )
661    }
662
663    /// Sends a local file via descriptor to the MTP device who this storage belongs to, note
664    /// that this method will send the file to the primary storage.
665    #[cfg(unix)]
666    pub fn send_file_from_descriptor(
667        &self,
668        descriptor: impl AsRawFd,
669        parent: Parent,
670        metadata: FileMetadata<'_>,
671    ) -> Result<File<'a>> {
672        let storage_id = 0;
673        files::send_file_from_descriptor(self.owner, storage_id, descriptor, parent, metadata)
674    }
675
676    /// Sends a local file via descriptor to the MTP device who this storage belongs to, note
677    /// that this method will send the file to the primary storage.
678    ///
679    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
680    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
681    /// want to cancel operation you just return `CallbackReturn::Cancel`.
682    #[cfg(unix)]
683    pub fn send_file_from_descriptor_with_callback<C>(
684        &self,
685        descriptor: impl AsRawFd,
686        parent: Parent,
687        metadata: FileMetadata<'_>,
688        callback: C,
689    ) -> Result<File<'a>>
690    where
691        C: FnMut(u64, u64) -> CallbackReturn,
692    {
693        let storage_id = 0;
694        files::send_file_from_descriptor_with_callback(
695            self.owner, storage_id, descriptor, parent, metadata, callback,
696        )
697    }
698
699    /// Sends a bunch of data to the MTP device who this storage belongs to, note that this
700    /// method will send the file to primary storage.
701    ///
702    /// The `handler` parameter is a function that gives you a chunk to write data with the
703    /// following signature `(data: &mut [u8]) -> HandlerReturn`, you should return
704    /// `HandlerReturn::Ok(written_bytes)` if there weren't errors with the amount of bytes you
705    /// wrote to `data`.
706    pub fn send_file_from_handler<H>(
707        &self,
708        handler: H,
709        parent: Parent,
710        metadata: FileMetadata<'_>,
711    ) -> Result<File<'a>>
712    where
713        H: FnMut(&mut [u8]) -> HandlerReturn,
714    {
715        let storage_id = 0;
716        files::send_file_from_handler(self.owner, storage_id, parent, metadata, handler)
717    }
718
719    /// Sends a bunch of data to the MTP device who this storage belongs to, note that this
720    /// method will send the file to primary storage.
721    ///
722    /// The `handler` parameter is a function that gives you a chunk to write data with the
723    /// following signature `(data: &mut [u8]) -> HandlerReturn`, you should return
724    /// `HandlerReturn::Ok(written_bytes)` if there weren't errors with the amount of bytes you
725    /// wrote to `data`.
726    ///
727    /// The `callback` parameter is a progress function with the following signature `(sent_bytes:
728    /// u64, total_bytes: u64) -> CallbackReturn`, this way you can check the progress and if you
729    /// want to cancel operation you just return `CallbackReturn::Cancel`.
730    pub fn send_file_from_handler_with_callback<H, C>(
731        &self,
732        handler: H,
733        parent: Parent,
734        metadata: FileMetadata<'_>,
735        callback: C,
736    ) -> Result<File<'a>>
737    where
738        H: FnMut(&mut [u8]) -> HandlerReturn,
739        C: FnMut(u64, u64) -> CallbackReturn,
740    {
741        let storage_id = 0;
742        files::send_file_from_handler_with_callback(
743            self.owner, storage_id, parent, metadata, handler, callback,
744        )
745    }
746}