diff --git a/rust/hg-core/src/errors.rs b/rust/hg-core/src/errors.rs --- a/rust/hg-core/src/errors.rs +++ b/rust/hg-core/src/errors.rs @@ -42,6 +42,9 @@ /// and syntax of each value. #[from] ConfigValueParseError(ConfigValueParseError), + + /// Censored revision data. + CensoredNodeError, } /// Details about where an I/O error happened @@ -101,6 +104,9 @@ HgError::UnsupportedFeature(explanation) => { write!(f, "unsupported feature: {}", explanation) } + HgError::CensoredNodeError => { + write!(f, "encountered a censored node") + } HgError::ConfigValueParseError(error) => error.fmt(f), } } diff --git a/rust/hg-core/src/revlog/filelog.rs b/rust/hg-core/src/revlog/filelog.rs --- a/rust/hg-core/src/revlog/filelog.rs +++ b/rust/hg-core/src/revlog/filelog.rs @@ -95,7 +95,7 @@ // Let’s call `file_data_len` what would be returned by // `self.data().file_data().len()`. - if self.0.is_cencored() { + if self.0.is_censored() { let file_data_len = 0; return other_len != file_data_len; } diff --git a/rust/hg-core/src/revlog/revlog.rs b/rust/hg-core/src/revlog/revlog.rs --- a/rust/hg-core/src/revlog/revlog.rs +++ b/rust/hg-core/src/revlog/revlog.rs @@ -378,7 +378,7 @@ } } - pub fn is_cencored(&self) -> bool { + pub fn is_censored(&self) -> bool { (self.flags & REVISION_FLAG_CENSORED) != 0 } @@ -389,7 +389,7 @@ } /// The data for this entry, after resolving deltas if any. - pub fn data(&self) -> Result, HgError> { + pub fn rawdata(&self) -> Result, HgError> { let mut entry = self.clone(); let mut delta_chain = vec![]; @@ -414,6 +414,13 @@ Revlog::build_data_from_deltas(entry, &delta_chain)?.into() }; + Ok(data) + } + + fn check_data( + &self, + data: Cow<'a, [u8]>, + ) -> Result, HgError> { if self.revlog.check_hash( self.p1, self.p2, @@ -426,6 +433,14 @@ } } + pub fn data(&self) -> Result, HgError> { + let data = self.rawdata()?; + if self.is_censored() { + return Err(HgError::CensoredNodeError) + } + self.check_data(data) + } + /// Extract the data contained in the entry. /// This may be a delta. (See `is_delta`.) fn data_chunk(&self) -> Result, HgError> { diff --git a/rust/rhg/src/error.rs b/rust/rhg/src/error.rs --- a/rust/rhg/src/error.rs +++ b/rust/rhg/src/error.rs @@ -73,6 +73,9 @@ HgError::UnsupportedFeature(message) => { CommandError::unsupported(message) } + HgError::CensoredNodeError => { + CommandError::unsupported("Encountered a censored node") + } HgError::Abort { message, detailed_exit_code, diff --git a/tests/test-censor.t b/tests/test-censor.t --- a/tests/test-censor.t +++ b/tests/test-censor.t @@ -10,10 +10,6 @@ #endif - $ cat >> $HGRCPATH < [extensions] - > censor= - > EOF $ cp $HGRCPATH $HGRCPATH.orig Create repo with unimpeachable content @@ -81,7 +77,7 @@ (this also tests file pattern matching: path relative to cwd case) $ mkdir -p foo/bar/baz - $ hg --cwd foo/bar/baz censor -r $C2 -t "remove password" ../../../target + $ hg --config extensions.censor= --cwd foo/bar/baz censor -r $C2 -t "remove password" ../../../target $ hg cat -r $H1 target | head -n 10 Tainted file is now sanitized $ hg cat -r $H2 target | head -n 10 @@ -99,7 +95,7 @@ (this also tests file pattern matching: with 'path:' scheme) - $ hg --cwd foo/bar/baz censor -r $C1 path:target + $ hg --config extensions.censor= --cwd foo/bar/baz censor -r $C1 path:target $ hg cat -r $H1 target | head -n 10 Tainted file is now sanitized $ hg cat -r $H2 target | head -n 10 @@ -242,7 +238,7 @@ $ echo 'advanced head H1' > target $ hg ci -m 'advance head H1' target $ H1=`hg id --debug -i` - $ hg censor -r $C3 target + $ hg --config extensions.censor= censor -r $C3 target $ hg update -r $H2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg merge -r $C3 @@ -254,14 +250,14 @@ $ hg update -C -r $H2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg censor -r $H2 target + $ hg --config extensions.censor= censor -r $H2 target abort: cannot censor file in heads (78a8fc215e79) (clean/delete and commit first) [255] $ echo 'twiddling thumbs' > bystander $ hg ci -m 'bystander commit' $ H2=`hg id --debug -i` - $ hg censor -r "$H2^" target + $ hg --config extensions.censor= censor -r "$H2^" target abort: cannot censor file in heads (efbe78065929) (clean/delete and commit first) [255] @@ -273,7 +269,7 @@ $ H2=`hg id --debug -i` $ hg update -r "$H2^" 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg censor -r . target + $ hg --config extensions.censor= censor -r . target abort: cannot censor working directory (clean/delete/update first) [255] @@ -286,7 +282,7 @@ $ hg rm target $ hg ci -m 'delete target so it may be censored' $ H2=`hg id --debug -i` - $ hg censor -r $C4 target + $ hg --config extensions.censor= censor -r $C4 target $ hg cat -r $C4 target | head -n 10 $ hg cat -r "$H2^^" target | head -n 10 Tainted file now super sanitized @@ -314,7 +310,7 @@ $ hg revert -r "$H2^" target $ hg ci -m 'cleaned 100k passwords' $ H2=`hg id --debug -i` - $ hg censor -r $C5 target + $ hg --config extensions.censor= censor -r $C5 target $ hg cat -r $C5 target | head -n 10 $ hg cat -r $H2 target | head -n 10 fresh start @@ -393,7 +389,7 @@ $ CLEANREV=$H2 $ hg cat -r $REV target | head -n 10 Passwords: hunter2hunter2 - $ hg censor -r $REV target + $ hg --config extensions.censor= censor -r $REV target $ hg cat -r $REV target | head -n 10 $ hg cat -r $CLEANREV target | head -n 10 Re-sanitized; nothing to see here @@ -503,7 +499,7 @@ Can import bundle where first revision of a file is censored $ hg init ../rinit - $ hg censor -r 0 target + $ hg --config extensions.censor= censor -r 0 target $ hg bundle -r 0 --base null ../rinit/initbundle 1 changesets found $ cd ../rinit @@ -553,7 +549,7 @@ $ hg cat -r $B1 target | wc -l *50002 (re) - $ hg censor -r $B1 target + $ hg --config extensions.censor= censor -r $B1 target $ hg cat -r $B1 target | wc -l *0 (re)