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}