Details
Details
- Reviewers
- None
- Group Reviewers
hg-reviewers - Commits
- rHGaebc976fd7d5: hg-core: add path_encode
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
| hg-reviewers |
| No Linters Available |
| No Unit Test Coverage |
| Path | Packages | |||
|---|---|---|---|---|
| M | rust/hg-core/src/revlog.rs (1 line) | |||
| A | M | rust/hg-core/src/revlog/path_encode.rs (653 lines) |
| Commit | Parents | Author | Summary | Date |
|---|---|---|---|---|
| 20d681a1a3f7 | bebc93623bb5 | Antoine Cezar | Sep 15 2020, 10:45 AM |
| Status | Author | Revision | |
|---|---|---|---|
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | D9049 hg-core: add path_encode | |
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | D8962 rhg: Add debug timing | |
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar | ||
| Closed | acezar |
| // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net> | // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net> | ||||
| // and Mercurial contributors | // and Mercurial contributors | ||||
| // | // | ||||
| // This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
| // GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
| //! Mercurial concepts for handling revision history | //! Mercurial concepts for handling revision history | ||||
| pub mod node; | pub mod node; | ||||
| pub mod nodemap; | pub mod nodemap; | ||||
| pub mod path_encode; | |||||
| pub use node::{Node, NodeError, NodePrefix, NodePrefixRef}; | pub use node::{Node, NodeError, NodePrefix, NodePrefixRef}; | ||||
| pub mod changelog; | pub mod changelog; | ||||
| pub mod index; | pub mod index; | ||||
| pub mod manifest; | pub mod manifest; | ||||
| pub mod patch; | pub mod patch; | ||||
| pub mod revlog; | pub mod revlog; | ||||
| /// Mercurial revision numbers | /// Mercurial revision numbers | ||||
| use crypto::digest::Digest; | |||||
| use crypto::sha1::Sha1; | |||||
| #[derive(PartialEq, Debug)] | |||||
| #[allow(non_camel_case_types)] | |||||
| enum path_state { | |||||
| START, /* first byte of a path component */ | |||||
| A, /* "AUX" */ | |||||
| AU, | |||||
| THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */ | |||||
| C, /* "CON" or "COMn" */ | |||||
| CO, | |||||
| COMLPT, /* "COM" or "LPT" */ | |||||
| COMLPTn, | |||||
| L, | |||||
| LP, | |||||
| N, | |||||
| NU, | |||||
| P, /* "PRN" */ | |||||
| PR, | |||||
| LDOT, /* leading '.' */ | |||||
| DOT, /* '.' in a non-leading position */ | |||||
| H, /* ".h" */ | |||||
| HGDI, /* ".hg", ".d", or ".i" */ | |||||
| SPACE, | |||||
| DEFAULT, /* byte of a path component after the first */ | |||||
| } | |||||
| /* state machine for dir-encoding */ | |||||
| #[allow(non_camel_case_types)] | |||||
| enum dir_state { | |||||
| DDOT, | |||||
| DH, | |||||
| DHGDI, | |||||
| DDEFAULT, | |||||
| } | |||||
| fn inset(bitset: &[u32; 8], c: u8) -> bool { | |||||
| bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0 | |||||
| } | |||||
| fn charcopy(dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { | |||||
| if let Some(slice) = dest { | |||||
| slice[*destlen] = c | |||||
| } | |||||
| *destlen += 1 | |||||
| } | |||||
| fn memcopy(dest: Option<&mut [u8]>, destlen: &mut usize, src: &[u8]) { | |||||
| if let Some(slice) = dest { | |||||
| slice[*destlen..*destlen + src.len()].copy_from_slice(src) | |||||
| } | |||||
| *destlen += src.len(); | |||||
| } | |||||
| fn rewrap_option<'a, 'b: 'a>( | |||||
| x: &'a mut Option<&'b mut [u8]>, | |||||
| ) -> Option<&'a mut [u8]> { | |||||
| match x { | |||||
| None => None, | |||||
| Some(y) => Some(y), | |||||
| } | |||||
| } | |||||
| fn hexencode<'a>(mut dest: Option<&'a mut [u8]>, destlen: &mut usize, c: u8) { | |||||
| let hexdigit = b"0123456789abcdef"; | |||||
| charcopy( | |||||
| rewrap_option(&mut dest), | |||||
| destlen, | |||||
| hexdigit[(c as usize) >> 4], | |||||
| ); | |||||
| charcopy(dest, destlen, hexdigit[(c as usize) & 15]); | |||||
| } | |||||
| /* 3-byte escape: tilde followed by two hex digits */ | |||||
| fn escape3(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { | |||||
| charcopy(rewrap_option(&mut dest), destlen, b'~'); | |||||
| hexencode(dest, destlen, c); | |||||
| } | |||||
| fn encode_dir(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize { | |||||
| let mut state = dir_state::DDEFAULT; | |||||
| let mut i = 0; | |||||
| let mut destlen = 0; | |||||
| while i < src.len() { | |||||
| match state { | |||||
| dir_state::DDOT => match src[i] { | |||||
| b'd' | b'i' => { | |||||
| state = dir_state::DHGDI; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'h' => { | |||||
| state = dir_state::DH; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| _ => { | |||||
| state = dir_state::DDEFAULT; | |||||
| } | |||||
| }, | |||||
| dir_state::DH => { | |||||
| if src[i] == b'g' { | |||||
| state = dir_state::DHGDI; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } else { | |||||
| state = dir_state::DDEFAULT; | |||||
| } | |||||
| } | |||||
| dir_state::DHGDI => { | |||||
| if src[i] == b'/' { | |||||
| memcopy(rewrap_option(&mut dest), &mut destlen, b".hg"); | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| state = dir_state::DDEFAULT; | |||||
| } | |||||
| dir_state::DDEFAULT => { | |||||
| if src[i] == b'.' { | |||||
| state = dir_state::DDOT | |||||
| } | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| } | |||||
| } | |||||
| destlen | |||||
| } | |||||
| fn _encode( | |||||
| twobytes: &[u32; 8], | |||||
| onebyte: &[u32; 8], | |||||
| mut dest: Option<&mut [u8]>, | |||||
| src: &[u8], | |||||
| encodedir: bool, | |||||
| ) -> usize { | |||||
| let mut state = path_state::START; | |||||
| let mut i = 0; | |||||
| let mut destlen = 0; | |||||
| let len = src.len(); | |||||
| while i < len { | |||||
| match state { | |||||
| path_state::START => match src[i] { | |||||
| b'/' => { | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'.' => { | |||||
| state = path_state::LDOT; | |||||
| escape3(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b' ' => { | |||||
| state = path_state::DEFAULT; | |||||
| escape3(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'a' => { | |||||
| state = path_state::A; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'c' => { | |||||
| state = path_state::C; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'l' => { | |||||
| state = path_state::L; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'n' => { | |||||
| state = path_state::N; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'p' => { | |||||
| state = path_state::P; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| _ => { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| }, | |||||
| path_state::A => { | |||||
| if src[i] == b'u' { | |||||
| state = path_state::AU; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::AU => { | |||||
| if src[i] == b'x' { | |||||
| state = path_state::THIRD; | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::THIRD => { | |||||
| state = path_state::DEFAULT; | |||||
| match src[i] { | |||||
| b'.' | b'/' | b'\0' => escape3( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| src[i - 1], | |||||
| ), | |||||
| _ => i -= 1, | |||||
| } | |||||
| } | |||||
| path_state::C => { | |||||
| if src[i] == b'o' { | |||||
| state = path_state::CO; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::CO => { | |||||
| if src[i] == b'm' { | |||||
| state = path_state::COMLPT; | |||||
| i += 1; | |||||
| } else if src[i] == b'n' { | |||||
| state = path_state::THIRD; | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::COMLPT => { | |||||
| if src[i] >= b'1' && src[i] <= b'9' { | |||||
| state = path_state::COMLPTn; | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| charcopy( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| src[i - 1], | |||||
| ); | |||||
| } | |||||
| } | |||||
| path_state::COMLPTn => { | |||||
| state = path_state::DEFAULT; | |||||
| match src[i] { | |||||
| b'.' | b'/' | b'\0' => { | |||||
| escape3( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| src[i - 2], | |||||
| ); | |||||
| charcopy( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| src[i - 1], | |||||
| ); | |||||
| } | |||||
| _ => { | |||||
| memcopy( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| &src[i - 2..i], | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| path_state::L => { | |||||
| if src[i] == b'p' { | |||||
| state = path_state::LP; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::LP => { | |||||
| if src[i] == b't' { | |||||
| state = path_state::COMLPT; | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::N => { | |||||
| if src[i] == b'u' { | |||||
| state = path_state::NU; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::NU => { | |||||
| if src[i] == b'l' { | |||||
| state = path_state::THIRD; | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::P => { | |||||
| if src[i] == b'r' { | |||||
| state = path_state::PR; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::PR => { | |||||
| if src[i] == b'n' { | |||||
| state = path_state::THIRD; | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::LDOT => match src[i] { | |||||
| b'd' | b'i' => { | |||||
| state = path_state::HGDI; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'h' => { | |||||
| state = path_state::H; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| _ => { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| }, | |||||
| path_state::DOT => match src[i] { | |||||
| b'/' | b'\0' => { | |||||
| state = path_state::START; | |||||
| memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e"); | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'd' | b'i' => { | |||||
| state = path_state::HGDI; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, b'.'); | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| b'h' => { | |||||
| state = path_state::H; | |||||
| memcopy(rewrap_option(&mut dest), &mut destlen, b".h"); | |||||
| i += 1; | |||||
| } | |||||
| _ => { | |||||
| state = path_state::DEFAULT; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, b'.'); | |||||
| } | |||||
| }, | |||||
| path_state::H => { | |||||
| if src[i] == b'g' { | |||||
| state = path_state::HGDI; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::HGDI => { | |||||
| if src[i] == b'/' { | |||||
| state = path_state::START; | |||||
| if encodedir { | |||||
| memcopy( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| b".hg", | |||||
| ); | |||||
| } | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1 | |||||
| } else { | |||||
| state = path_state::DEFAULT; | |||||
| } | |||||
| } | |||||
| path_state::SPACE => match src[i] { | |||||
| b'/' | b'\0' => { | |||||
| state = path_state::START; | |||||
| memcopy(rewrap_option(&mut dest), &mut destlen, b"~20"); | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| _ => { | |||||
| state = path_state::DEFAULT; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, b' '); | |||||
| } | |||||
| }, | |||||
| path_state::DEFAULT => { | |||||
| while i != len && inset(onebyte, src[i]) { | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); | |||||
| i += 1; | |||||
| } | |||||
| if i == len { | |||||
| break; | |||||
| } | |||||
| match src[i] { | |||||
| b'.' => { | |||||
| state = path_state::DOT; | |||||
| i += 1 | |||||
| } | |||||
| b' ' => { | |||||
| state = path_state::SPACE; | |||||
| i += 1 | |||||
| } | |||||
| b'/' => { | |||||
| state = path_state::START; | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, b'/'); | |||||
| i += 1; | |||||
| } | |||||
| _ => { | |||||
| if inset(onebyte, src[i]) { | |||||
| loop { | |||||
| charcopy( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| src[i], | |||||
| ); | |||||
| i += 1; | |||||
| if !(i < len && inset(onebyte, src[i])) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } else if inset(twobytes, src[i]) { | |||||
| let c = src[i]; | |||||
| i += 1; | |||||
| charcopy( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| b'_', | |||||
| ); | |||||
| charcopy( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| if c == b'_' { b'_' } else { c + 32 }, | |||||
| ); | |||||
| } else { | |||||
| escape3( | |||||
| rewrap_option(&mut dest), | |||||
| &mut destlen, | |||||
| src[i], | |||||
| ); | |||||
| i += 1; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| match state { | |||||
| path_state::START => (), | |||||
| path_state::A => (), | |||||
| path_state::AU => (), | |||||
| path_state::THIRD => { | |||||
| escape3(rewrap_option(&mut dest), &mut destlen, src[i - 1]) | |||||
| } | |||||
| path_state::C => (), | |||||
| path_state::CO => (), | |||||
| path_state::COMLPT => { | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]) | |||||
| } | |||||
| path_state::COMLPTn => { | |||||
| escape3(rewrap_option(&mut dest), &mut destlen, src[i - 2]); | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]); | |||||
| } | |||||
| path_state::L => (), | |||||
| path_state::LP => (), | |||||
| path_state::N => (), | |||||
| path_state::NU => (), | |||||
| path_state::P => (), | |||||
| path_state::PR => (), | |||||
| path_state::LDOT => (), | |||||
| path_state::DOT => { | |||||
| memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e"); | |||||
| } | |||||
| path_state::H => (), | |||||
| path_state::HGDI => (), | |||||
| path_state::SPACE => { | |||||
| memcopy(rewrap_option(&mut dest), &mut destlen, b"~20"); | |||||
| } | |||||
| path_state::DEFAULT => (), | |||||
| }; | |||||
| destlen | |||||
| } | |||||
| fn basic_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize { | |||||
| let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0]; | |||||
| let onebyte: [u32; 8] = | |||||
| [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0]; | |||||
| _encode(&twobytes, &onebyte, dest, src, true) | |||||
| } | |||||
| const MAXSTOREPATHLEN: usize = 120; | |||||
| fn lower_encode(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize { | |||||
| let onebyte: [u32; 8] = | |||||
| [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0]; | |||||
| let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0]; | |||||
| let mut destlen = 0; | |||||
| for c in src { | |||||
| if inset(&onebyte, *c) { | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, *c) | |||||
| } else if inset(&lower, *c) { | |||||
| charcopy(rewrap_option(&mut dest), &mut destlen, *c + 32) | |||||
| } else { | |||||
| escape3(rewrap_option(&mut dest), &mut destlen, *c) | |||||
| } | |||||
| } | |||||
| destlen | |||||
| } | |||||
| fn aux_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize { | |||||
| let twobytes = [0; 8]; | |||||
| let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0]; | |||||
| _encode(&twobytes, &onebyte, dest, src, false) | |||||
| } | |||||
| fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> { | |||||
| let dirprefixlen = 8; | |||||
| let maxshortdirslen = 68; | |||||
| let mut destlen = 0; | |||||
| let last_slash = src.iter().rposition(|b| *b == b'/'); | |||||
| let last_dot: Option<usize> = { | |||||
| let s = last_slash.unwrap_or(0); | |||||
| src[s..] | |||||
| .iter() | |||||
| .rposition(|b| *b == b'.') | |||||
| .and_then(|i| Some(i + s)) | |||||
| }; | |||||
| let mut dest = vec![0; MAXSTOREPATHLEN]; | |||||
| memcopy(Some(&mut dest), &mut destlen, b"dh/"); | |||||
| { | |||||
| let mut first = true; | |||||
| for slice in src[..last_slash.unwrap_or_else(|| src.len())] | |||||
| .split(|b| *b == b'/') | |||||
| { | |||||
| let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)]; | |||||
| if destlen + (slice.len() + if first { 0 } else { 1 }) | |||||
| > maxshortdirslen + 3 | |||||
| { | |||||
| break; | |||||
| } else { | |||||
| if !first { | |||||
| charcopy(Some(&mut dest), &mut destlen, b'/') | |||||
| }; | |||||
| memcopy(Some(&mut dest), &mut destlen, slice); | |||||
| if dest[destlen - 1] == b'.' || dest[destlen - 1] == b' ' { | |||||
| dest[destlen - 1] = b'_' | |||||
| } | |||||
| } | |||||
| first = false; | |||||
| } | |||||
| if !first { | |||||
| charcopy(Some(&mut dest), &mut destlen, b'/'); | |||||
| } | |||||
| } | |||||
| let used = destlen + 40 + { | |||||
| if let Some(l) = last_dot { | |||||
| src.len() - l | |||||
| } else { | |||||
| 0 | |||||
| } | |||||
| }; | |||||
| if MAXSTOREPATHLEN > used { | |||||
| let slop = MAXSTOREPATHLEN - used; | |||||
| let basenamelen = match last_slash { | |||||
| Some(l) => src.len() - l - 1, | |||||
| None => src.len(), | |||||
| }; | |||||
| let basenamelen = std::cmp::min(basenamelen, slop); | |||||
| if basenamelen > 0 { | |||||
| let start = match last_slash { | |||||
| Some(l) => l + 1, | |||||
| None => 0, | |||||
| }; | |||||
| memcopy( | |||||
| Some(&mut dest), | |||||
| &mut destlen, | |||||
| &src[start..][..basenamelen], | |||||
| ) | |||||
| } | |||||
| } | |||||
| for c in sha { | |||||
| hexencode(Some(&mut dest), &mut destlen, *c); | |||||
| } | |||||
| if let Some(l) = last_dot { | |||||
| memcopy(Some(&mut dest), &mut destlen, &src[l..]); | |||||
| } | |||||
| if destlen == dest.len() { | |||||
| dest | |||||
| } else { | |||||
| // sometimes the path are shorter than MAXSTOREPATHLEN | |||||
| dest[..destlen].to_vec() | |||||
| } | |||||
| } | |||||
| const MAXENCODE: usize = 4096 * 4; | |||||
| fn hash_encode(src: &[u8]) -> Vec<u8> { | |||||
| let dired = &mut [0; MAXENCODE]; | |||||
| let lowered = &mut [0; MAXENCODE]; | |||||
| let auxed = &mut [0; MAXENCODE]; | |||||
| let baselen = (src.len() - 5) * 3; | |||||
| if baselen >= MAXENCODE { | |||||
| panic!("path_encode::hash_encore: string too long: {}", baselen) | |||||
| }; | |||||
| let dirlen = encode_dir(Some(&mut dired[..]), src); | |||||
| let sha = { | |||||
| let mut hasher = Sha1::new(); | |||||
| hasher.input(&dired[..dirlen]); | |||||
| let mut hash = vec![0; 20]; | |||||
| hasher.result(&mut hash); | |||||
| hash | |||||
| }; | |||||
| let lowerlen = lower_encode(Some(&mut lowered[..]), &dired[..dirlen][5..]); | |||||
| let auxlen = aux_encode(Some(&mut auxed[..]), &lowered[..lowerlen]); | |||||
| hash_mangle(&auxed[..auxlen], &sha) | |||||
| } | |||||
| pub fn path_encode(path: &[u8]) -> Vec<u8> { | |||||
| let newlen = if path.len() <= MAXSTOREPATHLEN { | |||||
| basic_encode(None, path) | |||||
| } else { | |||||
| MAXSTOREPATHLEN + 1 | |||||
| }; | |||||
| if newlen <= MAXSTOREPATHLEN { | |||||
| if newlen == path.len() { | |||||
| path.to_vec() | |||||
| } else { | |||||
| let mut res = vec![0; newlen]; | |||||
| basic_encode(Some(&mut res), path); | |||||
| res | |||||
| } | |||||
| } else { | |||||
| hash_encode(&path) | |||||
| } | |||||
| } | |||||