4 #include <dsync/error.h>
7 // SimplifyPath - Short function to remove relative path components /*{{{*/
8 // ---------------------------------------------------------------------
9 /* This short function removes relative path components such as ./ and ../
10 from the path and removes double // as well. It works by seperating
11 the path into a list of components and then removing any un-needed
13 bool SimplifyPath(char *Buffer)
15 // Create a list of path compoments
20 for (char *I = Buffer; *I != 0;)
33 // Strip //, ./ and ../
34 for (unsigned I = 0; I != CurPos; I++)
48 if (Pos[I][0] == '.' && Pos[I][1] == 0)
55 if (Pos[I][0] == '.' && Pos[I][1] == '.' && Pos[I][2] == 0)
59 for (; Pos[J] == 0 && J != 0; J--);
61 return _error->Error("Invalid path, too many ../s");
67 // Recombine the path into full path
68 for (unsigned I = 0; I != CurPos; I++)
72 memmove(Buffer,Pos[I],strlen(Pos[I]));
73 Buffer += strlen(Pos[I]);
83 // ResolveLink - Resolve a file into an unsymlinked path /*{{{*/
84 // ---------------------------------------------------------------------
85 /* The returned path is a path that accesses the same file without
86 traversing a symlink, the memory buffer used should be twice as large
87 as the largest path. It uses an LRU cache of past lookups to speed things
88 up, just don't change directores :> */
95 static Cache DirCache[400];
96 static unsigned long CacheAge = 0;
97 bool ResolveLink(char *Buffer,unsigned long Max)
99 if (Buffer[0] == 0 || (Buffer[0] == '/' && Buffer[1] == 0))
102 // Lookup in the cache
104 for (int I = 0; I != 400; I++)
106 // Store an empty entry
107 if (DirCache[I].Dir.empty() == true)
109 Entry = &DirCache[I];
114 // Store the LRU entry
115 if (Entry != 0 && Entry->Age > DirCache[I].Age)
116 Entry = &DirCache[I];
118 if (DirCache[I].Dir != Buffer || DirCache[I].Trans.empty() == true)
120 strcpy(Buffer,DirCache[I].Trans.c_str());
121 DirCache[I].Age = CacheAge++;
125 // Prepare the cache for our new entry
126 if (Entry != 0 && Buffer[strlen(Buffer) - 1] == '/')
128 Entry->Age = CacheAge++;
134 // Resolve any symlinks
135 unsigned Counter = 0;
140 return _error->Error("Exceeded allowed symlink depth");
142 // Strip off the final component name
143 char *I = Buffer + strlen(Buffer);
144 for (; I != Buffer && (*I == '/' || *I == 0); I--);
145 for (; I != Buffer && *I != '/'; I--);
149 // If it is a link then read the link dest over the final component
150 int Res = readlink(Buffer,I,Max - (I - Buffer));
157 memmove(Buffer,I,strlen(I)+1);
159 if (SimplifyPath(Buffer) == false)
166 /* Here we are abusive and move the current path component to the end
167 of the buffer to advoid allocating space */
168 char *I = Buffer + strlen(Buffer);
169 for (; I != Buffer && (*I == '/' || *I == 0); I--);
170 for (; I != Buffer && *I != '/'; I--);
173 unsigned Len = strlen(I) + 1;
174 char *End = Buffer + Max - Len;
178 // Recurse to deal with any links in the files path
179 if (ResolveLink(Buffer,Max - Len) == false)
181 I = Buffer + strlen(Buffer);
184 // Store in the cache
186 Entry->Trans = Buffer;
192 int main(int argc,char *argv[])
195 // strcpy(Buf,argv[1]);
196 while (!cin == false)
199 cin.getline(Buf2,sizeof(Buf2));
202 if (ResolveLink(Buf,sizeof(Buf)) == false)
203 _error->DumpErrors();
208 if (stat(Buf,&StA) != 0 || stat(Buf2,&StB) != 0)
210 cerr << Buf << ',' << Buf2 << endl;
211 cerr << "Stat failure" << endl;
214 if (StA.st_ino != StB.st_ino)
215 cerr << "Inode mismatch" << endl;*/