| 337 | } |
| 338 | |
| 339 | char *path_simplify(const tal_t *ctx, const char *path) |
| 340 | { |
| 341 | size_t i, j, start, len; |
| 342 | char *ret; |
| 343 | bool ended = false; |
| 344 | |
| 345 | ret = tal_strdup(ctx, path); |
| 346 | if (!ret) |
| 347 | return NULL; |
| 348 | |
| 349 | /* Always need first / if there is one. */ |
| 350 | if (ret[0] == PATH_SEP) |
| 351 | start = 1; |
| 352 | else |
| 353 | start = 0; |
| 354 | |
| 355 | for (i = j = start; !ended; i += len) { |
| 356 | /* Get length of this segment, including terminator. */ |
| 357 | for (len = 0; ret[i+len] != PATH_SEP; len++) { |
| 358 | if (!ret[i+len]) { |
| 359 | ended = true; |
| 360 | break; |
| 361 | } |
| 362 | } |
| 363 | len++; |
| 364 | |
| 365 | /* Empty segment is //; ignore first one. */ |
| 366 | if (len == 1) |
| 367 | continue; |
| 368 | |
| 369 | /* Always ignore slashdot. */ |
| 370 | if (len == 2 && ret[i] == '.') |
| 371 | continue; |
| 372 | |
| 373 | /* .. => remove previous if there is one, unless symlink. */ |
| 374 | if (len == 3 && ret[i] == '.' && ret[i+1] == '.') { |
| 375 | struct stat st; |
| 376 | |
| 377 | if (j > start) { |
| 378 | /* eg. /foo/, foo/ or foo/bar/ */ |
| 379 | assert(ret[j-1] == PATH_SEP); |
| 380 | ret[j-1] = '\0'; |
| 381 | |
| 382 | /* Avoid stepping back over ..! */ |
| 383 | if (streq(ret, "..") |
| 384 | || strends(ret, PATH_SEP_STR"..")) { |
| 385 | ret[j-1] = PATH_SEP; |
| 386 | goto copy; |
| 387 | } |
| 388 | |
| 389 | if (lstat(ret, &st) == 0 |
| 390 | && !S_ISLNK(st.st_mode)) { |
| 391 | char *sep = strrchr(ret, PATH_SEP); |
| 392 | if (sep) |
| 393 | j = sep - ret + 1; |
| 394 | else |
| 395 | j = 0; |
| 396 | } |