| 219 | } |
| 220 | |
| 221 | func rel(basepath, targpath string) (string, error) { |
| 222 | base := path.Clean(basepath) |
| 223 | targ := path.Clean(targpath) |
| 224 | if targ == base { |
| 225 | return ".", nil |
| 226 | } |
| 227 | if base == "." { |
| 228 | base = "" |
| 229 | } |
| 230 | |
| 231 | // Can't use IsAbs - `\a` and `a` are both relative in Windows. |
| 232 | baseSlashed := len(base) > 0 && base[0] == '/' |
| 233 | targSlashed := len(targ) > 0 && targ[0] == '/' |
| 234 | if baseSlashed != targSlashed { |
| 235 | return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) |
| 236 | } |
| 237 | // Position base[b0:bi] and targ[t0:ti] at the first differing elements. |
| 238 | bl := len(base) |
| 239 | tl := len(targ) |
| 240 | var b0, bi, t0, ti int |
| 241 | for { |
| 242 | for bi < bl && base[bi] != '/' { |
| 243 | bi++ |
| 244 | } |
| 245 | for ti < tl && targ[ti] != '/' { |
| 246 | ti++ |
| 247 | } |
| 248 | if targ[t0:ti] != base[b0:bi] { |
| 249 | break |
| 250 | } |
| 251 | if bi < bl { |
| 252 | bi++ |
| 253 | } |
| 254 | if ti < tl { |
| 255 | ti++ |
| 256 | } |
| 257 | b0 = bi |
| 258 | t0 = ti |
| 259 | } |
| 260 | if base[b0:bi] == ".." { |
| 261 | return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) |
| 262 | } |
| 263 | if b0 != bl { |
| 264 | // Base elements left. Must go up before going down. |
| 265 | seps := strings.Count(base[b0:bl], string('/')) |
| 266 | size := 2 + seps*3 |
| 267 | if tl != t0 { |
| 268 | size += 1 + tl - t0 |
| 269 | } |
| 270 | buf := make([]byte, size) |
| 271 | n := copy(buf, "..") |
| 272 | for i := 0; i < seps; i++ { |
| 273 | buf[n] = '/' |
| 274 | copy(buf[n+1:], "..") |
| 275 | n += 3 |
| 276 | } |
| 277 | if t0 != tl { |
| 278 | buf[n] = '/' |