cleanname.c 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  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, erasedprefix;
  12. rooted = name[0] == '/';
  13. erasedprefix = 0;
  14. /*
  15. * invariants:
  16. * p points at beginning of path element we're considering.
  17. * q points just past the last path element we wrote (no slash).
  18. * dotdot points just past the point where .. cannot backtrack
  19. * any further (no slash).
  20. */
  21. p = q = dotdot = name+rooted;
  22. while(*p) {
  23. if(p[0] == '/') /* null element */
  24. p++;
  25. else if(p[0] == '.' && SEP(p[1])) {
  26. if(p == name)
  27. erasedprefix = 1;
  28. p += 1; /* don't count the separator in case it is nul */
  29. } else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
  30. p += 2;
  31. if(q > dotdot) { /* can backtrack */
  32. while(--q > dotdot && *q != '/')
  33. ;
  34. } else if(!rooted) { /* /.. is / but ./../ is .. */
  35. if(q != name)
  36. *q++ = '/';
  37. *q++ = '.';
  38. *q++ = '.';
  39. dotdot = q;
  40. }
  41. if(q == name)
  42. erasedprefix = 1; /* erased entire path via dotdot */
  43. } else { /* real path element */
  44. if(q != name+rooted)
  45. *q++ = '/';
  46. while((*q = *p) != '/' && *q != 0)
  47. p++, q++;
  48. }
  49. }
  50. if(q == name) /* empty string is really ``.'' */
  51. *q++ = '.';
  52. *q = '\0';
  53. if(erasedprefix && name[0] == '#'){
  54. /* this was not a #x device path originally - make it not one now */
  55. memmove(name+2, name, strlen(name)+1);
  56. name[0] = '.';
  57. name[1] = '/';
  58. }
  59. return name;
  60. }