##// END OF EJS Templates
rhg: demonstrate a bug in path_encode...
Arseniy Alekseyev -
r50990:362fe347 default
parent child Browse files
Show More
@@ -1,645 +1,664 b''
1 use sha1::{Digest, Sha1};
1 use sha1::{Digest, Sha1};
2
2
3 #[derive(PartialEq, Debug)]
3 #[derive(PartialEq, Debug)]
4 #[allow(non_camel_case_types)]
4 #[allow(non_camel_case_types)]
5 #[allow(clippy::upper_case_acronyms)]
5 #[allow(clippy::upper_case_acronyms)]
6 enum path_state {
6 enum path_state {
7 START, /* first byte of a path component */
7 START, /* first byte of a path component */
8 A, /* "AUX" */
8 A, /* "AUX" */
9 AU,
9 AU,
10 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
10 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
11 C, /* "CON" or "COMn" */
11 C, /* "CON" or "COMn" */
12 CO,
12 CO,
13 COMLPT, /* "COM" or "LPT" */
13 COMLPT, /* "COM" or "LPT" */
14 COMLPTn,
14 COMLPTn,
15 L,
15 L,
16 LP,
16 LP,
17 N,
17 N,
18 NU,
18 NU,
19 P, /* "PRN" */
19 P, /* "PRN" */
20 PR,
20 PR,
21 LDOT, /* leading '.' */
21 LDOT, /* leading '.' */
22 DOT, /* '.' in a non-leading position */
22 DOT, /* '.' in a non-leading position */
23 H, /* ".h" */
23 H, /* ".h" */
24 HGDI, /* ".hg", ".d", or ".i" */
24 HGDI, /* ".hg", ".d", or ".i" */
25 SPACE,
25 SPACE,
26 DEFAULT, /* byte of a path component after the first */
26 DEFAULT, /* byte of a path component after the first */
27 }
27 }
28
28
29 /* state machine for dir-encoding */
29 /* state machine for dir-encoding */
30 #[allow(non_camel_case_types)]
30 #[allow(non_camel_case_types)]
31 #[allow(clippy::upper_case_acronyms)]
31 #[allow(clippy::upper_case_acronyms)]
32 enum dir_state {
32 enum dir_state {
33 DDOT,
33 DDOT,
34 DH,
34 DH,
35 DHGDI,
35 DHGDI,
36 DDEFAULT,
36 DDEFAULT,
37 }
37 }
38
38
39 fn inset(bitset: &[u32; 8], c: u8) -> bool {
39 fn inset(bitset: &[u32; 8], c: u8) -> bool {
40 bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0
40 bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0
41 }
41 }
42
42
43 fn charcopy(dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
43 fn charcopy(dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
44 if let Some(slice) = dest {
44 if let Some(slice) = dest {
45 slice[*destlen] = c
45 slice[*destlen] = c
46 }
46 }
47 *destlen += 1
47 *destlen += 1
48 }
48 }
49
49
50 fn memcopy(dest: Option<&mut [u8]>, destlen: &mut usize, src: &[u8]) {
50 fn memcopy(dest: Option<&mut [u8]>, destlen: &mut usize, src: &[u8]) {
51 if let Some(slice) = dest {
51 if let Some(slice) = dest {
52 slice[*destlen..*destlen + src.len()].copy_from_slice(src)
52 slice[*destlen..*destlen + src.len()].copy_from_slice(src)
53 }
53 }
54 *destlen += src.len();
54 *destlen += src.len();
55 }
55 }
56
56
57 fn rewrap_option<'a, 'b: 'a>(
57 fn rewrap_option<'a, 'b: 'a>(
58 x: &'a mut Option<&'b mut [u8]>,
58 x: &'a mut Option<&'b mut [u8]>,
59 ) -> Option<&'a mut [u8]> {
59 ) -> Option<&'a mut [u8]> {
60 match x {
60 match x {
61 None => None,
61 None => None,
62 Some(y) => Some(y),
62 Some(y) => Some(y),
63 }
63 }
64 }
64 }
65
65
66 fn hexencode(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
66 fn hexencode(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
67 let hexdigit = b"0123456789abcdef";
67 let hexdigit = b"0123456789abcdef";
68 charcopy(
68 charcopy(
69 rewrap_option(&mut dest),
69 rewrap_option(&mut dest),
70 destlen,
70 destlen,
71 hexdigit[(c as usize) >> 4],
71 hexdigit[(c as usize) >> 4],
72 );
72 );
73 charcopy(dest, destlen, hexdigit[(c as usize) & 15]);
73 charcopy(dest, destlen, hexdigit[(c as usize) & 15]);
74 }
74 }
75
75
76 /* 3-byte escape: tilde followed by two hex digits */
76 /* 3-byte escape: tilde followed by two hex digits */
77 fn escape3(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
77 fn escape3(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
78 charcopy(rewrap_option(&mut dest), destlen, b'~');
78 charcopy(rewrap_option(&mut dest), destlen, b'~');
79 hexencode(dest, destlen, c);
79 hexencode(dest, destlen, c);
80 }
80 }
81
81
82 fn encode_dir(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize {
82 fn encode_dir(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize {
83 let mut state = dir_state::DDEFAULT;
83 let mut state = dir_state::DDEFAULT;
84 let mut i = 0;
84 let mut i = 0;
85 let mut destlen = 0;
85 let mut destlen = 0;
86
86
87 while i < src.len() {
87 while i < src.len() {
88 match state {
88 match state {
89 dir_state::DDOT => match src[i] {
89 dir_state::DDOT => match src[i] {
90 b'd' | b'i' => {
90 b'd' | b'i' => {
91 state = dir_state::DHGDI;
91 state = dir_state::DHGDI;
92 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
92 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
93 i += 1;
93 i += 1;
94 }
94 }
95 b'h' => {
95 b'h' => {
96 state = dir_state::DH;
96 state = dir_state::DH;
97 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
97 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
98 i += 1;
98 i += 1;
99 }
99 }
100 _ => {
100 _ => {
101 state = dir_state::DDEFAULT;
101 state = dir_state::DDEFAULT;
102 }
102 }
103 },
103 },
104 dir_state::DH => {
104 dir_state::DH => {
105 if src[i] == b'g' {
105 if src[i] == b'g' {
106 state = dir_state::DHGDI;
106 state = dir_state::DHGDI;
107 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
107 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
108 i += 1;
108 i += 1;
109 } else {
109 } else {
110 state = dir_state::DDEFAULT;
110 state = dir_state::DDEFAULT;
111 }
111 }
112 }
112 }
113 dir_state::DHGDI => {
113 dir_state::DHGDI => {
114 if src[i] == b'/' {
114 if src[i] == b'/' {
115 memcopy(rewrap_option(&mut dest), &mut destlen, b".hg");
115 memcopy(rewrap_option(&mut dest), &mut destlen, b".hg");
116 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
116 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
117 i += 1;
117 i += 1;
118 }
118 }
119 state = dir_state::DDEFAULT;
119 state = dir_state::DDEFAULT;
120 }
120 }
121 dir_state::DDEFAULT => {
121 dir_state::DDEFAULT => {
122 if src[i] == b'.' {
122 if src[i] == b'.' {
123 state = dir_state::DDOT
123 state = dir_state::DDOT
124 }
124 }
125 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
125 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
126 i += 1;
126 i += 1;
127 }
127 }
128 }
128 }
129 }
129 }
130 destlen
130 destlen
131 }
131 }
132
132
133 fn _encode(
133 fn _encode(
134 twobytes: &[u32; 8],
134 twobytes: &[u32; 8],
135 onebyte: &[u32; 8],
135 onebyte: &[u32; 8],
136 mut dest: Option<&mut [u8]>,
136 mut dest: Option<&mut [u8]>,
137 src: &[u8],
137 src: &[u8],
138 encodedir: bool,
138 encodedir: bool,
139 ) -> usize {
139 ) -> usize {
140 let mut state = path_state::START;
140 let mut state = path_state::START;
141 let mut i = 0;
141 let mut i = 0;
142 let mut destlen = 0;
142 let mut destlen = 0;
143 let len = src.len();
143 let len = src.len();
144
144
145 while i < len {
145 while i < len {
146 match state {
146 match state {
147 path_state::START => match src[i] {
147 path_state::START => match src[i] {
148 b'/' => {
148 b'/' => {
149 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
149 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
150 i += 1;
150 i += 1;
151 }
151 }
152 b'.' => {
152 b'.' => {
153 state = path_state::LDOT;
153 state = path_state::LDOT;
154 escape3(rewrap_option(&mut dest), &mut destlen, src[i]);
154 escape3(rewrap_option(&mut dest), &mut destlen, src[i]);
155 i += 1;
155 i += 1;
156 }
156 }
157 b' ' => {
157 b' ' => {
158 state = path_state::DEFAULT;
158 state = path_state::DEFAULT;
159 escape3(rewrap_option(&mut dest), &mut destlen, src[i]);
159 escape3(rewrap_option(&mut dest), &mut destlen, src[i]);
160 i += 1;
160 i += 1;
161 }
161 }
162 b'a' => {
162 b'a' => {
163 state = path_state::A;
163 state = path_state::A;
164 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
164 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
165 i += 1;
165 i += 1;
166 }
166 }
167 b'c' => {
167 b'c' => {
168 state = path_state::C;
168 state = path_state::C;
169 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
169 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
170 i += 1;
170 i += 1;
171 }
171 }
172 b'l' => {
172 b'l' => {
173 state = path_state::L;
173 state = path_state::L;
174 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
174 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
175 i += 1;
175 i += 1;
176 }
176 }
177 b'n' => {
177 b'n' => {
178 state = path_state::N;
178 state = path_state::N;
179 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
179 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
180 i += 1;
180 i += 1;
181 }
181 }
182 b'p' => {
182 b'p' => {
183 state = path_state::P;
183 state = path_state::P;
184 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
184 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
185 i += 1;
185 i += 1;
186 }
186 }
187 _ => {
187 _ => {
188 state = path_state::DEFAULT;
188 state = path_state::DEFAULT;
189 }
189 }
190 },
190 },
191 path_state::A => {
191 path_state::A => {
192 if src[i] == b'u' {
192 if src[i] == b'u' {
193 state = path_state::AU;
193 state = path_state::AU;
194 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
194 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
195 i += 1;
195 i += 1;
196 } else {
196 } else {
197 state = path_state::DEFAULT;
197 state = path_state::DEFAULT;
198 }
198 }
199 }
199 }
200 path_state::AU => {
200 path_state::AU => {
201 if src[i] == b'x' {
201 if src[i] == b'x' {
202 state = path_state::THIRD;
202 state = path_state::THIRD;
203 i += 1;
203 i += 1;
204 } else {
204 } else {
205 state = path_state::DEFAULT;
205 state = path_state::DEFAULT;
206 }
206 }
207 }
207 }
208 path_state::THIRD => {
208 path_state::THIRD => {
209 state = path_state::DEFAULT;
209 state = path_state::DEFAULT;
210 match src[i] {
210 match src[i] {
211 b'.' | b'/' | b'\0' => escape3(
211 b'.' | b'/' | b'\0' => escape3(
212 rewrap_option(&mut dest),
212 rewrap_option(&mut dest),
213 &mut destlen,
213 &mut destlen,
214 src[i - 1],
214 src[i - 1],
215 ),
215 ),
216 _ => i -= 1,
216 _ => i -= 1,
217 }
217 }
218 }
218 }
219 path_state::C => {
219 path_state::C => {
220 if src[i] == b'o' {
220 if src[i] == b'o' {
221 state = path_state::CO;
221 state = path_state::CO;
222 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
222 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
223 i += 1;
223 i += 1;
224 } else {
224 } else {
225 state = path_state::DEFAULT;
225 state = path_state::DEFAULT;
226 }
226 }
227 }
227 }
228 path_state::CO => {
228 path_state::CO => {
229 if src[i] == b'm' {
229 if src[i] == b'm' {
230 state = path_state::COMLPT;
230 state = path_state::COMLPT;
231 i += 1;
231 i += 1;
232 } else if src[i] == b'n' {
232 } else if src[i] == b'n' {
233 state = path_state::THIRD;
233 state = path_state::THIRD;
234 i += 1;
234 i += 1;
235 } else {
235 } else {
236 state = path_state::DEFAULT;
236 state = path_state::DEFAULT;
237 }
237 }
238 }
238 }
239 path_state::COMLPT => {
239 path_state::COMLPT => {
240 if src[i] >= b'1' && src[i] <= b'9' {
240 if src[i] >= b'1' && src[i] <= b'9' {
241 state = path_state::COMLPTn;
241 state = path_state::COMLPTn;
242 i += 1;
242 i += 1;
243 } else {
243 } else {
244 state = path_state::DEFAULT;
244 state = path_state::DEFAULT;
245 charcopy(
245 charcopy(
246 rewrap_option(&mut dest),
246 rewrap_option(&mut dest),
247 &mut destlen,
247 &mut destlen,
248 src[i - 1],
248 src[i - 1],
249 );
249 );
250 }
250 }
251 }
251 }
252 path_state::COMLPTn => {
252 path_state::COMLPTn => {
253 state = path_state::DEFAULT;
253 state = path_state::DEFAULT;
254 match src[i] {
254 match src[i] {
255 b'.' | b'/' | b'\0' => {
255 b'.' | b'/' | b'\0' => {
256 escape3(
256 escape3(
257 rewrap_option(&mut dest),
257 rewrap_option(&mut dest),
258 &mut destlen,
258 &mut destlen,
259 src[i - 2],
259 src[i - 2],
260 );
260 );
261 charcopy(
261 charcopy(
262 rewrap_option(&mut dest),
262 rewrap_option(&mut dest),
263 &mut destlen,
263 &mut destlen,
264 src[i - 1],
264 src[i - 1],
265 );
265 );
266 }
266 }
267 _ => {
267 _ => {
268 memcopy(
268 memcopy(
269 rewrap_option(&mut dest),
269 rewrap_option(&mut dest),
270 &mut destlen,
270 &mut destlen,
271 &src[i - 2..i],
271 &src[i - 2..i],
272 );
272 );
273 }
273 }
274 }
274 }
275 }
275 }
276 path_state::L => {
276 path_state::L => {
277 if src[i] == b'p' {
277 if src[i] == b'p' {
278 state = path_state::LP;
278 state = path_state::LP;
279 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
279 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
280 i += 1;
280 i += 1;
281 } else {
281 } else {
282 state = path_state::DEFAULT;
282 state = path_state::DEFAULT;
283 }
283 }
284 }
284 }
285 path_state::LP => {
285 path_state::LP => {
286 if src[i] == b't' {
286 if src[i] == b't' {
287 state = path_state::COMLPT;
287 state = path_state::COMLPT;
288 i += 1;
288 i += 1;
289 } else {
289 } else {
290 state = path_state::DEFAULT;
290 state = path_state::DEFAULT;
291 }
291 }
292 }
292 }
293 path_state::N => {
293 path_state::N => {
294 if src[i] == b'u' {
294 if src[i] == b'u' {
295 state = path_state::NU;
295 state = path_state::NU;
296 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
296 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
297 i += 1;
297 i += 1;
298 } else {
298 } else {
299 state = path_state::DEFAULT;
299 state = path_state::DEFAULT;
300 }
300 }
301 }
301 }
302 path_state::NU => {
302 path_state::NU => {
303 if src[i] == b'l' {
303 if src[i] == b'l' {
304 state = path_state::THIRD;
304 state = path_state::THIRD;
305 i += 1;
305 i += 1;
306 } else {
306 } else {
307 state = path_state::DEFAULT;
307 state = path_state::DEFAULT;
308 }
308 }
309 }
309 }
310 path_state::P => {
310 path_state::P => {
311 if src[i] == b'r' {
311 if src[i] == b'r' {
312 state = path_state::PR;
312 state = path_state::PR;
313 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
313 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
314 i += 1;
314 i += 1;
315 } else {
315 } else {
316 state = path_state::DEFAULT;
316 state = path_state::DEFAULT;
317 }
317 }
318 }
318 }
319 path_state::PR => {
319 path_state::PR => {
320 if src[i] == b'n' {
320 if src[i] == b'n' {
321 state = path_state::THIRD;
321 state = path_state::THIRD;
322 i += 1;
322 i += 1;
323 } else {
323 } else {
324 state = path_state::DEFAULT;
324 state = path_state::DEFAULT;
325 }
325 }
326 }
326 }
327 path_state::LDOT => match src[i] {
327 path_state::LDOT => match src[i] {
328 b'd' | b'i' => {
328 b'd' | b'i' => {
329 state = path_state::HGDI;
329 state = path_state::HGDI;
330 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
330 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
331 i += 1;
331 i += 1;
332 }
332 }
333 b'h' => {
333 b'h' => {
334 state = path_state::H;
334 state = path_state::H;
335 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
335 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
336 i += 1;
336 i += 1;
337 }
337 }
338 _ => {
338 _ => {
339 state = path_state::DEFAULT;
339 state = path_state::DEFAULT;
340 }
340 }
341 },
341 },
342 path_state::DOT => match src[i] {
342 path_state::DOT => match src[i] {
343 b'/' | b'\0' => {
343 b'/' | b'\0' => {
344 state = path_state::START;
344 state = path_state::START;
345 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e");
345 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e");
346 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
346 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
347 i += 1;
347 i += 1;
348 }
348 }
349 b'd' | b'i' => {
349 b'd' | b'i' => {
350 state = path_state::HGDI;
350 state = path_state::HGDI;
351 charcopy(rewrap_option(&mut dest), &mut destlen, b'.');
351 charcopy(rewrap_option(&mut dest), &mut destlen, b'.');
352 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
352 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
353 i += 1;
353 i += 1;
354 }
354 }
355 b'h' => {
355 b'h' => {
356 state = path_state::H;
356 state = path_state::H;
357 memcopy(rewrap_option(&mut dest), &mut destlen, b".h");
357 memcopy(rewrap_option(&mut dest), &mut destlen, b".h");
358 i += 1;
358 i += 1;
359 }
359 }
360 _ => {
360 _ => {
361 state = path_state::DEFAULT;
361 state = path_state::DEFAULT;
362 charcopy(rewrap_option(&mut dest), &mut destlen, b'.');
362 charcopy(rewrap_option(&mut dest), &mut destlen, b'.');
363 }
363 }
364 },
364 },
365 path_state::H => {
365 path_state::H => {
366 if src[i] == b'g' {
366 if src[i] == b'g' {
367 state = path_state::HGDI;
367 state = path_state::HGDI;
368 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
368 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
369 i += 1;
369 i += 1;
370 } else {
370 } else {
371 state = path_state::DEFAULT;
371 state = path_state::DEFAULT;
372 }
372 }
373 }
373 }
374 path_state::HGDI => {
374 path_state::HGDI => {
375 if src[i] == b'/' {
375 if src[i] == b'/' {
376 state = path_state::START;
376 state = path_state::START;
377 if encodedir {
377 if encodedir {
378 memcopy(
378 memcopy(
379 rewrap_option(&mut dest),
379 rewrap_option(&mut dest),
380 &mut destlen,
380 &mut destlen,
381 b".hg",
381 b".hg",
382 );
382 );
383 }
383 }
384 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
384 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
385 i += 1
385 i += 1
386 } else {
386 } else {
387 state = path_state::DEFAULT;
387 state = path_state::DEFAULT;
388 }
388 }
389 }
389 }
390 path_state::SPACE => match src[i] {
390 path_state::SPACE => match src[i] {
391 b'/' | b'\0' => {
391 b'/' | b'\0' => {
392 state = path_state::START;
392 state = path_state::START;
393 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20");
393 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20");
394 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
394 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
395 i += 1;
395 i += 1;
396 }
396 }
397 _ => {
397 _ => {
398 state = path_state::DEFAULT;
398 state = path_state::DEFAULT;
399 charcopy(rewrap_option(&mut dest), &mut destlen, b' ');
399 charcopy(rewrap_option(&mut dest), &mut destlen, b' ');
400 }
400 }
401 },
401 },
402 path_state::DEFAULT => {
402 path_state::DEFAULT => {
403 while i != len && inset(onebyte, src[i]) {
403 while i != len && inset(onebyte, src[i]) {
404 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
404 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
405 i += 1;
405 i += 1;
406 }
406 }
407 if i == len {
407 if i == len {
408 break;
408 break;
409 }
409 }
410 match src[i] {
410 match src[i] {
411 b'.' => {
411 b'.' => {
412 state = path_state::DOT;
412 state = path_state::DOT;
413 i += 1
413 i += 1
414 }
414 }
415 b' ' => {
415 b' ' => {
416 state = path_state::SPACE;
416 state = path_state::SPACE;
417 i += 1
417 i += 1
418 }
418 }
419 b'/' => {
419 b'/' => {
420 state = path_state::START;
420 state = path_state::START;
421 charcopy(rewrap_option(&mut dest), &mut destlen, b'/');
421 charcopy(rewrap_option(&mut dest), &mut destlen, b'/');
422 i += 1;
422 i += 1;
423 }
423 }
424 _ => {
424 _ => {
425 if inset(onebyte, src[i]) {
425 if inset(onebyte, src[i]) {
426 loop {
426 loop {
427 charcopy(
427 charcopy(
428 rewrap_option(&mut dest),
428 rewrap_option(&mut dest),
429 &mut destlen,
429 &mut destlen,
430 src[i],
430 src[i],
431 );
431 );
432 i += 1;
432 i += 1;
433 if !(i < len && inset(onebyte, src[i])) {
433 if !(i < len && inset(onebyte, src[i])) {
434 break;
434 break;
435 }
435 }
436 }
436 }
437 } else if inset(twobytes, src[i]) {
437 } else if inset(twobytes, src[i]) {
438 let c = src[i];
438 let c = src[i];
439 i += 1;
439 i += 1;
440 charcopy(
440 charcopy(
441 rewrap_option(&mut dest),
441 rewrap_option(&mut dest),
442 &mut destlen,
442 &mut destlen,
443 b'_',
443 b'_',
444 );
444 );
445 charcopy(
445 charcopy(
446 rewrap_option(&mut dest),
446 rewrap_option(&mut dest),
447 &mut destlen,
447 &mut destlen,
448 if c == b'_' { b'_' } else { c + 32 },
448 if c == b'_' { b'_' } else { c + 32 },
449 );
449 );
450 } else {
450 } else {
451 escape3(
451 escape3(
452 rewrap_option(&mut dest),
452 rewrap_option(&mut dest),
453 &mut destlen,
453 &mut destlen,
454 src[i],
454 src[i],
455 );
455 );
456 i += 1;
456 i += 1;
457 }
457 }
458 }
458 }
459 }
459 }
460 }
460 }
461 }
461 }
462 }
462 }
463 match state {
463 match state {
464 path_state::START => (),
464 path_state::START => (),
465 path_state::A => (),
465 path_state::A => (),
466 path_state::AU => (),
466 path_state::AU => (),
467 path_state::THIRD => {
467 path_state::THIRD => {
468 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 1])
468 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 1])
469 }
469 }
470 path_state::C => (),
470 path_state::C => (),
471 path_state::CO => (),
471 path_state::CO => (),
472 path_state::COMLPT => {
472 path_state::COMLPT => {
473 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1])
473 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1])
474 }
474 }
475 path_state::COMLPTn => {
475 path_state::COMLPTn => {
476 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 2]);
476 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 2]);
477 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]);
477 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]);
478 }
478 }
479 path_state::L => (),
479 path_state::L => (),
480 path_state::LP => (),
480 path_state::LP => (),
481 path_state::N => (),
481 path_state::N => (),
482 path_state::NU => (),
482 path_state::NU => (),
483 path_state::P => (),
483 path_state::P => (),
484 path_state::PR => (),
484 path_state::PR => (),
485 path_state::LDOT => (),
485 path_state::LDOT => (),
486 path_state::DOT => {
486 path_state::DOT => {
487 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e");
487 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e");
488 }
488 }
489 path_state::H => (),
489 path_state::H => (),
490 path_state::HGDI => (),
490 path_state::HGDI => (),
491 path_state::SPACE => {
491 path_state::SPACE => {
492 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20");
492 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20");
493 }
493 }
494 path_state::DEFAULT => (),
494 path_state::DEFAULT => (),
495 };
495 };
496 destlen
496 destlen
497 }
497 }
498
498
499 fn basic_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
499 fn basic_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
500 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0];
500 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0];
501 let onebyte: [u32; 8] =
501 let onebyte: [u32; 8] =
502 [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0];
502 [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0];
503 _encode(&twobytes, &onebyte, dest, src, true)
503 _encode(&twobytes, &onebyte, dest, src, true)
504 }
504 }
505
505
506 const MAXSTOREPATHLEN: usize = 120;
506 const MAXSTOREPATHLEN: usize = 120;
507
507
508 fn lower_encode(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize {
508 fn lower_encode(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize {
509 let onebyte: [u32; 8] =
509 let onebyte: [u32; 8] =
510 [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0];
510 [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0];
511 let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0];
511 let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0];
512 let mut destlen = 0;
512 let mut destlen = 0;
513 for c in src {
513 for c in src {
514 if inset(&onebyte, *c) {
514 if inset(&onebyte, *c) {
515 charcopy(rewrap_option(&mut dest), &mut destlen, *c)
515 charcopy(rewrap_option(&mut dest), &mut destlen, *c)
516 } else if inset(&lower, *c) {
516 } else if inset(&lower, *c) {
517 charcopy(rewrap_option(&mut dest), &mut destlen, *c + 32)
517 charcopy(rewrap_option(&mut dest), &mut destlen, *c + 32)
518 } else {
518 } else {
519 escape3(rewrap_option(&mut dest), &mut destlen, *c)
519 escape3(rewrap_option(&mut dest), &mut destlen, *c)
520 }
520 }
521 }
521 }
522 destlen
522 destlen
523 }
523 }
524
524
525 fn aux_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
525 fn aux_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
526 let twobytes = [0; 8];
526 let twobytes = [0; 8];
527 let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0];
527 let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0];
528 _encode(&twobytes, &onebyte, dest, src, false)
528 _encode(&twobytes, &onebyte, dest, src, false)
529 }
529 }
530
530
531 fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> {
531 fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> {
532 let dirprefixlen = 8;
532 let dirprefixlen = 8;
533 let maxshortdirslen = 68;
533 let maxshortdirslen = 68;
534 let mut destlen = 0;
534 let mut destlen = 0;
535
535
536 let last_slash = src.iter().rposition(|b| *b == b'/');
536 let last_slash = src.iter().rposition(|b| *b == b'/');
537 let last_dot: Option<usize> = {
537 let last_dot: Option<usize> = {
538 let s = last_slash.unwrap_or(0);
538 let s = last_slash.unwrap_or(0);
539 src[s..].iter().rposition(|b| *b == b'.').map(|i| i + s)
539 src[s..].iter().rposition(|b| *b == b'.').map(|i| i + s)
540 };
540 };
541
541
542 let mut dest = vec![0; MAXSTOREPATHLEN];
542 let mut dest = vec![0; MAXSTOREPATHLEN];
543 memcopy(Some(&mut dest), &mut destlen, b"dh/");
543 memcopy(Some(&mut dest), &mut destlen, b"dh/");
544
544
545 {
545 {
546 let mut first = true;
546 let mut first = true;
547 for slice in
547 for slice in
548 src[..last_slash.unwrap_or(src.len())].split(|b| *b == b'/')
548 src[..last_slash.unwrap_or(src.len())].split(|b| *b == b'/')
549 {
549 {
550 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)];
550 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)];
551 if destlen + (slice.len() + if first { 0 } else { 1 })
551 if destlen + (slice.len() + if first { 0 } else { 1 })
552 > maxshortdirslen + 3
552 > maxshortdirslen + 3
553 {
553 {
554 break;
554 break;
555 } else {
555 } else {
556 if !first {
556 if !first {
557 charcopy(Some(&mut dest), &mut destlen, b'/')
557 charcopy(Some(&mut dest), &mut destlen, b'/')
558 };
558 };
559 memcopy(Some(&mut dest), &mut destlen, slice);
559 memcopy(Some(&mut dest), &mut destlen, slice);
560 if dest[destlen - 1] == b'.' || dest[destlen - 1] == b' ' {
560 if dest[destlen - 1] == b'.' || dest[destlen - 1] == b' ' {
561 dest[destlen - 1] = b'_'
561 dest[destlen - 1] = b'_'
562 }
562 }
563 }
563 }
564 first = false;
564 first = false;
565 }
565 }
566 if !first {
566 if !first {
567 charcopy(Some(&mut dest), &mut destlen, b'/');
567 charcopy(Some(&mut dest), &mut destlen, b'/');
568 }
568 }
569 }
569 }
570
570
571 let used = destlen + 40 + {
571 let used = destlen + 40 + {
572 if let Some(l) = last_dot {
572 if let Some(l) = last_dot {
573 src.len() - l
573 src.len() - l
574 } else {
574 } else {
575 0
575 0
576 }
576 }
577 };
577 };
578
578
579 if MAXSTOREPATHLEN > used {
579 if MAXSTOREPATHLEN > used {
580 let slop = MAXSTOREPATHLEN - used;
580 let slop = MAXSTOREPATHLEN - used;
581 let basenamelen = match last_slash {
581 let basenamelen = match last_slash {
582 Some(l) => src.len() - l - 1,
582 Some(l) => src.len() - l - 1,
583 None => src.len(),
583 None => src.len(),
584 };
584 };
585 let basenamelen = std::cmp::min(basenamelen, slop);
585 let basenamelen = std::cmp::min(basenamelen, slop);
586 if basenamelen > 0 {
586 if basenamelen > 0 {
587 let start = match last_slash {
587 let start = match last_slash {
588 Some(l) => l + 1,
588 Some(l) => l + 1,
589 None => 0,
589 None => 0,
590 };
590 };
591 memcopy(
591 memcopy(
592 Some(&mut dest),
592 Some(&mut dest),
593 &mut destlen,
593 &mut destlen,
594 &src[start..][..basenamelen],
594 &src[start..][..basenamelen],
595 )
595 )
596 }
596 }
597 }
597 }
598 for c in sha {
598 for c in sha {
599 hexencode(Some(&mut dest), &mut destlen, *c);
599 hexencode(Some(&mut dest), &mut destlen, *c);
600 }
600 }
601 if let Some(l) = last_dot {
601 if let Some(l) = last_dot {
602 memcopy(Some(&mut dest), &mut destlen, &src[l..]);
602 memcopy(Some(&mut dest), &mut destlen, &src[l..]);
603 }
603 }
604 if destlen == dest.len() {
604 if destlen == dest.len() {
605 dest
605 dest
606 } else {
606 } else {
607 // sometimes the path are shorter than MAXSTOREPATHLEN
607 // sometimes the path are shorter than MAXSTOREPATHLEN
608 dest[..destlen].to_vec()
608 dest[..destlen].to_vec()
609 }
609 }
610 }
610 }
611
611
612 const MAXENCODE: usize = 4096 * 4;
612 const MAXENCODE: usize = 4096 * 4;
613 fn hash_encode(src: &[u8]) -> Vec<u8> {
613 fn hash_encode(src: &[u8]) -> Vec<u8> {
614 let dired = &mut [0; MAXENCODE];
614 let dired = &mut [0; MAXENCODE];
615 let lowered = &mut [0; MAXENCODE];
615 let lowered = &mut [0; MAXENCODE];
616 let auxed = &mut [0; MAXENCODE];
616 let auxed = &mut [0; MAXENCODE];
617 let baselen = (src.len() - 5) * 3;
617 let baselen = (src.len() - 5) * 3;
618 if baselen >= MAXENCODE {
618 if baselen >= MAXENCODE {
619 panic!("path_encode::hash_encore: string too long: {}", baselen)
619 panic!("path_encode::hash_encore: string too long: {}", baselen)
620 };
620 };
621 let dirlen = encode_dir(Some(&mut dired[..]), src);
621 let dirlen = encode_dir(Some(&mut dired[..]), src);
622 let sha = Sha1::digest(&dired[..dirlen]);
622 let sha = Sha1::digest(&dired[..dirlen]);
623 let lowerlen = lower_encode(Some(&mut lowered[..]), &dired[..dirlen][5..]);
623 let lowerlen = lower_encode(Some(&mut lowered[..]), &dired[..dirlen][5..]);
624 let auxlen = aux_encode(Some(&mut auxed[..]), &lowered[..lowerlen]);
624 let auxlen = aux_encode(Some(&mut auxed[..]), &lowered[..lowerlen]);
625 hash_mangle(&auxed[..auxlen], &sha)
625 hash_mangle(&auxed[..auxlen], &sha)
626 }
626 }
627
627
628 pub fn path_encode(path: &[u8]) -> Vec<u8> {
628 pub fn path_encode(path: &[u8]) -> Vec<u8> {
629 let newlen = if path.len() <= MAXSTOREPATHLEN {
629 let newlen = if path.len() <= MAXSTOREPATHLEN {
630 basic_encode(None, path)
630 basic_encode(None, path)
631 } else {
631 } else {
632 MAXSTOREPATHLEN + 1
632 MAXSTOREPATHLEN + 1
633 };
633 };
634 if newlen <= MAXSTOREPATHLEN {
634 if newlen <= MAXSTOREPATHLEN {
635 if newlen == path.len() {
635 if newlen == path.len() {
636 path.to_vec()
636 path.to_vec()
637 } else {
637 } else {
638 let mut res = vec![0; newlen];
638 let mut res = vec![0; newlen];
639 basic_encode(Some(&mut res), path);
639 basic_encode(Some(&mut res), path);
640 res
640 res
641 }
641 }
642 } else {
642 } else {
643 hash_encode(path)
643 hash_encode(path)
644 }
644 }
645 }
645 }
646
647 #[cfg(test)]
648 mod tests {
649 use super::*;
650 use crate::utils::hg_path::HgPathBuf;
651
652 // expected failure
653 #[test]
654 #[should_panic]
655 fn test_long_filename_at_root() {
656 let input = b"data/ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ.i";
657 let expected = b"dh/abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij.i708243a2237a7afae259ea3545a72a2ef11c247b.i";
658 let res = path_encode(input);
659 assert_eq!(
660 HgPathBuf::from_bytes(&res),
661 HgPathBuf::from_bytes(expected)
662 );
663 }
664 }
General Comments 0
You need to be logged in to leave comments. Login now