Show More
@@ -6,6 +6,7 b' use crate::dirstate_tree::on_disk::Dirst' | |||||
6 | use crate::matchers::get_ignore_function; |
|
6 | use crate::matchers::get_ignore_function; | |
7 | use crate::matchers::Matcher; |
|
7 | use crate::matchers::Matcher; | |
8 | use crate::utils::files::get_bytes_from_os_string; |
|
8 | use crate::utils::files::get_bytes_from_os_string; | |
|
9 | use crate::utils::files::get_path_from_bytes; | |||
9 | use crate::utils::hg_path::HgPath; |
|
10 | use crate::utils::hg_path::HgPath; | |
10 | use crate::BadMatch; |
|
11 | use crate::BadMatch; | |
11 | use crate::DirstateStatus; |
|
12 | use crate::DirstateStatus; | |
@@ -83,14 +84,17 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
83 | fs_path: &Path, |
|
84 | fs_path: &Path, | |
84 | is_at_repo_root: bool, |
|
85 | is_at_repo_root: bool, | |
85 | ) -> Result<Vec<DirEntry>, ()> { |
|
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 | let errno = error.raw_os_error().expect("expected real OS error"); | |
88 |
|
|
93 | self.outcome | |
89 |
|
|
94 | .lock() | |
90 |
|
|
95 | .unwrap() | |
91 |
|
|
96 | .bad | |
92 |
|
|
97 | .push((hg_path.to_owned().into(), BadMatch::OsError(errno))) | |
93 | }) |
|
|||
94 | } |
|
98 | } | |
95 |
|
99 | |||
96 | fn traverse_fs_directory_and_dirstate( |
|
100 | fn traverse_fs_directory_and_dirstate( | |
@@ -101,6 +105,35 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
101 | directory_fs_path: &Path, |
|
105 | directory_fs_path: &Path, | |
102 | is_at_repo_root: bool, |
|
106 | is_at_repo_root: bool, | |
103 | ) -> Result<(), DirstateV2ParseError> { |
|
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 | let mut fs_entries = if let Ok(entries) = self.read_dir( |
|
137 | let mut fs_entries = if let Ok(entries) = self.read_dir( | |
105 | directory_hg_path, |
|
138 | directory_hg_path, | |
106 | directory_fs_path, |
|
139 | directory_fs_path, | |
@@ -141,7 +174,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
141 | match pair { |
|
174 | match pair { | |
142 | Both(dirstate_node, fs_entry) => self |
|
175 | Both(dirstate_node, fs_entry) => self | |
143 | .traverse_fs_and_dirstate( |
|
176 | .traverse_fs_and_dirstate( | |
144 | fs_entry, |
|
177 | &fs_entry.full_path, | |
|
178 | &fs_entry.metadata, | |||
145 | dirstate_node, |
|
179 | dirstate_node, | |
146 | has_ignored_ancestor, |
|
180 | has_ignored_ancestor, | |
147 | ), |
|
181 | ), | |
@@ -160,12 +194,13 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
160 |
|
194 | |||
161 | fn traverse_fs_and_dirstate( |
|
195 | fn traverse_fs_and_dirstate( | |
162 | &self, |
|
196 | &self, | |
163 |
fs_ |
|
197 | fs_path: &Path, | |
|
198 | fs_metadata: &std::fs::Metadata, | |||
164 | dirstate_node: NodeRef<'tree, '_>, |
|
199 | dirstate_node: NodeRef<'tree, '_>, | |
165 | has_ignored_ancestor: bool, |
|
200 | has_ignored_ancestor: bool, | |
166 | ) -> Result<(), DirstateV2ParseError> { |
|
201 | ) -> Result<(), DirstateV2ParseError> { | |
167 | let hg_path = dirstate_node.full_path(self.dmap.on_disk)?; |
|
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 | let file_or_symlink = file_type.is_file() || file_type.is_symlink(); |
|
204 | let file_or_symlink = file_type.is_file() || file_type.is_symlink(); | |
170 | if !file_or_symlink { |
|
205 | if !file_or_symlink { | |
171 | // If we previously had a file here, it was removed (with |
|
206 | // If we previously had a file here, it was removed (with | |
@@ -186,7 +221,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
186 | is_ignored, |
|
221 | is_ignored, | |
187 | dirstate_node.children(self.dmap.on_disk)?, |
|
222 | dirstate_node.children(self.dmap.on_disk)?, | |
188 | hg_path, |
|
223 | hg_path, | |
189 |
|
|
224 | fs_path, | |
190 | is_at_repo_root, |
|
225 | is_at_repo_root, | |
191 | )? |
|
226 | )? | |
192 | } else { |
|
227 | } else { | |
@@ -209,9 +244,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
209 | .unwrap() |
|
244 | .unwrap() | |
210 | .modified |
|
245 | .modified | |
211 | .push(full_path), |
|
246 | .push(full_path), | |
212 |
EntryState::Normal => |
|
247 | EntryState::Normal => self | |
213 |
|
|
248 | .handle_normal_file(&dirstate_node, fs_metadata)?, | |
214 | } |
|
|||
215 | // This variant is not used in DirstateMap |
|
249 | // This variant is not used in DirstateMap | |
216 | // nodes |
|
250 | // nodes | |
217 | EntryState::Unknown => unreachable!(), |
|
251 | EntryState::Unknown => unreachable!(), | |
@@ -239,7 +273,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
239 | fn handle_normal_file( |
|
273 | fn handle_normal_file( | |
240 | &self, |
|
274 | &self, | |
241 | dirstate_node: &NodeRef<'tree, '_>, |
|
275 | dirstate_node: &NodeRef<'tree, '_>, | |
242 | fs_entry: &DirEntry, |
|
276 | fs_metadata: &std::fs::Metadata, | |
243 | ) -> Result<(), DirstateV2ParseError> { |
|
277 | ) -> Result<(), DirstateV2ParseError> { | |
244 | // Keep the low 31 bits |
|
278 | // Keep the low 31 bits | |
245 | fn truncate_u64(value: u64) -> i32 { |
|
279 | fn truncate_u64(value: u64) -> i32 { | |
@@ -253,13 +287,12 b" impl<'tree, 'a> StatusCommon<'tree, 'a, " | |||||
253 | .entry()? |
|
287 | .entry()? | |
254 | .expect("handle_normal_file called with entry-less node"); |
|
288 | .expect("handle_normal_file called with entry-less node"); | |
255 | let full_path = Cow::from(dirstate_node.full_path(self.dmap.on_disk)?); |
|
289 | let full_path = Cow::from(dirstate_node.full_path(self.dmap.on_disk)?); | |
256 |
let mode_changed = |
|
290 | let mode_changed = | |
257 |
self.options.check_exec && entry.mode_changed( |
|
291 | || self.options.check_exec && entry.mode_changed(fs_metadata); | |
258 | }; |
|
292 | let size_changed = entry.size != truncate_u64(fs_metadata.len()); | |
259 | let size_changed = entry.size != truncate_u64(fs_entry.metadata.len()); |
|
|||
260 | if entry.size >= 0 |
|
293 | if entry.size >= 0 | |
261 | && size_changed |
|
294 | && size_changed | |
262 |
&& fs_ |
|
295 | && fs_metadata.file_type().is_symlink() | |
263 | { |
|
296 | { | |
264 | // issue6456: Size returned may be longer due to encryption |
|
297 | // issue6456: Size returned may be longer due to encryption | |
265 | // on EXT-4 fscrypt. TODO maybe only do it on EXT4? |
|
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 | self.outcome.lock().unwrap().modified.push(full_path) |
|
304 | self.outcome.lock().unwrap().modified.push(full_path) | |
272 | } else { |
|
305 | } else { | |
273 |
let mtime = mtime_seconds( |
|
306 | let mtime = mtime_seconds(fs_metadata); | |
274 | if truncate_i64(mtime) != entry.mtime |
|
307 | if truncate_i64(mtime) != entry.mtime | |
275 | || mtime == self.options.last_normal_time |
|
308 | || mtime == self.options.last_normal_time | |
276 | { |
|
309 | { |
General Comments 0
You need to be logged in to leave comments.
Login now