1
1
use std:: {
2
2
cell:: RefCell ,
3
- cmp:: { Ord , Ordering } ,
4
3
collections:: BTreeMap ,
5
4
ffi:: { OsStr , OsString } ,
6
5
path:: Path ,
@@ -45,7 +44,7 @@ pub struct Leaf {
45
44
#[ derive( Debug ) ]
46
45
pub struct Directory {
47
46
pub stat : Stat ,
48
- pub entries : Vec < DirEnt > ,
47
+ pub entries : BTreeMap < Box < OsStr > , Inode > ,
49
48
}
50
49
51
50
#[ derive( Debug ) ]
@@ -54,12 +53,6 @@ pub enum Inode {
54
53
Leaf ( Rc < Leaf > ) ,
55
54
}
56
55
57
- #[ derive( Debug ) ]
58
- pub struct DirEnt {
59
- pub name : OsString ,
60
- pub inode : Inode ,
61
- }
62
-
63
56
impl Inode {
64
57
pub fn stat ( & self ) -> & Stat {
65
58
match self {
@@ -73,99 +66,46 @@ impl Directory {
73
66
pub fn new ( stat : Stat ) -> Self {
74
67
Self {
75
68
stat,
76
- entries : vec ! [ ] ,
77
- }
78
- }
79
-
80
- pub fn find_entry ( & self , name : & OsStr ) -> Result < usize , usize > {
81
- // OCI layer tarballs are typically sorted, with the entries for a particular directory
82
- // written out immediately after that directory was created. That means that it's very
83
- // likely that the thing we're looking for is either the last entry or the insertion point
84
- // immediately following it. Fast-path those cases by essentially unrolling the first
85
- // iteration of the binary search.
86
- if let Some ( last_entry) = self . entries . last ( ) {
87
- match name. cmp ( & last_entry. name ) {
88
- Ordering :: Equal => Ok ( self . entries . len ( ) - 1 ) , // the last item, indeed
89
- Ordering :: Greater => Err ( self . entries . len ( ) ) , // need to append
90
- Ordering :: Less => self . entries . binary_search_by_key ( & name, |e| & e. name ) ,
91
- }
92
- } else {
93
- Err ( 0 )
69
+ entries : BTreeMap :: new ( ) ,
94
70
}
95
71
}
96
72
97
73
pub fn recurse ( & mut self , name : impl AsRef < OsStr > ) -> Result < & mut Directory > {
98
- match self . find_entry ( name. as_ref ( ) ) {
99
- Ok ( idx) => match & mut self . entries [ idx] . inode {
100
- Inode :: Directory ( ref mut subdir) => Ok ( subdir) ,
101
- _ => bail ! ( "Parent directory is not a directory" ) ,
102
- } ,
103
- _ => bail ! ( "Unable to find parent directory {:?}" , name. as_ref( ) ) ,
74
+ match self . entries . get_mut ( name. as_ref ( ) ) {
75
+ Some ( Inode :: Directory ( subdir) ) => Ok ( subdir) ,
76
+ Some ( _) => bail ! ( "Parent directory is not a directory" ) ,
77
+ None => bail ! ( "Unable to find parent directory {:?}" , name. as_ref( ) ) ,
104
78
}
105
79
}
106
80
107
81
pub fn mkdir ( & mut self , name : & OsStr , stat : Stat ) {
108
- match self . find_entry ( name) {
109
- Ok ( idx) => match self . entries [ idx] . inode {
110
- // Entry already exists, is a dir
111
- Inode :: Directory ( ref mut dir) => {
112
- // update the stat, but don't drop the entries
113
- dir. stat = stat;
114
- }
115
- // Entry already exists, is not a dir
116
- Inode :: Leaf ( ..) => {
117
- todo ! ( "Trying to replace non-dir with dir!" ) ;
118
- }
119
- } ,
82
+ match self . entries . get_mut ( name) {
83
+ // Entry already exists, is a dir. update the stat, but don't drop the entries
84
+ Some ( Inode :: Directory ( dir) ) => dir. stat = stat,
85
+ // Entry already exists, is not a dir
86
+ Some ( Inode :: Leaf ( ..) ) => todo ! ( "Trying to replace non-dir with dir!" ) ,
120
87
// Entry doesn't exist yet
121
- Err ( idx) => {
122
- self . entries . insert (
123
- idx,
124
- DirEnt {
125
- name : OsString :: from ( name) ,
126
- inode : Inode :: Directory ( Box :: new ( Directory :: new ( stat) ) ) ,
127
- } ,
128
- ) ;
88
+ None => {
89
+ self . entries
90
+ . insert ( name. into ( ) , Inode :: Directory ( Directory :: new ( stat) . into ( ) ) ) ;
129
91
}
130
92
}
131
93
}
132
94
133
95
pub fn insert ( & mut self , name : & OsStr , inode : Inode ) {
134
- match self . find_entry ( name) {
135
- Ok ( idx) => {
136
- // found existing item
137
- self . entries [ idx] . inode = inode;
138
- }
139
- Err ( idx) => {
140
- // need to add new item
141
- self . entries . insert (
142
- idx,
143
- DirEnt {
144
- name : OsString :: from ( name) ,
145
- inode,
146
- } ,
147
- ) ;
148
- }
149
- }
96
+ self . entries . insert ( name. into ( ) , inode) ;
150
97
}
151
98
152
99
pub fn get_for_link ( & self , name : & OsStr ) -> Result < Rc < Leaf > > {
153
- match self . find_entry ( name) {
154
- Ok ( idx) => match self . entries [ idx] . inode {
155
- Inode :: Leaf ( ref leaf) => Ok ( Rc :: clone ( leaf) ) ,
156
- Inode :: Directory ( ..) => bail ! ( "Cannot hardlink to directory" ) ,
157
- } ,
158
- _ => bail ! ( "Attempt to hardlink to non-existent file" ) ,
100
+ match self . entries . get ( name) {
101
+ Some ( Inode :: Leaf ( leaf) ) => Ok ( Rc :: clone ( leaf) ) ,
102
+ Some ( Inode :: Directory ( ..) ) => bail ! ( "Cannot hardlink to directory" ) ,
103
+ None => bail ! ( "Attempt to hardlink to non-existent file" ) ,
159
104
}
160
105
}
161
106
162
107
pub fn remove ( & mut self , name : & OsStr ) {
163
- match self . find_entry ( name) {
164
- Ok ( idx) => {
165
- self . entries . remove ( idx) ;
166
- }
167
- _ => { /* not an error to remove an already-missing file */ }
168
- }
108
+ self . entries . remove ( name) ;
169
109
}
170
110
171
111
pub fn remove_all ( & mut self ) {
@@ -174,7 +114,7 @@ impl Directory {
174
114
175
115
pub fn newest_file ( & self ) -> i64 {
176
116
let mut newest = self . stat . st_mtim_sec ;
177
- for DirEnt { inode, .. } in & self . entries {
117
+ for inode in self . entries . values ( ) {
178
118
let mtime = match inode {
179
119
Inode :: Leaf ( ref leaf) => leaf. stat . st_mtim_sec ,
180
120
Inode :: Directory ( ref dir) => dir. newest_file ( ) ,
0 commit comments