1
- use std:: path:: { Path , PathBuf } ;
1
+ use std:: path:: { Component , Path , PathBuf } ;
2
2
3
3
use crate :: Stack ;
4
4
@@ -22,20 +22,22 @@ impl Stack {
22
22
23
23
/// A delegate for use in a [`Stack`].
24
24
pub trait Delegate {
25
- /// Called whenever we push a directory on top of the stack, after the fact .
25
+ /// Called whenever we push a directory on top of the stack, and after the respective call to [`push()`](Self::push) .
26
26
///
27
- /// It is also called if the currently acted on path is a directory in itself.
28
- /// Use `stack.current()` to see the directory.
27
+ /// It is only called if the currently acted on path is a directory in itself, which is determined by knowing
28
+ /// that it's not the last component fo the path.
29
+ /// Use [`Stack::current()`] to see the directory.
29
30
fn push_directory ( & mut self , stack : & Stack ) -> std:: io:: Result < ( ) > ;
30
31
31
- /// Called after any component was pushed, with the path available at `stack. current()`.
32
+ /// Called after any component was pushed, with the path available at [`Stack:: current()`] .
32
33
///
33
- /// `is_last_component` is true if the path is completely built.
34
+ /// `is_last_component` is ` true` if the path is completely built, which typically means it's not a directory .
34
35
fn push ( & mut self , is_last_component : bool , stack : & Stack ) -> std:: io:: Result < ( ) > ;
35
36
36
37
/// Called right after a directory-component was popped off the stack.
37
38
///
38
- /// Use it to pop information off internal data structures.
39
+ /// Use it to pop information off internal data structures. Note that no equivalent call exists for popping
40
+ /// the file-component.
39
41
fn pop_directory ( & mut self ) ;
40
42
}
41
43
@@ -58,12 +60,17 @@ impl Stack {
58
60
/// The full path to `relative` will be returned along with the data returned by `push_comp`.
59
61
/// Note that this only works correctly for the delegate's `push_directory()` and `pop_directory()` methods if
60
62
/// `relative` paths are terminal, so point to their designated file or directory.
63
+ /// The path is also expected to be normalized, and should not contain extra separators, and must not contain `..`
64
+ /// or have leading or trailing slashes (or additionally backslashes on Windows).
61
65
pub fn make_relative_path_current ( & mut self , relative : & Path , delegate : & mut dyn Delegate ) -> std:: io:: Result < ( ) > {
62
- debug_assert ! (
63
- relative. is_relative( ) ,
64
- "only index paths are handled correctly here, must be relative"
65
- ) ;
66
-
66
+ if relative. as_os_str ( ) . is_empty ( ) {
67
+ return Err ( std:: io:: Error :: new (
68
+ std:: io:: ErrorKind :: Other ,
69
+ "empty inputs are not allowed" ,
70
+ ) ) ;
71
+ }
72
+ // TODO: prevent leading or trailing slashes, on Windows also backslashes.
73
+ // prevent leading backslashes on Windows as they are strange
67
74
if self . valid_components == 0 {
68
75
delegate. push_directory ( self ) ?;
69
76
}
@@ -95,6 +102,15 @@ impl Stack {
95
102
}
96
103
97
104
while let Some ( comp) = components. next ( ) {
105
+ if !matches ! ( comp, Component :: Normal ( _) ) {
106
+ return Err ( std:: io:: Error :: new (
107
+ std:: io:: ErrorKind :: Other ,
108
+ format ! (
109
+ "Input path \" {}\" contains relative or absolute components" ,
110
+ relative. display( )
111
+ ) ,
112
+ ) ) ;
113
+ }
98
114
let is_last_component = components. peek ( ) . is_none ( ) ;
99
115
self . current_is_directory = !is_last_component;
100
116
self . current . push ( comp) ;
0 commit comments