|
|
use sha1::{Digest, 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 = Sha1::digest(&dired[..dirlen]);
|
|
|
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)
|
|
|
}
|
|
|
}
|
|
|
|