1 // -*- mode: cpp; mode: fold -*-
3 // $Id: path-utils.cc,v 1.2 1999/03/22 02:52:46 jgg Exp $
4 /* ######################################################################
6 Misc utility functions for dsync-flist to make use of.
8 ##################################################################### */
10 #include "dsync-flist.h"
14 #include <dsync/error.h>
16 // SimplifyPath - Short function to remove relative path components /*{{{*/
17 // ---------------------------------------------------------------------
18 /* This short function removes relative path components such as ./ and ../
19 from the path and removes double // as well. It works by seperating
20 the path into a list of components and then removing any un-needed
22 bool SimplifyPath(char *Buffer)
24 // Create a list of path compoments
29 for (char *I = Buffer; *I != 0;)
42 // Strip //, ./ and ../
43 for (unsigned I = 0; I != CurPos; I++)
57 if (Pos[I][0] == '.' && Pos[I][1] == 0)
64 if (Pos[I][0] == '.' && Pos[I][1] == '.' && Pos[I][2] == 0)
68 for (; Pos[J] == 0 && J != 0; J--);
70 return _error->Error("Invalid path, too many ../s");
76 // Recombine the path into full path
77 for (unsigned I = 0; I != CurPos; I++)
81 memmove(Buffer,Pos[I],strlen(Pos[I]));
82 Buffer += strlen(Pos[I]);
92 // ResolveLink - Resolve a file into an unsymlinked path /*{{{*/
93 // ---------------------------------------------------------------------
94 /* The returned path is a path that accesses the same file without
95 traversing a symlink, the memory buffer used should be twice as large
96 as the largest path. It uses an LRU cache of past lookups to speed things
97 up, just don't change directores :> */
104 static Cache DirCache[400];
105 static unsigned long CacheAge = 0;
106 bool ResolveLink(char *Buffer,unsigned long Max)
108 if (Buffer[0] == 0 || (Buffer[0] == '/' && Buffer[1] == 0))
111 // Lookup in the cache
113 for (int I = 0; I != 400; I++)
115 // Store an empty entry
116 if (DirCache[I].Dir.empty() == true)
118 Entry = &DirCache[I];
123 // Store the LRU entry
124 if (Entry != 0 && Entry->Age > DirCache[I].Age)
125 Entry = &DirCache[I];
127 if (DirCache[I].Dir != Buffer || DirCache[I].Trans.empty() == true)
129 strcpy(Buffer,DirCache[I].Trans.c_str());
130 DirCache[I].Age = CacheAge++;
134 // Prepare the cache for our new entry
135 if (Entry != 0 && Buffer[strlen(Buffer) - 1] == '/')
137 Entry->Age = CacheAge++;
143 // Resolve any symlinks
144 unsigned Counter = 0;
149 return _error->Error("Exceeded allowed symlink depth");
151 // Strip off the final component name
152 char *I = Buffer + strlen(Buffer);
153 for (; I != Buffer && (*I == '/' || *I == 0); I--);
154 for (; I != Buffer && *I != '/'; I--);
162 /* We need to remove the final slash in the directory component for
163 readlink to work right */
165 if (I[strlen(I) - 1] == '/')
167 End = I + strlen(I) - 1;
171 int Res = readlink(Buffer,I,Max - (I - Buffer) - 2);
173 // If it is a link then read the link dest over the final component
180 memmove(Buffer,I,strlen(I)+1);
182 // Put the slash back..
189 if (SimplifyPath(Buffer) == false)
194 // Put the slash back..
202 /* Here we are abusive and move the current path component to the end
203 of the buffer to advoid allocating space */
204 char *I = Buffer + strlen(Buffer);
205 for (; I != Buffer && (*I == '/' || *I == 0); I--);
206 for (; I != Buffer && *I != '/'; I--);
209 unsigned Len = strlen(I) + 1;
210 char *End = Buffer + Max - Len;
215 // Recurse to deal with any links in the files path
216 if (ResolveLink(Buffer,Max - Len) == false)
218 I = Buffer + strlen(Buffer);
221 // Store in the cache
223 Entry->Trans = Buffer;