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
44pub 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}