hasRelativePathSegment reports whether p contains ".", "..", "./", "../", "/.", "/..", "//", "/./", or "/../".
(p string)
| 529 | |
| 530 | // hasRelativePathSegment reports whether p contains ".", "..", "./", "../", "/.", "/..", "//", "/./", or "/../". |
| 531 | func hasRelativePathSegment(p string) bool { |
| 532 | n := len(p) |
| 533 | if n == 0 { |
| 534 | return false |
| 535 | } |
| 536 | |
| 537 | if p == "." || p == ".." { |
| 538 | return true |
| 539 | } |
| 540 | |
| 541 | // Leading "./" OR "../" |
| 542 | if p[0] == '.' { |
| 543 | if n >= 2 && p[1] == '/' { |
| 544 | return true |
| 545 | } |
| 546 | // Leading "../" |
| 547 | if n >= 3 && p[1] == '.' && p[2] == '/' { |
| 548 | return true |
| 549 | } |
| 550 | } |
| 551 | // Trailing "/." OR "/.." |
| 552 | if p[n-1] == '.' { |
| 553 | if n >= 2 && p[n-2] == '/' { |
| 554 | return true |
| 555 | } |
| 556 | if n >= 3 && p[n-2] == '.' && p[n-3] == '/' { |
| 557 | return true |
| 558 | } |
| 559 | } |
| 560 | |
| 561 | // Now look for any `//` or `/./` or `/../` |
| 562 | |
| 563 | prevSlash := false |
| 564 | segLen := 0 // length of current segment since last slash |
| 565 | dotCount := 0 // consecutive dots at start of the current segment; -1 => not only dots |
| 566 | |
| 567 | for i := range n { |
| 568 | c := p[i] |
| 569 | if c == '/' { |
| 570 | // "//" |
| 571 | if prevSlash { |
| 572 | return true |
| 573 | } |
| 574 | // "/./" or "/../" |
| 575 | if (segLen == 1 && dotCount == 1) || (segLen == 2 && dotCount == 2) { |
| 576 | return true |
| 577 | } |
| 578 | prevSlash = true |
| 579 | segLen = 0 |
| 580 | dotCount = 0 |
| 581 | continue |
| 582 | } |
| 583 | |
| 584 | if c == '.' { |
| 585 | if dotCount >= 0 { |
| 586 | dotCount++ |
| 587 | } |
| 588 | } else { |