libmtp_rs/device/
raw.rs

1//! Module to handle raw devices, this will be your entrypoint to manage connected USB
2//! devices.
3
4use libmtp_sys as ffi;
5use std::ffi::CStr;
6use std::fmt::{self, Debug};
7use std::mem::MaybeUninit;
8
9use crate::device::MtpDevice;
10use crate::error::{Error, MtpErrorKind};
11use crate::internals::{maybe_init, DeviceEntry};
12use crate::Result;
13
14/// This struct handles a raw device, which should be opened with `open` or `open_uncached`
15/// if you want to manage the proper MTP device.
16pub struct RawDevice {
17    pub(crate) inner: ffi::LIBMTP_raw_device_struct,
18}
19
20impl Debug for RawDevice {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        f.debug_struct("RawDevice")
23            .field("bus_number", &self.bus_number())
24            .field("dev_number", &self.dev_number())
25            .field("device_entry", &self.device_entry())
26            .finish()
27    }
28}
29
30impl RawDevice {
31    /// Open an MTP device from this raw device descriptor, this method
32    /// may cache devices, thus may be slower.
33    pub fn open(&self) -> Option<MtpDevice> {
34        unsafe {
35            let ptr = &self.inner as *const _;
36            let device = ffi::LIBMTP_Open_Raw_Device(ptr as *mut _);
37
38            if device.is_null() {
39                None
40            } else {
41                Some(MtpDevice { inner: device })
42            }
43        }
44    }
45
46    /// Open an MTP device from this raw device descriptor, uncached version.
47    pub fn open_uncached(&self) -> Option<MtpDevice> {
48        unsafe {
49            let ptr = &self.inner as *const _;
50            let device = ffi::LIBMTP_Open_Raw_Device_Uncached(ptr as *mut _);
51
52            if device.is_null() {
53                None
54            } else {
55                Some(MtpDevice { inner: device })
56            }
57        }
58    }
59
60    /// Returns the bus number of this raw device.
61    pub fn bus_number(&self) -> u32 {
62        self.inner.bus_location
63    }
64
65    /// Returns the device number of this raw device.
66    pub fn dev_number(&self) -> u8 {
67        self.inner.devnum
68    }
69
70    /// Returns the device entry of this raw device.
71    pub fn device_entry(&self) -> DeviceEntry {
72        let vendor;
73        let product;
74
75        unsafe {
76            vendor = CStr::from_ptr(self.inner.device_entry.vendor);
77            product = CStr::from_ptr(self.inner.device_entry.product);
78        }
79
80        DeviceEntry {
81            vendor: vendor.to_str().expect("Invalid UTF-8 in music-players.h?"),
82            vendor_id: self.inner.device_entry.vendor_id,
83            product: product.to_str().expect("Invalid UTF-8 in music-players.h?"),
84            product_id: self.inner.device_entry.product_id,
85            device_flags: self.inner.device_entry.device_flags,
86        }
87    }
88}
89
90/// Detect the raw device descriptors, you will use this function whenever you want
91/// to find which devices are connected, then you may open one or all of these devices,
92/// to properly manage the device properties, its storage, files, etc.
93///
94/// ## Example
95/// ```
96/// use libmtp_rs::raw::detect_raw_devices;
97///
98/// let raw_devices = detect_raw_devices().expect("Failed to detect raw devices");
99///
100/// // Try to open the first device
101/// let mtp_device = raw_devices
102///                     .get(0)
103///                     .map(|r| r.open_uncached())
104///                     .transpose()
105///                     .expect("Couldn't open raw device");
106/// ```
107pub fn detect_raw_devices() -> Result<Vec<RawDevice>> {
108    maybe_init();
109
110    unsafe {
111        let mut devices = std::ptr::null_mut();
112        let mut len = 0;
113
114        let res = ffi::LIBMTP_Detect_Raw_Devices(&mut devices, &mut len);
115
116        if let Some(kind) = MtpErrorKind::from_error_number(res) {
117            Err(Error::MtpError {
118                kind,
119                text: "Failed to detect raw devices".to_string(),
120            })
121        } else {
122            let mut devices_vec = Vec::with_capacity(len as usize);
123            for i in 0..(len as isize) {
124                let mut new = MaybeUninit::zeroed().assume_init();
125
126                std::ptr::copy_nonoverlapping(devices.offset(i), &mut new, 1);
127                devices_vec.push(RawDevice { inner: new });
128            }
129
130            libc::free(devices as *mut _);
131            Ok(devices_vec)
132        }
133    }
134}
135
136/// Check if a specific device, given its bus and device number, has an
137/// MTP type device descriptor.
138pub fn check_specific_device(bus_number: u32, dev_number: u32) -> bool {
139    let res = unsafe { ffi::LIBMTP_Check_Specific_Device(bus_number as i32, dev_number as i32) };
140    res == 1
141}