Validates an [`InputPaths`]. With `input_paths`a set of relative paths and a common base directory is provided. Each member of [`InputPaths::paths`] is compared with the data available in `self` by retrieving metadata from the on-disk files below [`InputPaths::base_dir`]. For this, [`MTREE_PATH_PREFIX`] is stripped from each [`Path`][`crate::mtree::v2::Path`] tracked by the [`Mtree`] and afterwa
(&self, input_paths: &InputPaths)
| 77 | /// |
| 78 | /// [ALPM-MTREE]: https://alpm.archlinux.page/specifications/ALPM-MTREE.5.html |
| 79 | pub fn validate_paths(&self, input_paths: &InputPaths) -> Result<(), Error> { |
| 80 | let base_dir = input_paths.base_dir(); |
| 81 | // Use paths in a HashSet for easier handling later. |
| 82 | let mut hashed_paths = HashSet::new(); |
| 83 | let mut duplicates = HashSet::new(); |
| 84 | for path in input_paths.paths() { |
| 85 | if hashed_paths.contains(path.as_path()) { |
| 86 | duplicates.insert(path.to_path_buf()); |
| 87 | } |
| 88 | hashed_paths.insert(path.as_path()); |
| 89 | } |
| 90 | // If there are duplicate paths, return early. |
| 91 | if !duplicates.is_empty() { |
| 92 | return Err(Error::DuplicatePaths { paths: duplicates }); |
| 93 | } |
| 94 | |
| 95 | let mtree_paths = match self { |
| 96 | Mtree::V1(mtree) | Mtree::V2(mtree) => mtree, |
| 97 | }; |
| 98 | let mut errors = PathValidationErrors::new(base_dir.to_path_buf()); |
| 99 | let mut unmatched_paths = Vec::new(); |
| 100 | |
| 101 | for mtree_path in mtree_paths.iter() { |
| 102 | // Normalize the ALPM-MTREE path. |
| 103 | let normalized_path = match mtree_path.as_normalized_path() { |
| 104 | Ok(mtree_path) => mtree_path, |
| 105 | Err(source) => { |
| 106 | let mut normalize_errors: Vec<PathValidationError> = vec![source.into()]; |
| 107 | errors.append(&mut normalize_errors); |
| 108 | // Continue, as the ALPM-MTREE data is not as it should be. |
| 109 | continue; |
| 110 | } |
| 111 | }; |
| 112 | |
| 113 | // If the normalized path exists in the hashed input paths, compare. |
| 114 | if hashed_paths.remove(normalized_path) { |
| 115 | if let Err(mut comparison_errors) = |
| 116 | mtree_path.equals_path(&InputPath::new(base_dir, normalized_path)?) |
| 117 | { |
| 118 | errors.append(&mut comparison_errors); |
| 119 | } |
| 120 | } else { |
| 121 | unmatched_paths.push(mtree_path); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | // Add dedicated error, if some file system paths are not covered by ALPM-MTREE data. |
| 126 | if !hashed_paths.is_empty() { |
| 127 | errors.append(&mut vec![PathValidationError::UnmatchedFileSystemPaths { |
| 128 | paths: hashed_paths.iter().map(|path| path.to_path_buf()).collect(), |
| 129 | }]) |
| 130 | } |
| 131 | |
| 132 | // Add dedicated error, if some ALPM-MTREE paths have no matching file system paths. |
| 133 | if !unmatched_paths.is_empty() { |
| 134 | errors.append(&mut vec![PathValidationError::UnmatchedMtreePaths { |
| 135 | paths: unmatched_paths |
| 136 | .iter() |