alpm_ll/
filelist.rs

1use crate::LIBRARY;
2use crate::Library;
3use crate::utils::*;
4use crate::Result;
5
6use alpm_sys_ll::*;
7
8use std::cell::UnsafeCell;
9use std::ffi::CString;
10use std::fmt;
11use std::mem;
12use std::slice;
13
14#[repr(transparent)]
15pub struct File {
16    inner: alpm_file_t,
17}
18
19impl fmt::Debug for File {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        f.debug_struct("File")
22            .field("name", &self.name())
23            .field("size", &self.size())
24            .field("mode", &self.mode())
25            .finish()
26    }
27}
28
29impl File {
30    pub fn name(&self) -> &str {
31        unsafe { from_cstr(self.inner.name) }
32    }
33
34    pub fn size(&self) -> i64 {
35        #[allow(clippy::useless_conversion)]
36        self.inner.size.into()
37    }
38
39    pub fn mode(&self) -> u32 {
40        self.inner.mode
41    }
42}
43
44// TODO unsound: needs lifetime on handle
45pub struct FileList {
46    inner: UnsafeCell<alpm_filelist_t>,
47}
48
49impl fmt::Debug for FileList {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        f.debug_list().entries(self.files()).finish()
52    }
53}
54
55impl FileList {
56    pub(crate) unsafe fn new(files: alpm_filelist_t) -> FileList {
57        FileList {
58            inner: UnsafeCell::new(files),
59        }
60    }
61
62    pub(crate) fn as_ptr(&self) -> *mut alpm_filelist_t {
63        self.inner.get()
64    }
65
66    pub fn files(&self) -> &[File] {
67        let files = unsafe { *self.as_ptr() };
68        if files.files.is_null() {
69            unsafe { slice::from_raw_parts(mem::align_of::<File>() as *const File, 0) }
70        } else {
71            unsafe { slice::from_raw_parts(files.files as *const File, files.count) }
72        }
73    }
74
75    pub fn contains<S: Into<Vec<u8>>>(&self, path: S) -> Result<Option<File>> {
76        let path = CString::new(path).unwrap();
77        let file = unsafe { LIBRARY.force_load().alpm_filelist_contains(self.as_ptr(), path.as_ptr()) };
78
79        if file.is_null() {
80            Ok(None)
81        } else {
82            let file = unsafe { *file };
83            Ok(Some(File { inner: file }))
84        }
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use crate::{Alpm, SigLevel};
91
92    #[test]
93    fn test_files() {
94        let handle = Alpm::new("/", "tests/db").unwrap();
95        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
96        let pkg = db.pkg("linux").unwrap();
97        let files = pkg.files();
98
99        assert!(files.files().is_empty());
100        assert!(Some(files.files()).is_some());
101
102        let db = handle.localdb();
103        let pkg = db.pkg("linux").unwrap();
104        let files = pkg.files();
105
106        assert!(!files.files().is_empty());
107        assert!(Some(files.files()).is_some());
108
109        let file = files.contains("boot/").unwrap().unwrap();
110        assert_eq!(file.name(), "boot/");
111        assert!(files.contains("aaaaa/").unwrap().is_none());
112    }
113}