Show More
@@ -580,10 +580,8 b' impl DirstateEntry {' | |||
|
580 | 580 | &self, |
|
581 | 581 | filesystem_metadata: &std::fs::Metadata, |
|
582 | 582 | ) -> bool { |
|
583 | use std::os::unix::fs::MetadataExt; | |
|
584 | const EXEC_BIT_MASK: u32 = 0o100; | |
|
585 | let dirstate_exec_bit = (self.mode() as u32) & EXEC_BIT_MASK; | |
|
586 | let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK; | |
|
583 | let dirstate_exec_bit = (self.mode() as u32 & EXEC_BIT_MASK) != 0; | |
|
584 | let fs_exec_bit = has_exec_bit(filesystem_metadata); | |
|
587 | 585 | dirstate_exec_bit != fs_exec_bit |
|
588 | 586 | } |
|
589 | 587 | |
@@ -641,3 +639,11 b' impl Into<u8> for EntryState {' | |||
|
641 | 639 | } |
|
642 | 640 | } |
|
643 | 641 | } |
|
642 | ||
|
643 | const EXEC_BIT_MASK: u32 = 0o100; | |
|
644 | ||
|
645 | pub fn has_exec_bit(metadata: &std::fs::Metadata) -> bool { | |
|
646 | // TODO: How to handle executable permissions on Windows? | |
|
647 | use std::os::unix::fs::MetadataExt; | |
|
648 | (metadata.mode() & EXEC_BIT_MASK) != 0 | |
|
649 | } |
@@ -16,6 +16,22 b" impl Vfs<'_> {" | |||
|
16 | 16 | self.base.join(relative_path) |
|
17 | 17 | } |
|
18 | 18 | |
|
19 | pub fn symlink_metadata( | |
|
20 | &self, | |
|
21 | relative_path: impl AsRef<Path>, | |
|
22 | ) -> Result<std::fs::Metadata, HgError> { | |
|
23 | let path = self.join(relative_path); | |
|
24 | std::fs::symlink_metadata(&path).when_reading_file(&path) | |
|
25 | } | |
|
26 | ||
|
27 | pub fn read_link( | |
|
28 | &self, | |
|
29 | relative_path: impl AsRef<Path>, | |
|
30 | ) -> Result<PathBuf, HgError> { | |
|
31 | let path = self.join(relative_path); | |
|
32 | std::fs::read_link(&path).when_reading_file(&path) | |
|
33 | } | |
|
34 | ||
|
19 | 35 | pub fn read( |
|
20 | 36 | &self, |
|
21 | 37 | relative_path: impl AsRef<Path>, |
@@ -11,11 +11,12 b' use crate::utils::path_utils::relativize' | |||
|
11 | 11 | use clap::{Arg, SubCommand}; |
|
12 | 12 | use hg; |
|
13 | 13 | use hg::config::Config; |
|
14 | use hg::dirstate::TruncatedTimestamp; | |
|
14 | use hg::dirstate::{has_exec_bit, TruncatedTimestamp}; | |
|
15 | 15 | use hg::errors::HgError; |
|
16 | 16 | use hg::manifest::Manifest; |
|
17 | 17 | use hg::matchers::AlwaysMatcher; |
|
18 | 18 | use hg::repo::Repo; |
|
19 | use hg::utils::files::get_bytes_from_os_string; | |
|
19 | 20 | use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; |
|
20 | 21 | use hg::{HgPathCow, StatusOptions}; |
|
21 | 22 | use log::{info, warn}; |
@@ -302,16 +303,30 b' fn display_status_paths(' | |||
|
302 | 303 | /// |
|
303 | 304 | /// This meant to be used for those that the dirstate cannot resolve, due |
|
304 | 305 | /// to time resolution limits. |
|
305 | /// | |
|
306 | /// TODO: detect permission bits and similar metadata modifications | |
|
307 | 306 | fn unsure_is_modified( |
|
308 | 307 | repo: &Repo, |
|
309 | 308 | manifest: &Manifest, |
|
310 | 309 | hg_path: &HgPath, |
|
311 | 310 | ) -> Result<bool, HgError> { |
|
311 | let vfs = repo.working_directory_vfs(); | |
|
312 | let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion"); | |
|
313 | let fs_metadata = vfs.symlink_metadata(&fs_path)?; | |
|
314 | let is_symlink = fs_metadata.file_type().is_symlink(); | |
|
315 | // TODO: Also account for `FALLBACK_SYMLINK` and `FALLBACK_EXEC` from the dirstate | |
|
316 | let fs_flags = if is_symlink { | |
|
317 | Some(b'l') | |
|
318 | } else if has_exec_bit(&fs_metadata) { | |
|
319 | Some(b'x') | |
|
320 | } else { | |
|
321 | None | |
|
322 | }; | |
|
323 | ||
|
312 | 324 | let entry = manifest |
|
313 | 325 | .find_file(hg_path)? |
|
314 | 326 | .expect("ambgious file not in p1"); |
|
327 | if entry.flags != fs_flags { | |
|
328 | return Ok(true); | |
|
329 | } | |
|
315 | 330 | let filelog = repo.filelog(hg_path)?; |
|
316 | 331 | let filelog_entry = |
|
317 | 332 | filelog.data_for_node(entry.node_id()?).map_err(|_| { |
@@ -319,7 +334,10 b' fn unsure_is_modified(' | |||
|
319 | 334 | })?; |
|
320 | 335 | let contents_in_p1 = filelog_entry.data()?; |
|
321 | 336 | |
|
322 | let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion"); | |
|
323 | let fs_contents = repo.working_directory_vfs().read(fs_path)?; | |
|
337 | let fs_contents = if is_symlink { | |
|
338 | get_bytes_from_os_string(vfs.read_link(fs_path)?.into_os_string()) | |
|
339 | } else { | |
|
340 | vfs.read(fs_path)? | |
|
341 | }; | |
|
324 | 342 | return Ok(contents_in_p1 != &*fs_contents); |
|
325 | 343 | } |
@@ -1,9 +1,5 b'' | |||
|
1 | 1 | #require execbit |
|
2 | 2 | |
|
3 | TODO: fix rhg bugs that make this test fail when status is enabled | |
|
4 | $ unset RHG_STATUS | |
|
5 | ||
|
6 | ||
|
7 | 3 | $ hg init |
|
8 | 4 | $ echo a > a |
|
9 | 5 | $ hg ci -Am'not executable' |
@@ -4,10 +4,6 b' Testing merge involving change to the ex' | |||
|
4 | 4 | |
|
5 | 5 | #require execbit |
|
6 | 6 | |
|
7 | TODO: fix rhg bugs that make this test fail when status is enabled | |
|
8 | $ unset RHG_STATUS | |
|
9 | ||
|
10 | ||
|
11 | 7 | Initial setup |
|
12 | 8 |
============= |
|
13 | 9 |
General Comments 0
You need to be logged in to leave comments.
Login now