pathtest.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <sys/stat.h>
  4. #include <dsync/error.h>
  5. #include <iostream>
  6. // SimplifyPath - Short function to remove relative path components /*{{{*/
  7. // ---------------------------------------------------------------------
  8. /* This short function removes relative path components such as ./ and ../
  9. from the path and removes double // as well. It works by seperating
  10. the path into a list of components and then removing any un-needed
  11. compoments */
  12. bool SimplifyPath(char *Buffer)
  13. {
  14. // Create a list of path compoments
  15. char *Pos[100];
  16. unsigned CurPos = 0;
  17. Pos[CurPos] = Buffer;
  18. CurPos++;
  19. for (char *I = Buffer; *I != 0;)
  20. {
  21. if (*I == '/')
  22. {
  23. *I = 0;
  24. I++;
  25. Pos[CurPos] = I;
  26. CurPos++;
  27. }
  28. else
  29. I++;
  30. }
  31. // Strip //, ./ and ../
  32. for (unsigned I = 0; I != CurPos; I++)
  33. {
  34. if (Pos[I] == 0)
  35. continue;
  36. // Double slash
  37. if (Pos[I][0] == 0)
  38. {
  39. if (I != 0)
  40. Pos[I] = 0;
  41. continue;
  42. }
  43. // Dot slash
  44. if (Pos[I][0] == '.' && Pos[I][1] == 0)
  45. {
  46. Pos[I] = 0;
  47. continue;
  48. }
  49. // Dot dot slash
  50. if (Pos[I][0] == '.' && Pos[I][1] == '.' && Pos[I][2] == 0)
  51. {
  52. Pos[I] = 0;
  53. unsigned J = I;
  54. for (; Pos[J] == 0 && J != 0; J--);
  55. if (Pos[J] == 0)
  56. return _error->Error("Invalid path, too many ../s");
  57. Pos[J] = 0;
  58. continue;
  59. }
  60. }
  61. // Recombine the path into full path
  62. for (unsigned I = 0; I != CurPos; I++)
  63. {
  64. if (Pos[I] == 0)
  65. continue;
  66. memmove(Buffer,Pos[I],strlen(Pos[I]));
  67. Buffer += strlen(Pos[I]);
  68. if (I + 1 != CurPos)
  69. *Buffer++ = '/';
  70. }
  71. *Buffer = 0;
  72. return true;
  73. }
  74. /*}}}*/
  75. // ResolveLink - Resolve a file into an unsymlinked path /*{{{*/
  76. // ---------------------------------------------------------------------
  77. /* The returned path is a path that accesses the same file without
  78. traversing a symlink, the memory buffer used should be twice as large
  79. as the largest path. It uses an LRU cache of past lookups to speed things
  80. up, just don't change directores :> */
  81. struct Cache
  82. {
  83. string Dir;
  84. string Trans;
  85. unsigned long Age;
  86. };
  87. static Cache DirCache[400];
  88. static unsigned long CacheAge = 0;
  89. bool ResolveLink(char *Buffer,unsigned long Max)
  90. {
  91. if (Buffer[0] == 0 || (Buffer[0] == '/' && Buffer[1] == 0))
  92. return true;
  93. // Lookup in the cache
  94. Cache *Entry = 0;
  95. for (int I = 0; I != 400; I++)
  96. {
  97. // Store an empty entry
  98. if (DirCache[I].Dir.empty() == true)
  99. {
  100. Entry = &DirCache[I];
  101. Entry->Age = 0;
  102. continue;
  103. }
  104. // Store the LRU entry
  105. if (Entry != 0 && Entry->Age > DirCache[I].Age)
  106. Entry = &DirCache[I];
  107. if (DirCache[I].Dir != Buffer || DirCache[I].Trans.empty() == true)
  108. continue;
  109. strcpy(Buffer,DirCache[I].Trans.c_str());
  110. DirCache[I].Age = CacheAge++;
  111. return true;
  112. }
  113. // Prepare the cache for our new entry
  114. if (Entry != 0 && Buffer[strlen(Buffer) - 1] == '/')
  115. {
  116. Entry->Age = CacheAge++;
  117. Entry->Dir = Buffer;
  118. }
  119. else
  120. Entry = 0;
  121. // Resolve any symlinks
  122. unsigned Counter = 0;
  123. while (1)
  124. {
  125. Counter++;
  126. if (Counter > 50)
  127. return _error->Error("Exceeded allowed symlink depth");
  128. // Strip off the final component name
  129. char *I = Buffer + strlen(Buffer);
  130. for (; I != Buffer && (*I == '/' || *I == 0); I--);
  131. for (; I != Buffer && *I != '/'; I--);
  132. if (I != Buffer)
  133. I++;
  134. // If it is a link then read the link dest over the final component
  135. int Res = readlink(Buffer,I,Max - (I - Buffer));
  136. if (Res > 0)
  137. {
  138. I[Res] = 0;
  139. // Absolute path..
  140. if (*I == '/')
  141. memmove(Buffer,I,strlen(I)+1);
  142. if (SimplifyPath(Buffer) == false)
  143. return false;
  144. }
  145. else
  146. break;
  147. }
  148. /* Here we are abusive and move the current path component to the end
  149. of the buffer to advoid allocating space */
  150. char *I = Buffer + strlen(Buffer);
  151. for (; I != Buffer && (*I == '/' || *I == 0); I--);
  152. for (; I != Buffer && *I != '/'; I--);
  153. if (I != Buffer)
  154. I++;
  155. unsigned Len = strlen(I) + 1;
  156. char *End = Buffer + Max - Len;
  157. memmove(End,I,Len);
  158. *I = 0;
  159. // Recurse to deal with any links in the files path
  160. if (ResolveLink(Buffer,Max - Len) == false)
  161. return false;
  162. I = Buffer + strlen(Buffer);
  163. memmove(I,End,Len);
  164. // Store in the cache
  165. if (Entry != 0)
  166. Entry->Trans = Buffer;
  167. return true;
  168. }
  169. /*}}}*/
  170. int main(int argc,char *argv[])
  171. {
  172. char Buf[1024*4];
  173. // strcpy(Buf,argv[1]);
  174. while (!cin == false)
  175. {
  176. char Buf2[200];
  177. cin.getline(Buf2,sizeof(Buf2));
  178. strcpy(Buf,Buf2);
  179. if (ResolveLink(Buf,sizeof(Buf)) == false)
  180. _error->DumpErrors();
  181. else
  182. {
  183. /* struct stat StA;
  184. struct stat StB;
  185. if (stat(Buf,&StA) != 0 || stat(Buf2,&StB) != 0)
  186. {
  187. cerr << Buf << ',' << Buf2 << endl;
  188. cerr << "Stat failure" << endl;
  189. }
  190. if (StA.st_ino != StB.st_ino)
  191. cerr << "Inode mismatch" << endl;*/
  192. cout << Buf << endl;
  193. }
  194. }
  195. return 0;
  196. }