1use crate::mtp::object::NewObjectInfo;
4use crate::mtp::stream::{FileDownload, Progress};
5use crate::ptp::{ObjectHandle, ObjectInfo, StorageId, StorageInfo};
6use crate::Error;
7use bytes::Bytes;
8use futures::Stream;
9use std::ops::ControlFlow;
10use std::sync::Arc;
11
12use super::device::MtpDeviceInner;
13
14pub struct Storage {
19 inner: Arc<MtpDeviceInner>,
20 id: StorageId,
21 info: StorageInfo,
22}
23
24impl Storage {
25 pub(crate) fn new(inner: Arc<MtpDeviceInner>, id: StorageId, info: StorageInfo) -> Self {
27 Self { inner, id, info }
28 }
29
30 #[must_use]
31 pub fn id(&self) -> StorageId {
32 self.id
33 }
34
35 #[must_use]
37 pub fn info(&self) -> &StorageInfo {
38 &self.info
39 }
40
41 pub async fn refresh(&mut self) -> Result<(), Error> {
43 self.info = self.inner.session.get_storage_info(self.id).await?;
44 Ok(())
45 }
46
47 pub async fn list_objects(
54 &self,
55 parent: Option<ObjectHandle>,
56 ) -> Result<Vec<ObjectInfo>, Error> {
57 let effective_parent = if parent.is_none() && self.inner.is_android() {
62 Some(ObjectHandle::ALL)
63 } else {
64 parent
65 };
66
67 let result = self
68 .inner
69 .session
70 .get_object_handles(self.id, None, effective_parent)
71 .await;
72
73 let handles = match result {
74 Ok(h) => h,
75 Err(Error::Protocol {
76 code: crate::ptp::ResponseCode::InvalidObjectHandle,
77 ..
78 }) if parent.is_none() => {
79 return self.list_objects_samsung_fallback().await;
81 }
82 Err(e) => return Err(e),
83 };
84
85 let mut objects = Vec::with_capacity(handles.len());
86 let expected_parent = parent.unwrap_or(ObjectHandle::ROOT);
87
88 for handle in handles {
89 let mut info = self.inner.session.get_object_info(handle).await?;
90 info.handle = handle;
91
92 let parent_matches = if parent.is_none() && self.inner.is_android() {
97 info.parent.0 == 0 || info.parent.0 == 0xFFFFFFFF
98 } else {
99 info.parent == expected_parent
100 };
101
102 if parent_matches {
103 objects.push(info);
104 }
105 }
106 Ok(objects)
107 }
108
109 async fn list_objects_samsung_fallback(&self) -> Result<Vec<ObjectInfo>, Error> {
111 let handles = self
112 .inner
113 .session
114 .get_object_handles(self.id, None, Some(ObjectHandle::ALL))
115 .await?;
116
117 let mut objects = Vec::new();
118 for handle in handles {
119 let mut info = self.inner.session.get_object_info(handle).await?;
120 info.handle = handle;
121
122 if info.parent.0 == 0 || info.parent.0 == 0xFFFFFFFF {
124 objects.push(info);
125 }
126 }
127 Ok(objects)
128 }
129
130 pub async fn list_objects_recursive(
139 &self,
140 parent: Option<ObjectHandle>,
141 ) -> Result<Vec<ObjectInfo>, Error> {
142 if self.inner.is_android() {
143 return self.list_objects_recursive_manual(parent).await;
144 }
145
146 let native_result = self.list_objects_recursive_native(parent).await?;
147
148 let has_files = native_result.iter().any(|o| o.is_file());
151 if !native_result.is_empty() && !has_files {
152 return self.list_objects_recursive_manual(parent).await;
153 }
154
155 Ok(native_result)
156 }
157
158 pub async fn list_objects_recursive_native(
160 &self,
161 parent: Option<ObjectHandle>,
162 ) -> Result<Vec<ObjectInfo>, Error> {
163 let recursive_parent = if parent.is_none() {
164 Some(ObjectHandle::ALL)
165 } else {
166 parent
167 };
168
169 let handles = self
170 .inner
171 .session
172 .get_object_handles(self.id, None, recursive_parent)
173 .await?;
174
175 let mut objects = Vec::with_capacity(handles.len());
176 for handle in handles {
177 let mut info = self.inner.session.get_object_info(handle).await?;
178 info.handle = handle;
179 objects.push(info);
180 }
181 Ok(objects)
182 }
183
184 pub async fn list_objects_recursive_manual(
186 &self,
187 parent: Option<ObjectHandle>,
188 ) -> Result<Vec<ObjectInfo>, Error> {
189 let mut result = Vec::new();
190 let mut folders_to_visit = vec![parent];
191
192 while let Some(current_parent) = folders_to_visit.pop() {
193 let objects = self.list_objects(current_parent).await?;
194
195 for obj in objects {
196 if obj.is_folder() {
197 folders_to_visit.push(Some(obj.handle));
198 }
199 result.push(obj);
200 }
201 }
202
203 Ok(result)
204 }
205
206 pub async fn get_object_info(&self, handle: ObjectHandle) -> Result<ObjectInfo, Error> {
208 let mut info = self.inner.session.get_object_info(handle).await?;
209 info.handle = handle;
210 Ok(info)
211 }
212
213 pub async fn download(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error> {
222 self.inner.session.get_object(handle).await
223 }
224
225 pub async fn download_partial(
227 &self,
228 handle: ObjectHandle,
229 offset: u64,
230 size: u32,
231 ) -> Result<Vec<u8>, Error> {
232 self.inner
233 .session
234 .get_partial_object(handle, offset, size)
235 .await
236 }
237
238 pub async fn download_thumbnail(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error> {
239 self.inner.session.get_thumb(handle).await
240 }
241
242 pub async fn download_stream(&self, handle: ObjectHandle) -> Result<FileDownload, Error> {
267 let info = self.get_object_info(handle).await?;
268 let size = info.size;
269
270 let stream = self
271 .inner
272 .session
273 .execute_with_receive_stream(crate::ptp::OperationCode::GetObject, &[handle.0])
274 .await?;
275
276 Ok(FileDownload::new(size, stream))
277 }
278
279 pub async fn upload<S>(
294 &self,
295 parent: Option<ObjectHandle>,
296 info: NewObjectInfo,
297 data: S,
298 ) -> Result<ObjectHandle, Error>
299 where
300 S: Stream<Item = Result<Bytes, std::io::Error>> + Unpin,
301 {
302 self.upload_with_progress(parent, info, data, |_| ControlFlow::Continue(()))
303 .await
304 }
305
306 pub async fn upload_with_progress<S, F>(
311 &self,
312 parent: Option<ObjectHandle>,
313 info: NewObjectInfo,
314 mut data: S,
315 mut on_progress: F,
316 ) -> Result<ObjectHandle, Error>
317 where
318 S: Stream<Item = Result<Bytes, std::io::Error>> + Unpin,
319 F: FnMut(Progress) -> ControlFlow<()>,
320 {
321 use futures::StreamExt;
322
323 let total_size = info.size;
324 let mut buffer = Vec::with_capacity(total_size as usize);
325 let mut bytes_received = 0u64;
326
327 while let Some(chunk) = data.next().await {
328 let chunk = chunk.map_err(Error::Io)?;
329 bytes_received += chunk.len() as u64;
330 buffer.extend_from_slice(&chunk);
331
332 let progress = Progress {
333 bytes_transferred: bytes_received,
334 total_bytes: Some(total_size),
335 };
336
337 if let ControlFlow::Break(()) = on_progress(progress) {
338 return Err(Error::Cancelled);
339 }
340 }
341
342 let object_info = info.to_object_info();
343 let parent_handle = parent.unwrap_or(ObjectHandle::ROOT);
344 let (_, _, handle) = self
345 .inner
346 .session
347 .send_object_info(self.id, parent_handle, &object_info)
348 .await?;
349
350 self.inner.session.send_object(&buffer).await?;
351
352 Ok(handle)
353 }
354
355 pub async fn create_folder(
360 &self,
361 parent: Option<ObjectHandle>,
362 name: &str,
363 ) -> Result<ObjectHandle, Error> {
364 let info = NewObjectInfo::folder(name);
365 let object_info = info.to_object_info();
366 let parent_handle = parent.unwrap_or(ObjectHandle::ROOT);
367
368 let (_, _, handle) = self
369 .inner
370 .session
371 .send_object_info(self.id, parent_handle, &object_info)
372 .await?;
373
374 Ok(handle)
375 }
376
377 pub async fn delete(&self, handle: ObjectHandle) -> Result<(), Error> {
378 self.inner.session.delete_object(handle).await
379 }
380
381 pub async fn move_object(
383 &self,
384 handle: ObjectHandle,
385 new_parent: ObjectHandle,
386 new_storage: Option<StorageId>,
387 ) -> Result<(), Error> {
388 let storage = new_storage.unwrap_or(self.id);
389 self.inner
390 .session
391 .move_object(handle, storage, new_parent)
392 .await
393 }
394
395 pub async fn copy_object(
396 &self,
397 handle: ObjectHandle,
398 new_parent: ObjectHandle,
399 new_storage: Option<StorageId>,
400 ) -> Result<ObjectHandle, Error> {
401 let storage = new_storage.unwrap_or(self.id);
402 self.inner
403 .session
404 .copy_object(handle, storage, new_parent)
405 .await
406 }
407
408 pub async fn rename(&self, handle: ObjectHandle, new_name: &str) -> Result<(), Error> {
413 self.inner.session.rename_object(handle, new_name).await
414 }
415}