cleanname.c 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. #include <u.h>
  2. #include <libc.h>
  3. /*
  4. * In place, rewrite name to compress multiple /, eliminate ., and process ..
  5. */
  6. #define SEP(x) ((x)=='/' || (x) == 0)
  7. char*
  8. cleanname(char *name)
  9. {
  10. char *p, *q, *dotdot;
  11. int rooted;
  12. rooted = name[0] == '/';
  13. /*
  14. * invariants:
  15. * p points at beginning of path element we're considering.
  16. * q points just past the last path element we wrote (no slash).
  17. * dotdot points just past the point where .. cannot backtrack
  18. * any further (no slash).
  19. */
  20. p = q = dotdot = name+rooted;
  21. while(*p) {
  22. if(p[0] == '/') /* null element */
  23. p++;
  24. else if(p[0] == '.' && SEP(p[1]))
  25. p += 1; /* don't count the separator in case it is nul */
  26. else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
  27. p += 2;
  28. if(q > dotdot) { /* can backtrack */
  29. while(--q > dotdot && *q != '/')
  30. ;
  31. } else if(!rooted) { /* /.. is / but ./../ is .. */
  32. if(q != name)
  33. *q++ = '/';
  34. *q++ = '.';
  35. *q++ = '.';
  36. dotdot = q;
  37. }
  38. } else { /* real path element */
  39. if(q != name+rooted)
  40. *q++ = '/';
  41. while((*q = *p) != '/' && *q != 0)
  42. p++, q++;
  43. }
  44. }
  45. if(q == name) /* empty string is really ``.'' */
  46. *q++ = '.';
  47. *q = '\0';
  48. return name;
  49. }