1 /************************************************************************/
2 /*									*/
3 /*  Maniputaion of file names.						*/
4 /*									*/
5 /*  The routines do not consult the file system to find out whether	*/
6 /*  strings refer to a particular kind of thing on the file system.	*/
7 /*  The current directory is however retrieved to resolve relative	*/
8 /*  names.								*/
9 /*									*/
10 /************************************************************************/
11 
12 #   include	"appUtilConfig.h"
13 
14 #   include	<string.h>
15 
16 #   include	"appSystem.h"
17 
18 #   include	<appDebugon.h>
19 
20 /************************************************************************/
21 /*									*/
22 /*  Return a pointer to the beginning of the extension part in a file	*/
23 /*  name. The pointer points IN the input string.			*/
24 /*									*/
25 /************************************************************************/
26 
appFileGetFileExtension(MemoryBuffer * extension,const MemoryBuffer * filename)27 int appFileGetFileExtension(	MemoryBuffer *		extension,
28 				const MemoryBuffer *	filename )
29     {
30     const char *	all= utilMemoryBufferGetString( filename );
31     const char *	slash;
32     const char *	dot;
33 
34     slash= strrchr( all, '/' );
35     if  ( slash )
36 	{ dot= strrchr( slash+ 1, '.' );	}
37     else{ dot= strrchr( all, '.' );		}
38 
39     if  ( ! dot )
40 	{ utilEmptyMemoryBuffer( extension );	}
41     else{
42 	int	off= dot- all+ 1;
43 	int	len= filename->mbSize- off;
44 
45 	if  ( utilMemoryBufferGetRange( extension, filename, off, len ) )
46 	    { LDEB(1); return -1;	}
47 	}
48 
49     return 0;
50     }
51 
appFileSetExtensionX(MemoryBuffer * filename,const char * extension,int replace)52 static int appFileSetExtensionX(	MemoryBuffer *		filename,
53 					const char *		extension,
54 					int			replace )
55     {
56     const char *	all= utilMemoryBufferGetString( filename );
57     const char *	dot= (const char *)0;
58 
59     int			from;
60     int			extlen= 0;
61 
62     if  ( utilMemoryBufferIsEmpty( filename ) )
63 	{ LDEB(filename->mbSize); return -1;	}
64 
65     if  ( replace )
66 	{
67 	const char *	slash;
68 
69 	slash= strrchr( all, '/' );
70 
71 	if  ( slash )
72 	    { dot= strrchr( slash+ 1, '.' );	}
73 	else{ dot= strrchr( all, '.' );		}
74 	}
75 
76     if  ( ! dot )
77 	{
78 	if  ( extension && extension[0] )
79 	    {
80 	    if  ( utilMemoryBufferAppendBytes( filename, (unsigned char *)".", 1 ) )
81 		{ LDEB(1); return -1;	}
82 
83 	    extlen= strlen( extension );
84 	    }
85 
86 	from= filename->mbSize;
87 	}
88     else{
89 	if  ( extension && extension[0] )
90 	    {
91 	    from= dot- all+ 1;
92 	    extlen= strlen( extension );
93 	    }
94 	else{ from= dot- all;		}
95 	}
96 
97     if  ( utilMemoryBufferReplaceBytes( filename, from, filename->mbSize,
98 				(const unsigned char *)extension, extlen ) )
99 	{ LDEB(1); return -1;	}
100 
101     return 0;
102     }
103 
appFileSetExtension(MemoryBuffer * filename,const char * extension)104 int appFileSetExtension(		MemoryBuffer *		filename,
105 					const char *		extension )
106     {
107     return appFileSetExtensionX( filename, extension, 1 );
108     }
109 
appFileAddExtension(MemoryBuffer * filename,const char * extension)110 int appFileAddExtension(		MemoryBuffer *		filename,
111 					const char *		extension )
112     {
113     return appFileSetExtensionX( filename, extension, 0 );
114     }
115 
appFileGetRelativeName(MemoryBuffer * relative,const MemoryBuffer * filename)116 int appFileGetRelativeName(	MemoryBuffer *		relative,
117 				const MemoryBuffer *	filename )
118     {
119     const char *	all= utilMemoryBufferGetString( filename );
120     const char *	slash;
121 
122     slash= strrchr( all, '/' );
123 
124     if  ( ! slash )
125 	{
126 	if  ( utilCopyMemoryBuffer( relative, filename ) )
127 	    { LDEB(1); return -1;	}
128 	}
129     else{
130 	int	off= slash- all+ 1;
131 	int	len= filename->mbSize- off;
132 
133 	if  ( utilMemoryBufferGetRange( relative, filename, off, len ) )
134 	    { LDEB(1); return -1;	}
135 	}
136 
137     return 0;
138     }
139 
appDirectoryOfFileName(MemoryBuffer * dir,const MemoryBuffer * name)140 int appDirectoryOfFileName(	MemoryBuffer *		dir,
141 				const MemoryBuffer *	name )
142     {
143     const char *	all= utilMemoryBufferGetString( name );
144     const char *	slash= strrchr( all, '/' );
145 
146     if  ( ! slash )
147 	{ utilEmptyMemoryBuffer( dir );	}
148     else{
149 	if  ( utilMemoryBufferGetRange( dir, name, 0, slash- all ) )
150 	    { LDEB(1); return -1;	}
151 	}
152 
153     return 0;
154     }
155 
appFileNameIsAbsolute(const char * filename)156 int appFileNameIsAbsolute( const char *	filename )
157     { return filename[0] == '/';	}
158 
159 /************************************************************************/
160 /*									*/
161 /*  Translate a file name to an absolute name.				*/
162 /*									*/
163 /*  a)  Utility routine: append a path fragment to an already existing	*/
164 /*	piece of path.							*/
165 /*  b)  Make some attempts to remove silly intermediate fragments	*/
166 /*	from the path. This can give unexpected results when there are	*/
167 /*	symbolic links to directories, or the ../ go below the root of	*/
168 /*	the file system. The results of not removing ./ and ../ can be	*/
169 /*	as unexpected, but has the advantage not to attach any meaning	*/
170 /*	to the structure of file names in application code.		*/
171 /*									*/
172 /*  1)  If the name is an absolute one, just copy it to the		*/
173 /*	destination.							*/
174 /*  2)  See whether the file the name has to be relative to has a	*/
175 /*	directory part. If so, determine its length, including the	*/
176 /*	slash that separates it from the relative part.			*/
177 /*  3)  If the file the name has to be relative to is an absolute one,	*/
178 /*	append the relative name to the absolute one.			*/
179 /*  4)  Both names are relative.. Determine the current directory.	*/
180 /*  5)  Append a final slash to the name of the current directory.	*/
181 /*  6)  Build one absolute name of the collected path elements.		*/
182 /*									*/
183 /************************************************************************/
184 
185 /*  a  */
utilFileNameCatenate(MemoryBuffer * path,const MemoryBuffer * relative,int relLen)186 static int utilFileNameCatenate(	MemoryBuffer *		path,
187 					const MemoryBuffer *	relative,
188 					int			relLen )
189     {
190     const char *	r= utilMemoryBufferGetString( relative );
191     const char *	p= utilMemoryBufferGetString( path );
192     int			rOff= 0;
193     int			pLen= path->mbSize;
194 
195     /*  b  */
196     while( rOff < relLen )
197 	{
198 	if  ( ! strncmp( r, "./", 2 ) )
199 	    { r += 2; rOff += 2; continue; }
200 
201 	if  ( ! strncmp( r, "../", 3 ) )
202 	    {
203 	    int			lastSlash= -1;
204 	    int			i;
205 
206 	    for ( i= 0; i < pLen- 1; i++ )
207 		{
208 		if  ( p[i] == '/' )
209 		    { lastSlash= i;	}
210 		}
211 
212 	    if  ( lastSlash < 0 )
213 		{ break; }
214 
215 	    pLen= lastSlash+ 1;
216 	    r += 3; rOff += 3;
217 	    continue;
218 	    }
219 
220 	break;
221 	}
222 
223     if  ( pLen > 0 && p[pLen- 1] != '/' )
224 	{
225 	if  ( utilMemoryBufferReplaceBytes( path, pLen, path->mbSize,
226 						(unsigned char *)"/", 1 ) )
227 	    { LDEB(1); return -1;	}
228 
229 	pLen= path->mbSize;
230 	}
231 
232     if  ( utilMemoryBufferReplaceBytes( path, pLen, path->mbSize,
233 			    relative->mbBytes+ rOff, relLen- rOff ) )
234 	{ LDEB(relLen); return -1;	}
235 
236     return path->mbSize;
237     }
238 
appAbsoluteName(MemoryBuffer * absolute,const MemoryBuffer * relative,int relativeIsFile,const MemoryBuffer * nameRelativeTo)239 extern int appAbsoluteName(	MemoryBuffer *		absolute,
240 				const MemoryBuffer *	relative,
241 				int			relativeIsFile,
242 				const MemoryBuffer *	nameRelativeTo )
243     {
244     int			rval= -1;
245     int			relLen= 0;
246 
247     if  ( ! relative || utilMemoryBufferIsEmpty( relative ) )
248 	{ XDEB(relative); rval= -1; goto ready;	}
249 
250     /*  1  */
251     if  ( relative->mbBytes[0] == '/' )
252 	{
253 	if  ( utilCopyMemoryBuffer( absolute, relative ) )
254 	    { LDEB(1); rval= -1; goto ready;	}
255 
256 	rval= absolute->mbSize; goto ready;
257 	}
258 
259     /*  2  */
260     if  ( nameRelativeTo && ! utilMemoryBufferIsEmpty( nameRelativeTo ) )
261 	{
262 	if  ( relativeIsFile )
263 	    {
264 	    int slash= utilMemoryBufferLastIndexOf( nameRelativeTo, '/' );
265 
266 	    if  ( slash >= 0 )
267 		{ relLen= slash;	}
268 	    }
269 	else{
270 	    relLen= nameRelativeTo->mbSize;
271 	    }
272 
273 	/*  3  */
274 	if  ( relLen > 0 && nameRelativeTo->mbBytes[0] == '/' )
275 	    {
276 	    if  ( utilMemoryBufferSetBytes( absolute,
277 					    nameRelativeTo->mbBytes, relLen ) )
278 		{ LDEB(relLen); rval= -1; goto ready;	}
279 
280 	    if  ( utilFileNameCatenate( absolute,
281 					    relative, relative->mbSize ) < 0 )
282 		{ LDEB(1); rval= -1; goto ready;	}
283 
284 	    rval= absolute->mbSize; goto ready;
285 	    }
286 	}
287 
288     /*  4  */
289     if  ( appCurrentDirectory( absolute ) < 0 )
290 	{ LDEB(1); rval= -1; goto ready;	}
291 
292     /*  6  */
293     if  ( relLen > 0 )
294 	{
295 	if  ( utilFileNameCatenate( absolute, nameRelativeTo, relLen ) < 0 )
296 	    { LDEB(relLen); rval= -1; goto ready;	}
297 	}
298 
299     if  ( utilFileNameCatenate( absolute, relative, relative->mbSize ) < 0 )
300 	{ LDEB(1); rval= -1; goto ready;	}
301 
302     rval= absolute->mbSize;
303 
304   ready:
305 
306     return rval;
307     }
308 
309 # if 0
310 
311 static void xx( const char *	filename,
312 		const char *	fileRelativeTo )
313     {
314     char	absolute[1000+1];
315 
316     if  ( appAbsoluteName( absolute, sizeof( absolute )- 1,
317 					    filename, fileRelativeTo ) < 0 )
318 	{ SSDEB( filename, fileRelativeTo );		}
319     else{ SSSDEB( filename, fileRelativeTo, absolute );	}
320 
321     return;
322     }
323 
324 void xxx()
325     {
326 
327     xx( "in.gif", "out.rtf" );
328     xx( "../in.gif", "out.rtf" );
329     xx( "../../in.gif", "out.rtf" );
330 
331     xx( "in.gif", "../out.rtf" );
332     xx( "in.gif", "../../out.rtf" );
333     xx( "../in.gif", "../../out.rtf" );
334 
335     xx( "/in.gif", "../../out.rtf" );
336     xx( "/tmp/in.gif", "../../out.rtf" );
337 
338     xx( "in.gif", "/out.rtf" );
339     xx( "in.gif", "/etc/out.rtf" );
340     xx( "../in.gif", "/etc/out.rtf" );
341     xx( "../../in.gif", "/etc/out.rtf" );
342 
343     return;
344     }
345 
346 # endif
347 
348