Show More
@@ -6,6 +6,7 b' use crate::dirstate_tree::on_disk::Dirst' | |||
|
6 | 6 | use crate::matchers::get_ignore_function; |
|
7 | 7 | use crate::matchers::Matcher; |
|
8 | 8 | use crate::utils::files::get_bytes_from_os_string; |
|
9 | use crate::utils::files::get_path_from_bytes; | |
|
9 | 10 | use crate::utils::hg_path::HgPath; |
|
10 | 11 | use crate::BadMatch; |
|
11 | 12 | use crate::DirstateStatus; |
@@ -83,14 +84,17 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
83 | 84 | fs_path: &Path, |
|
84 | 85 | is_at_repo_root: bool, |
|
85 | 86 | ) -> Result<Vec<DirEntry>, ()> { |
|
86 |
DirEntry::read_dir(fs_path, is_at_repo_root) |
|
|
87 | DirEntry::read_dir(fs_path, is_at_repo_root) | |
|
88 | .map_err(|error| self.io_error(error, hg_path)) | |
|
89 | } | |
|
90 | ||
|
91 | fn io_error(&self, error: std::io::Error, hg_path: &HgPath) { | |
|
87 | 92 |
|
|
88 | 93 |
|
|
89 | 94 |
|
|
90 | 95 |
|
|
91 | 96 |
|
|
92 | 97 |
|
|
93 | }) | |
|
94 | 98 | } |
|
95 | 99 | |
|
96 | 100 | fn traverse_fs_directory_and_dirstate( |
@@ -101,6 +105,35 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
101 | 105 | directory_fs_path: &Path, |
|
102 | 106 | is_at_repo_root: bool, |
|
103 | 107 | ) -> Result<(), DirstateV2ParseError> { |
|
108 | if !self.options.list_unknown && !self.options.list_ignored { | |
|
109 | // We only care about files in the dirstate, so we can skip listing | |
|
110 | // filesystem directories entirely. | |
|
111 | return dirstate_nodes | |
|
112 | .par_iter() | |
|
113 | .map(|dirstate_node| { | |
|
114 | let fs_path = directory_fs_path.join(get_path_from_bytes( | |
|
115 | dirstate_node.base_name(self.dmap.on_disk)?.as_bytes(), | |
|
116 | )); | |
|
117 | match std::fs::symlink_metadata(&fs_path) { | |
|
118 | Ok(fs_metadata) => self.traverse_fs_and_dirstate( | |
|
119 | &fs_path, | |
|
120 | &fs_metadata, | |
|
121 | dirstate_node, | |
|
122 | has_ignored_ancestor, | |
|
123 | ), | |
|
124 | Err(e) if e.kind() == std::io::ErrorKind::NotFound => { | |
|
125 | self.traverse_dirstate_only(dirstate_node) | |
|
126 | } | |
|
127 | Err(error) => { | |
|
128 | let hg_path = | |
|
129 | dirstate_node.full_path(self.dmap.on_disk)?; | |
|
130 | Ok(self.io_error(error, hg_path)) | |
|
131 | } | |
|
132 | } | |
|
133 | }) | |
|
134 | .collect(); | |
|
135 | } | |
|
136 | ||
|
104 | 137 | let mut fs_entries = if let Ok(entries) = self.read_dir( |
|
105 | 138 | directory_hg_path, |
|
106 | 139 | directory_fs_path, |
@@ -141,7 +174,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
141 | 174 | match pair { |
|
142 | 175 | Both(dirstate_node, fs_entry) => self |
|
143 | 176 | .traverse_fs_and_dirstate( |
|
144 | fs_entry, | |
|
177 | &fs_entry.full_path, | |
|
178 | &fs_entry.metadata, | |
|
145 | 179 | dirstate_node, |
|
146 | 180 | has_ignored_ancestor, |
|
147 | 181 | ), |
@@ -160,12 +194,13 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
160 | 194 | |
|
161 | 195 | fn traverse_fs_and_dirstate( |
|
162 | 196 | &self, |
|
163 |
fs_ |
|
|
197 | fs_path: &Path, | |
|
198 | fs_metadata: &std::fs::Metadata, | |
|
164 | 199 | dirstate_node: NodeRef<'tree, '_>, |
|
165 | 200 | has_ignored_ancestor: bool, |
|
166 | 201 | ) -> Result<(), DirstateV2ParseError> { |
|
167 | 202 | let hg_path = dirstate_node.full_path(self.dmap.on_disk)?; |
|
168 |
let file_type = fs_ |
|
|
203 | let file_type = fs_metadata.file_type(); | |
|
169 | 204 | let file_or_symlink = file_type.is_file() || file_type.is_symlink(); |
|
170 | 205 | if !file_or_symlink { |
|
171 | 206 | // If we previously had a file here, it was removed (with |
@@ -186,7 +221,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
186 | 221 | is_ignored, |
|
187 | 222 | dirstate_node.children(self.dmap.on_disk)?, |
|
188 | 223 | hg_path, |
|
189 |
|
|
|
224 | fs_path, | |
|
190 | 225 | is_at_repo_root, |
|
191 | 226 | )? |
|
192 | 227 | } else { |
@@ -209,9 +244,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
209 | 244 | .unwrap() |
|
210 | 245 | .modified |
|
211 | 246 | .push(full_path), |
|
212 |
EntryState::Normal => |
|
|
213 |
|
|
|
214 | } | |
|
247 | EntryState::Normal => self | |
|
248 | .handle_normal_file(&dirstate_node, fs_metadata)?, | |
|
215 | 249 | // This variant is not used in DirstateMap |
|
216 | 250 | // nodes |
|
217 | 251 | EntryState::Unknown => unreachable!(), |
@@ -239,7 +273,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
239 | 273 | fn handle_normal_file( |
|
240 | 274 | &self, |
|
241 | 275 | dirstate_node: &NodeRef<'tree, '_>, |
|
242 | fs_entry: &DirEntry, | |
|
276 | fs_metadata: &std::fs::Metadata, | |
|
243 | 277 | ) -> Result<(), DirstateV2ParseError> { |
|
244 | 278 | // Keep the low 31 bits |
|
245 | 279 | fn truncate_u64(value: u64) -> i32 { |
@@ -253,13 +287,12 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
253 | 287 | .entry()? |
|
254 | 288 | .expect("handle_normal_file called with entry-less node"); |
|
255 | 289 | let full_path = Cow::from(dirstate_node.full_path(self.dmap.on_disk)?); |
|
256 |
let mode_changed = |
|
|
257 |
self.options.check_exec && entry.mode_changed( |
|
|
258 | }; | |
|
259 | let size_changed = entry.size != truncate_u64(fs_entry.metadata.len()); | |
|
290 | let mode_changed = | |
|
291 | || self.options.check_exec && entry.mode_changed(fs_metadata); | |
|
292 | let size_changed = entry.size != truncate_u64(fs_metadata.len()); | |
|
260 | 293 | if entry.size >= 0 |
|
261 | 294 | && size_changed |
|
262 |
&& fs_ |
|
|
295 | && fs_metadata.file_type().is_symlink() | |
|
263 | 296 | { |
|
264 | 297 | // issue6456: Size returned may be longer due to encryption |
|
265 | 298 | // on EXT-4 fscrypt. TODO maybe only do it on EXT4? |
@@ -270,7 +303,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||
|
270 | 303 | { |
|
271 | 304 | self.outcome.lock().unwrap().modified.push(full_path) |
|
272 | 305 | } else { |
|
273 |
let mtime = mtime_seconds( |
|
|
306 | let mtime = mtime_seconds(fs_metadata); | |
|
274 | 307 | if truncate_i64(mtime) != entry.mtime |
|
275 | 308 | || mtime == self.options.last_normal_time |
|
276 | 309 | { |
General Comments 0
You need to be logged in to leave comments.
Login now