Skip to content

Commit 4bbb21e

Browse files
committed
WIP: use same paths representation for unix/windows
1 parent 87e73cb commit 4bbb21e

24 files changed

+320
-300
lines changed

Cargo.lock

+9-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/core/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ itertools = "0.13.0"
105105
quick_cache = "0.6.9"
106106
shell-words = "1.1.0"
107107
strum = { version = "0.26.3", features = ["derive"] }
108+
typed-path = "0.10.0"
108109
zstd = "0.13.2"
109110

110111
[target.'cfg(not(windows))'.dependencies]

crates/core/src/archiver.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ pub(crate) mod parent;
33
pub(crate) mod tree;
44
pub(crate) mod tree_archiver;
55

6-
use std::path::{Path, PathBuf};
7-
86
use chrono::Local;
97
use log::warn;
108
use pariter::{scope, IteratorExt};
9+
use typed_path::{UnixPath, UnixPathBuf};
1110

1211
use crate::{
1312
archiver::{
@@ -126,8 +125,8 @@ impl<'a, BE: DecryptFullBackend, I: ReadGlobalIndex> Archiver<'a, BE, I> {
126125
pub fn archive<R>(
127126
mut self,
128127
src: &R,
129-
backup_path: &Path,
130-
as_path: Option<&PathBuf>,
128+
backup_path: &UnixPath,
129+
as_path: Option<&UnixPathBuf>,
131130
skip_identical_parent: bool,
132131
no_scan: bool,
133132
p: &impl Progress,

crates/core/src/archiver/parent.rs

+8-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use std::{
2-
cmp::Ordering,
3-
ffi::{OsStr, OsString},
4-
};
1+
use std::cmp::Ordering;
52

63
use log::warn;
74

@@ -124,20 +121,20 @@ impl Parent {
124121
/// # Returns
125122
///
126123
/// The parent node with the given name, or `None` if the parent node is not found.
127-
fn p_node(&mut self, name: &OsStr) -> Option<&Node> {
124+
fn p_node(&mut self, name: &[u8]) -> Option<&Node> {
128125
match &self.tree {
129126
None => None,
130127
Some(tree) => {
131128
let p_nodes = &tree.nodes;
132129
loop {
133130
match p_nodes.get(self.node_idx) {
134131
None => break None,
135-
Some(p_node) => match p_node.name().as_os_str().cmp(name) {
136-
Ordering::Less => self.node_idx += 1,
132+
Some(p_node) => match name.cmp(&p_node.name()) {
133+
Ordering::Greater => self.node_idx += 1,
137134
Ordering::Equal => {
138135
break Some(p_node);
139136
}
140-
Ordering::Greater => {
137+
Ordering::Less => {
141138
break None;
142139
}
143140
},
@@ -161,7 +158,7 @@ impl Parent {
161158
/// # Note
162159
///
163160
/// TODO: This function does not check whether the given node is a directory.
164-
fn is_parent(&mut self, node: &Node, name: &OsStr) -> ParentResult<&Node> {
161+
fn is_parent(&mut self, node: &Node, name: &[u8]) -> ParentResult<&Node> {
165162
// use new variables as the mutable borrow is used later
166163
let ignore_ctime = self.ignore_ctime;
167164
let ignore_inode = self.ignore_inode;
@@ -190,12 +187,7 @@ impl Parent {
190187
///
191188
/// * `be` - The backend to read from.
192189
/// * `name` - The name of the parent node.
193-
fn set_dir(
194-
&mut self,
195-
be: &impl DecryptReadBackend,
196-
index: &impl ReadGlobalIndex,
197-
name: &OsStr,
198-
) {
190+
fn set_dir(&mut self, be: &impl DecryptReadBackend, index: &impl ReadGlobalIndex, name: &[u8]) {
199191
let tree = self.p_node(name).and_then(|p_node| {
200192
p_node.subtree.map_or_else(
201193
|| {
@@ -257,7 +249,7 @@ impl Parent {
257249
&mut self,
258250
be: &impl DecryptReadBackend,
259251
index: &impl ReadGlobalIndex,
260-
item: TreeType<O, OsString>,
252+
item: TreeType<O, Vec<u8>>,
261253
) -> Result<ItemWithParent<O>, TreeStackEmptyError> {
262254
let result = match item {
263255
TreeType::NewTree((path, node, tree)) => {

crates/core/src/archiver/tree.rs

+17-20
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use std::{ffi::OsString, path::PathBuf};
2-
31
use crate::{
42
backend::node::{Metadata, Node, NodeType},
53
blob::tree::comp_to_osstr,
64
};
75

6+
use typed_path::UnixPathBuf;
7+
88
/// `TreeIterator` turns an Iterator yielding items with paths and Nodes into an
99
/// Iterator which ensures that all subdirectories are visited and closed.
1010
/// The resulting Iterator yielss a `TreeType` which either contains the original
@@ -18,7 +18,7 @@ pub(crate) struct TreeIterator<T, I> {
1818
/// The original Iterator.
1919
iter: I,
2020
/// The current path.
21-
path: PathBuf,
21+
path: UnixPathBuf,
2222
/// The current item.
2323
item: Option<T>,
2424
}
@@ -31,7 +31,7 @@ where
3131
let item = iter.next();
3232
Self {
3333
iter,
34-
path: PathBuf::new(),
34+
path: UnixPathBuf::new(),
3535
item,
3636
}
3737
}
@@ -49,32 +49,25 @@ where
4949
#[derive(Debug)]
5050
pub(crate) enum TreeType<T, U> {
5151
/// New tree to be inserted.
52-
NewTree((PathBuf, Node, U)),
52+
NewTree((UnixPathBuf, Node, U)),
5353
/// A pseudo item which indicates that a tree is finished.
5454
EndTree,
5555
/// Original item.
56-
Other((PathBuf, Node, T)),
56+
Other((UnixPathBuf, Node, T)),
5757
}
5858

59-
impl<I, O> Iterator for TreeIterator<(PathBuf, Node, O), I>
59+
impl<I, O> Iterator for TreeIterator<(UnixPathBuf, Node, O), I>
6060
where
61-
I: Iterator<Item = (PathBuf, Node, O)>,
61+
I: Iterator<Item = (UnixPathBuf, Node, O)>,
6262
{
63-
type Item = TreeType<O, OsString>;
63+
type Item = TreeType<O, Vec<u8>>;
6464
fn next(&mut self) -> Option<Self::Item> {
6565
match &self.item {
6666
None => {
6767
if self.path.pop() {
6868
Some(TreeType::EndTree)
6969
} else {
70-
// Check if we still have a path prefix open...
71-
match self.path.components().next() {
72-
Some(std::path::Component::Prefix(..)) => {
73-
self.path = PathBuf::new();
74-
Some(TreeType::EndTree)
75-
}
76-
_ => None,
77-
}
70+
None
7871
}
7972
}
8073
Some((path, node, _)) => {
@@ -91,16 +84,20 @@ where
9184
if node.is_dir() && path == &self.path {
9285
let (path, node, _) = self.item.take().unwrap();
9386
self.item = self.iter.next();
94-
let name = node.name();
87+
let name = node.name().to_vec();
9588
return Some(TreeType::NewTree((path, node, name)));
9689
}
9790
// Use mode 755 for missing dirs, so they can be accessed
9891
let meta = Metadata {
9992
mode: Some(0o755),
10093
..Default::default()
10194
};
102-
let node = Node::new_node(&p, NodeType::Dir, meta);
103-
return Some(TreeType::NewTree((self.path.clone(), node, p)));
95+
let node = Node::new_node(p, NodeType::Dir, meta);
96+
return Some(TreeType::NewTree((
97+
self.path.clone(),
98+
node,
99+
p.to_vec(),
100+
)));
104101
}
105102
}
106103
// there wasn't any normal path component to process - return current item

crates/core/src/archiver/tree_archiver.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use std::path::{Path, PathBuf};
2-
31
use bytesize::ByteSize;
42
use log::{debug, trace};
3+
use typed_path::{UnixPath, UnixPathBuf};
54

65
use crate::{
76
archiver::{parent::ParentResult, tree::TreeType},
@@ -30,7 +29,7 @@ pub(crate) struct TreeArchiver<'a, BE: DecryptWriteBackend, I: ReadGlobalIndex>
3029
/// The current tree.
3130
tree: Tree,
3231
/// The stack of trees.
33-
stack: Vec<(PathBuf, Node, ParentResult<TreeId>, Tree)>,
32+
stack: Vec<(UnixPathBuf, Node, ParentResult<TreeId>, Tree)>,
3433
/// The index to read from.
3534
index: &'a I,
3635
/// The packer to write to.
@@ -129,7 +128,7 @@ impl<'a, BE: DecryptWriteBackend, I: ReadGlobalIndex> TreeArchiver<'a, BE, I> {
129128
/// * `path` - The path of the file.
130129
/// * `node` - The node of the file.
131130
/// * `parent` - The parent result of the file.
132-
fn add_file(&mut self, path: &Path, node: Node, parent: &ParentResult<()>, size: u64) {
131+
fn add_file(&mut self, path: &UnixPath, node: Node, parent: &ParentResult<()>, size: u64) {
133132
let filename = path.join(node.name());
134133
match parent {
135134
ParentResult::Matched(()) => {
@@ -164,7 +163,11 @@ impl<'a, BE: DecryptWriteBackend, I: ReadGlobalIndex> TreeArchiver<'a, BE, I> {
164163
/// # Returns
165164
///
166165
/// The id of the tree.
167-
fn backup_tree(&mut self, path: &Path, parent: &ParentResult<TreeId>) -> RusticResult<TreeId> {
166+
fn backup_tree(
167+
&mut self,
168+
path: &UnixPath,
169+
parent: &ParentResult<TreeId>,
170+
) -> RusticResult<TreeId> {
168171
let (chunk, id) = self.tree.serialize().map_err(|err| {
169172
RusticError::with_source(
170173
ErrorKind::Internal,
@@ -224,7 +227,7 @@ impl<'a, BE: DecryptWriteBackend, I: ReadGlobalIndex> TreeArchiver<'a, BE, I> {
224227
parent_tree: Option<TreeId>,
225228
) -> RusticResult<(TreeId, SnapshotSummary)> {
226229
let parent = parent_tree.map_or(ParentResult::NotFound, ParentResult::Matched);
227-
let id = self.backup_tree(&PathBuf::new(), &parent)?;
230+
let id = self.backup_tree(UnixPath::new(&[]), &parent)?;
228231
let stats = self.tree_packer.finalize()?;
229232
stats.apply(&mut self.summary, BlobType::Tree);
230233

crates/core/src/backend.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use log::trace;
2020
use mockall::mock;
2121

2222
use serde_derive::{Deserialize, Serialize};
23+
use typed_path::UnixPathBuf;
2324

2425
use crate::{
2526
backend::node::{Metadata, Node, NodeType},
@@ -31,8 +32,8 @@ use crate::{
3132
#[derive(thiserror::Error, Debug, displaydoc::Display)]
3233
#[non_exhaustive]
3334
pub enum BackendErrorKind {
34-
/// Path is not allowed: `{0:?}`
35-
PathNotAllowed(PathBuf),
35+
/// Path is not allowed: `{0}`
36+
PathNotAllowed(String),
3637
}
3738

3839
pub(crate) type BackendResult<T> = Result<T, BackendErrorKind>;
@@ -416,7 +417,7 @@ impl std::fmt::Debug for dyn WriteBackend {
416417
#[derive(Debug, Clone)]
417418
pub struct ReadSourceEntry<O> {
418419
/// The path of the entry.
419-
pub path: PathBuf,
420+
pub path: UnixPathBuf,
420421

421422
/// The node information of the entry.
422423
pub node: Node,
@@ -426,10 +427,11 @@ pub struct ReadSourceEntry<O> {
426427
}
427428

428429
impl<O> ReadSourceEntry<O> {
429-
fn from_path(path: PathBuf, open: Option<O>) -> BackendResult<Self> {
430+
fn from_path(path: UnixPathBuf, open: Option<O>) -> BackendResult<Self> {
430431
let node = Node::new_node(
431-
path.file_name()
432-
.ok_or_else(|| BackendErrorKind::PathNotAllowed(path.clone()))?,
432+
path.file_name().ok_or_else(|| {
433+
BackendErrorKind::PathNotAllowed(path.to_string_lossy().to_string())
434+
})?,
433435
NodeType::File,
434436
Metadata::default(),
435437
);

crates/core/src/backend/childstdout.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use std::{
22
iter::{once, Once},
3-
path::PathBuf,
43
process::{Child, ChildStdout, Command, Stdio},
54
sync::Mutex,
65
};
76

7+
use typed_path::UnixPathBuf;
8+
89
use crate::{
910
backend::{ReadSource, ReadSourceEntry},
1011
error::{ErrorKind, RusticError, RusticResult},
@@ -15,7 +16,7 @@ use crate::{
1516
#[derive(Debug)]
1617
pub struct ChildStdoutSource {
1718
/// The path of the stdin entry.
18-
path: PathBuf,
19+
path: UnixPathBuf,
1920
/// The child process
2021
///
2122
/// # Note
@@ -30,14 +31,14 @@ pub struct ChildStdoutSource {
3031

3132
impl ChildStdoutSource {
3233
/// Creates a new `ChildSource`.
33-
pub fn new(cmd: &CommandInput, path: PathBuf) -> RusticResult<Self> {
34+
pub fn new(cmd: &CommandInput, path: UnixPathBuf) -> RusticResult<Self> {
3435
let process = Command::new(cmd.command())
3536
.args(cmd.args())
3637
.stdout(Stdio::piped())
3738
.spawn()
3839
.map_err(|err| CommandInputErrorKind::ProcessExecutionFailed {
3940
command: cmd.clone(),
40-
path: path.clone(),
41+
path: path.to_string_lossy().to_string(),
4142
source: err,
4243
});
4344

0 commit comments

Comments
 (0)