xref: /trunk/main/sal/osl/unx/file_url.cxx (revision 0170220d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sal.hxx"
26 
27 #include "file_url.h"
28 
29 #include "system.h"
30 
31 #include <limits.h>
32 #include <errno.h>
33 #include <strings.h>
34 #include <unistd.h>
35 
36 #include "osl/file.hxx"
37 #include <osl/security.h>
38 #include <osl/diagnose.h>
39 #include <osl/thread.h>
40 #include <osl/process.h>
41 
42 #include <rtl/uri.h>
43 #include <rtl/ustring.hxx>
44 #include <rtl/ustrbuf.h>
45 #include "rtl/textcvt.h"
46 
47 #include "file_error_transl.h"
48 #include "file_path_helper.hxx"
49 
50 #include "uunxapi.hxx"
51 
52 /***************************************************
53 
54  General note
55 
56  This file contains the part that handles File URLs.
57 
58  File URLs as scheme specific notion of URIs
59  (RFC2396) may be handled platform independent, but
60  will not in osl which is considered wrong.
61  Future version of osl should handle File URLs this
62  way. In rtl/uri there is already an URI parser etc.
63  so this code should be consolidated.
64 
65  **************************************************/
66 /************************************************************************
67  * ToDo
68  *
69  * Fix osl_getCanonicalName
70  ***********************************************************************/
71 
72 
73 /***************************************************
74  * namespace directives
75  **************************************************/
76 
77 using namespace osl;
78 
79 /***************************************************
80  * constants
81  **************************************************/
82 
83 const sal_Unicode UNICHAR_SLASH = ((sal_Unicode)'/');
84 const sal_Unicode UNICHAR_COLON = ((sal_Unicode)':');
85 const sal_Unicode UNICHAR_DOT   = ((sal_Unicode)'.');
86 
87 /******************************************************************************
88  * Exported Module Functions
89  *****************************************************************************/
90 
91 /* a slightly modified version of Pchar in rtl/source/uri.c */
92 const sal_Bool uriCharClass[128] =
93 {
94   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */
95   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96   0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./  */
97   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */
98   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */
99   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */
100   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */
101   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0  /* pqrstuvwxyz{|}~  */
102 };
103 
104 
105 /* check for top wrong usage strings */
106 /*
107 static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len )
108 {
109 	rtl_uString *pTmp = NULL;
110 	sal_Bool bRet;
111 
112 	rtl_uString_newFromStr_WithLength( &pTmp, path, len );
113 
114 	rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length );
115 
116 	bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) ||
117 		   ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) ||
118 		   ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) ||
119 		   ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) ||
120 		   ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) );
121 
122 	rtl_uString_release( pTmp );
123 	return bRet;
124 }
125 */
126 
127 /****************************************************************************/
128 /* osl_getCanonicalName */
129 /****************************************************************************/
130 
osl_getCanonicalName(rtl_uString * ustrFileURL,rtl_uString ** pustrValidURL)131 oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL )
132 {
133 	OSL_ENSURE(0, "osl_getCanonicalName not implemented");
134 
135 	rtl_uString_newFromString(pustrValidURL, ustrFileURL);
136 	return osl_File_E_None;
137 }
138 
139 /****************************************************************************/
140 /* osl_getSystemPathFromFileURL */
141 /****************************************************************************/
142 
osl_getSystemPathFromFileURL(rtl_uString * ustrFileURL,rtl_uString ** pustrSystemPath)143 oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
144 {
145 	sal_Int32 nIndex;
146 	rtl_uString * pTmp = NULL;
147 
148 	sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
149 	sal_Unicode protocolDelimiter[3] = { ':', '/', '/' };
150 
151 	/* temporary hack: if already system path, return ustrFileURL */
152 	/*
153 	if( (sal_Unicode) '/' == ustrFileURL->buffer[0] )
154 	{
155 		OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" );
156 		rtl_uString_assign( pustrSystemPath, ustrFileURL );
157 		return osl_File_E_None;
158 	}
159 	*/
160 
161 	/* a valid file url may not start with '/' */
162 	if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) )
163 	{
164 		return osl_File_E_INVAL;
165 	}
166 
167 	/* Check for non file:// protocols */
168 
169 	nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 );
170 	if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) )
171 	{
172 		return osl_File_E_INVAL;
173 	}
174 
175 	/* search for encoded slashes (%2F) and decode every single token if we find one */
176 
177 	nIndex = 0;
178 
179 	if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) )
180 	{
181 		rtl_uString * ustrPathToken = NULL;
182 		sal_Int32 nOffset = 7;
183 
184 		do
185 		{
186 			nOffset += nIndex;
187 
188 			/* break url down in '/' divided tokens tokens */
189 			nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' );
190 
191 			/* copy token to new string */
192 			rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset,
193 				-1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ );
194 
195 			/* decode token */
196 			rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
197 
198 			/* the result should not contain any '/' */
199 			if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) )
200 			{
201 				rtl_uString_release( pTmp );
202 				rtl_uString_release( ustrPathToken );
203 
204 				return osl_File_E_INVAL;
205 			}
206 
207 		} while( -1 != nIndex );
208 
209 		/* release temporary string and restore index variable */
210 		rtl_uString_release( ustrPathToken );
211 		nIndex = 0;
212 	}
213 
214 	/* protocol and server should not be encoded, so decode the whole string */
215 	rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
216 
217 	/* check if file protocol specified */
218 	/* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
219 	if( 7 <= pTmp->length )
220 	{
221 		rtl_uString * pProtocol = NULL;
222 		rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
223 
224 		/* protocol is case insensitive */
225 		rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
226 
227 		if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
228 			nIndex = 7;
229 
230 		rtl_uString_release( pProtocol );
231 	}
232 
233 	/* skip "localhost" or "127.0.0.1" if "file://" is specified */
234 	/* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
235 	if( nIndex && ( 10 <= pTmp->length - nIndex ) )
236 	{
237 		rtl_uString * pServer = NULL;
238 		rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
239 
240 		/* server is case insensitive */
241 		rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
242 
243 		if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
244 			( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) )
245 		{
246 			/* don't exclude the '/' */
247 			nIndex += 9;
248 		}
249 
250 		rtl_uString_release( pServer );
251 	}
252 
253 	if( nIndex )
254 		rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex );
255 
256 	/* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
257 	if( (sal_Unicode) '~' == pTmp->buffer[0] )
258 	{
259 		/* check if another user is specified */
260 		if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) )
261 		{
262 			rtl_uString *pTmp2 = NULL;
263 			oslSecurity pSecTemp;
264 
265 			/* osl_getHomeDir returns file URL */
266 			osl_getHomeDir( pSecTemp = osl_getCurrentSecurity(), &pTmp2 );
267 			osl_freeSecurityHandle( pSecTemp );
268 
269 			/* remove "file://" prefix */
270 			rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 );
271 
272 			/* replace '~' in original string */
273 			rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 );
274 			rtl_uString_release( pTmp2 );
275 		}
276 
277 		else
278 		{
279 			/* FIXME: replace ~user with users home directory */
280 			return osl_File_E_INVAL;
281 		}
282 	}
283 
284 	/* temporary check for top 5 wrong usage strings (which are valid but unlikely filenames) */
285 	/*
286 	OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
287 	*/
288 
289 	*pustrSystemPath = pTmp;
290 	return osl_File_E_None;
291 }
292 
293 /****************************************************************************/
294 /* osl_getFileURLFromSystemPath */
295 /****************************************************************************/
296 
osl_getFileURLFromSystemPath(rtl_uString * ustrSystemPath,rtl_uString ** pustrFileURL)297 oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
298 {
299 	static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
300 
301 	rtl_uString *pTmp = NULL;
302 	sal_Int32 nIndex;
303 
304 	if( 0 == ustrSystemPath->length )
305 		return osl_File_E_INVAL;
306 
307 	/* temporary hack: if already file url, return ustrSystemPath */
308 
309 	if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) )
310 	{
311 	/*
312 		if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) )
313 		{
314 			OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" );
315 			rtl_uString_assign( pustrFileURL, ustrSystemPath );
316 		}
317 		else
318 		{
319 			rtl_uString *pTmp2 = NULL;
320 
321 			OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" );
322 			rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 );
323 			rtl_uString_newFromAscii( &pTmp2, "file://" );
324 			rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 );
325 			rtl_uString_release( pTmp2 );
326 		}
327 		return osl_File_E_None;
328 		*/
329 		return osl_File_E_INVAL;
330 	}
331 
332 
333 	/* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
334 	if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] )
335 	{
336 		/* check if another user is specified */
337 		if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) )
338 		{
339 			/* osl_getHomeDir returns file URL */
340 			osl_getHomeDir( osl_getCurrentSecurity(), &pTmp );
341 
342 			/* remove "file://" prefix */
343 			rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 );
344 
345 			/* replace '~' in original string */
346 			rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp );
347 		}
348 
349 		else
350 		{
351 			/* FIXME: replace ~user with users home directory */
352 			return osl_File_E_INVAL;
353 		}
354 	}
355 
356 	/* check if initial string contains double instances of '/' */
357 	nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
358 	if( -1 != nIndex )
359 	{
360 		sal_Int32 nSrcIndex;
361 		sal_Int32 nDeleted = 0;
362 
363 		/* if pTmp is not already allocated, copy ustrSystemPath for modification */
364 		if( NULL == pTmp )
365 			rtl_uString_newFromString( &pTmp, ustrSystemPath );
366 
367 		/* adapt index to pTmp */
368 		nIndex += pTmp->length - ustrSystemPath->length;
369 
370 		/* remove all occurrences of '//' */
371 		for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
372 		{
373 			if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) )
374 				nDeleted++;
375 			else
376 				pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
377 		}
378 
379 		/* adjust length member */
380 		pTmp->length -= nDeleted;
381 	}
382 
383 	if( NULL == pTmp )
384 		rtl_uString_assign( &pTmp, ustrSystemPath );
385 
386 	/* temporary check for top 5 wrong usage strings (which are valid but unlikely filenames) */
387 	/*
388 	OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
389 	*/
390 
391 	/* file URLs must be URI encoded */
392 	rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
393 
394 	rtl_uString_release( pTmp );
395 
396 	/* absolute urls should start with 'file://' */
397 	if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] )
398 	{
399 		rtl_uString *pProtocol = NULL;
400 
401 		rtl_uString_newFromAscii( &pProtocol, "file://" );
402 		rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
403 		rtl_uString_release( pProtocol );
404 	}
405 
406 	return osl_File_E_None;
407 }
408 
409 /****************************************************************************
410  * osl_getSystemPathFromFileURL_Ex - helper function
411  * clients may specify if they want to accept relative
412  * URLs or not
413  ****************************************************************************/
414 
osl_getSystemPathFromFileURL_Ex(rtl_uString * ustrFileURL,rtl_uString ** pustrSystemPath,sal_Bool bAllowRelative)415 oslFileError osl_getSystemPathFromFileURL_Ex(
416 	rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative)
417 {
418 	rtl_uString* temp = 0;
419 	oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
420 
421 	if (osl_File_E_None == osl_error)
422 	{
423 		if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0]))
424 		{
425 			*pustrSystemPath = temp;
426 		}
427 		else
428 		{
429 			rtl_uString_release(temp);
430 			osl_error = osl_File_E_INVAL;
431 		}
432 	}
433 
434 	return osl_error;
435 }
436 
437 namespace /* private */
438 {
439 
440 	/******************************************************
441 	 * Helper function, return a pinter to the final '\0'
442 	 * of a string
443 	 ******************************************************/
444 
ustrtoend(sal_Unicode * pStr)445 	sal_Unicode* ustrtoend(sal_Unicode* pStr)
446 	{
447 		return (pStr + rtl_ustr_getLength(pStr));
448 	}
449 
450 	/*********************************************
451 
452 	 ********************************************/
453 
ustrchrcat(const sal_Unicode chr,sal_Unicode * d)454 	sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
455 	{
456 		sal_Unicode* p = ustrtoend(d);
457 		*p++ = chr;
458 		*p   = 0;
459 		return d;
460 	}
461 
462 	/******************************************************
463 	 *
464 	 ******************************************************/
465 
_islastchr(sal_Unicode * pStr,sal_Unicode Chr)466 	bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
467 	{
468 		sal_Unicode* p = ustrtoend(pStr);
469 		if (p > pStr)
470 			p--;
471 		return (*p == Chr);
472 	}
473 
474 	/******************************************************
475 	 * Remove the last part of a path, a path that has
476 	 * only a '/' or no '/' at all will be returned
477 	 * unmodified
478 	 ******************************************************/
479 
_rmlastpathtoken(sal_Unicode * aPath)480 	sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath)
481 	{
482 		/* 	we always may skip -2 because we
483 			may at least stand on a '/' but
484 			either there is no other character
485 			before this '/' or it's another
486 			character than the '/'
487 		*/
488 		sal_Unicode* p = ustrtoend(aPath) - 2;
489 
490 		// move back to the next path separator
491 		// or to the start of the string
492 		while ((p > aPath) && (*p != UNICHAR_SLASH))
493 			p--;
494 
495 		if (p >= aPath)
496 		{
497 			if (UNICHAR_SLASH == *p)
498 			{
499 				p++;
500 			   *p = '\0';
501 			}
502 			else
503 			{
504 			   *p = '\0';
505 			}
506 		}
507 
508 		return aPath;
509 	}
510 
511 	/******************************************************
512 	 *
513 	 ******************************************************/
514 
_osl_resolvepath(sal_Unicode * path,sal_Unicode * current_pos,bool * failed)515 	oslFileError _osl_resolvepath(
516 		/*inout*/ sal_Unicode* path,
517 		/*inout*/ sal_Unicode* current_pos,
518 		/*inout*/ bool* failed)
519 	{
520 		oslFileError ferr = osl_File_E_None;
521 
522 		if (!*failed)
523 		{
524 			char unresolved_path[PATH_MAX];
525 			if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path)))
526 				return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
527 
528 			char resolved_path[PATH_MAX];
529 			if (realpath(unresolved_path, resolved_path))
530 			{
531 				if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
532 					return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
533 
534 				current_pos = ustrtoend(path) - 1;
535 			}
536 			else
537 			{
538 				if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
539 					*failed = true;
540 				else
541 					ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
542 			}
543 		}
544 
545 		return ferr;
546 	}
547 
548 	/******************************************************
549 	 * Works even with non existing paths. The resulting
550 	 * path must not exceed PATH_MAX else
551 	 * osl_File_E_NAMETOOLONG is the result
552 	 ******************************************************/
553 
osl_getAbsoluteFileURL_impl_(const rtl::OUString & unresolved_path,rtl::OUString & resolved_path)554 	oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path)
555 	{
556 		// the given unresolved path must not exceed PATH_MAX
557 		if (unresolved_path.getLength() >= (PATH_MAX - 2))
558 			return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
559 
560 		sal_Unicode        path_resolved_so_far[PATH_MAX];
561 		const sal_Unicode* punresolved = unresolved_path.getStr();
562 		sal_Unicode*       presolvedsf = path_resolved_so_far;
563 
564 		// reserve space for leading '/' and trailing '\0'
565 		// do not exceed this limit
566 		sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2;
567 
568 		// if realpath fails with error ENOTDIR, EACCES or ENOENT
569 		// we will not call it again, because _osl_realpath should also
570 		// work with non existing directories etc.
571 		bool realpath_failed = false;
572 		oslFileError ferr;
573 
574 		path_resolved_so_far[0] = '\0';
575 
576 		while (*punresolved != '\0')
577 		{
578 			// ignore '/.' , skip one part back when '/..'
579 
580 			if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf))
581 			{
582 				if ('\0' == *(punresolved + 1))
583 				{
584 					punresolved++;
585 					continue;
586 				}
587 				else if (UNICHAR_SLASH == *(punresolved + 1))
588 				{
589 					punresolved += 2;
590 					continue;
591 				}
592 				else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2))))
593 				{
594 					_rmlastpathtoken(path_resolved_so_far);
595 
596 					presolvedsf = ustrtoend(path_resolved_so_far) - 1;
597 
598 					if (UNICHAR_SLASH == *(punresolved + 2))
599 						punresolved += 3;
600 					else
601 						punresolved += 2;
602 
603 					continue;
604 				}
605 				else // a file or directory name may start with '.'
606 				{
607 					if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
608 						return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
609 
610 					ustrchrcat(*punresolved++, path_resolved_so_far);
611 
612 					if ('\0' == *punresolved && !realpath_failed)
613 					{
614 						ferr = _osl_resolvepath(
615 							path_resolved_so_far,
616 							presolvedsf,
617 							&realpath_failed);
618 
619 						if (osl_File_E_None != ferr)
620 							return ferr;
621 					}
622 				}
623 			}
624 			else if (UNICHAR_SLASH == *punresolved)
625 			{
626 				if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
627 					return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
628 
629 				ustrchrcat(*punresolved++, path_resolved_so_far);
630 
631 				if (!realpath_failed)
632 				{
633 					ferr = _osl_resolvepath(
634 						path_resolved_so_far,
635 						presolvedsf,
636 						&realpath_failed);
637 
638 					if (osl_File_E_None != ferr)
639 						return ferr;
640 
641 					if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH))
642 					{
643 						if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
644 							return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
645 
646 						ustrchrcat(UNICHAR_SLASH, path_resolved_so_far);
647 					}
648 				}
649 			}
650 			else // any other character
651 			{
652 				if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
653 					return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
654 
655 				ustrchrcat(*punresolved++, path_resolved_so_far);
656 
657 				if ('\0' == *punresolved && !realpath_failed)
658 				{
659 					ferr = _osl_resolvepath(
660 						path_resolved_so_far,
661 						presolvedsf,
662 						&realpath_failed);
663 
664 					if (osl_File_E_None != ferr)
665 						return ferr;
666 				}
667 			}
668 		}
669 
670 		sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
671 
672 		OSL_ASSERT(len < PATH_MAX);
673 
674 		resolved_path = rtl::OUString(path_resolved_so_far, len);
675 
676 		return osl_File_E_None;
677 	}
678 
679 } // end namespace private
680 
681 
682 /******************************************************
683  * osl_getAbsoluteFileURL
684  ******************************************************/
685 
osl_getAbsoluteFileURL(rtl_uString * ustrBaseDirURL,rtl_uString * ustrRelativeURL,rtl_uString ** pustrAbsoluteURL)686 oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
687 {
688 	FileBase::RC  rc;
689 	rtl::OUString unresolved_path;
690 
691 	rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path);
692 
693 	if(FileBase::E_None != rc)
694 		return oslFileError(rc);
695 
696 	if (systemPathIsRelativePath(unresolved_path))
697 	{
698 		rtl::OUString base_path;
699 		rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False);
700 
701 		if (FileBase::E_None != rc)
702 			return oslFileError(rc);
703 
704 		rtl::OUString abs_path;
705 		systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
706 
707 		unresolved_path = abs_path;
708 	}
709 
710 	rtl::OUString resolved_path;
711 	rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
712 
713 	if (FileBase::E_None == rc)
714 	{
715 		rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
716 		OSL_ASSERT(FileBase::E_None == rc);
717 	}
718 
719 	return oslFileError(rc);
720 }
721 
722 
723 namespace /* private */
724 {
725 
726 	/*********************************************
727 	 No separate error code if unicode to text
728 	 conversion or getenv fails because for the
729 	 caller there is no difference why a file
730 	 could not be found in $PATH
731 	 ********************************************/
732 
find_in_PATH(const rtl::OUString & file_path,rtl::OUString & result)733 	bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
734 	{
735 		bool          bfound = false;
736 		rtl::OUString path   = rtl::OUString::createFromAscii("PATH");
737 		rtl::OUString env_path;
738 
739 		if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
740 			bfound = osl::searchPath(file_path, env_path, result);
741 
742 		return bfound;
743 	}
744 
745 	/*********************************************
746 	 No separate error code if unicode to text
747 	 conversion or getcwd fails because for the
748 	 caller there is no difference why a file
749 	 could not be found in CDW
750 	 ********************************************/
751 
find_in_CWD(const rtl::OUString & file_path,rtl::OUString & result)752 	bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
753 	{
754 		bool bfound = false;
755 		rtl::OUString cwd_url;
756 
757 		if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
758 		{
759 			rtl::OUString cwd;
760 			FileBase::getSystemPathFromFileURL(cwd_url, cwd);
761 			bfound = osl::searchPath(file_path, cwd, result);
762 		}
763 		return bfound;
764 	}
765 
766 	/*********************************************
767 
768 	 ********************************************/
769 
find_in_searchPath(const rtl::OUString & file_path,rtl_uString * search_path,rtl::OUString & result)770 	bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
771 	{
772 		return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
773 	}
774 
775 } // end namespace private
776 
777 
778 /****************************************************************************
779  * osl_searchFileURL
780  ***************************************************************************/
781 
osl_searchFileURL(rtl_uString * ustrFilePath,rtl_uString * ustrSearchPath,rtl_uString ** pustrURL)782 oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
783 {
784 	OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
785 
786 	FileBase::RC  rc;
787 	rtl::OUString file_path;
788 
789 	// try to interpret search path as file url else assume it's a system path list
790 	rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
791 	if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc))
792 		file_path = ustrFilePath;
793 	else if (FileBase::E_None != rc)
794 		return oslFileError(rc);
795 
796 	bool          bfound = false;
797 	rtl::OUString result;
798 
799 	if (find_in_searchPath(file_path, ustrSearchPath, result) ||
800 		find_in_PATH(file_path, result) ||
801 		find_in_CWD(file_path, result))
802 	{
803 		rtl::OUString resolved;
804 
805 		if (osl::realpath(result, resolved))
806 		{
807 #if OSL_DEBUG_LEVEL > 0
808 			oslFileError osl_error =
809 #endif
810 				osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
811 			OSL_ASSERT(osl_File_E_None == osl_error);
812 			bfound = true;
813 		}
814 	}
815 	return bfound ? osl_File_E_None : osl_File_E_NOENT;
816 }
817 
818 
819 /****************************************************************************
820  * FileURLToPath
821  ***************************************************************************/
822 
FileURLToPath(char * buffer,size_t bufLen,rtl_uString * ustrFileURL)823 oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
824 {
825 	rtl_uString* ustrSystemPath = NULL;
826 	oslFileError osl_error		= osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
827 
828 	if(osl_File_E_None != osl_error)
829 		return osl_error;
830 
831 	osl_systemPathRemoveSeparator(ustrSystemPath);
832 
833 	/* convert unicode path to text */
834 	if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
835 		osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
836 
837 	rtl_uString_release(ustrSystemPath);
838 
839 	return osl_error;
840 }
841 
842 /*****************************************************************************
843  * UnicodeToText
844  ****************************************************************************/
845 
846 namespace /* private */
847 {
848 	class UnicodeToTextConverter_Impl
849 	{
850 		rtl_UnicodeToTextConverter m_converter;
851 
UnicodeToTextConverter_Impl()852 		UnicodeToTextConverter_Impl()
853 			: m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
854 		{}
855 
~UnicodeToTextConverter_Impl()856 		~UnicodeToTextConverter_Impl()
857 		{
858 			rtl_destroyUnicodeToTextConverter (m_converter);
859 		}
860 	public:
getInstance()861 		static UnicodeToTextConverter_Impl & getInstance()
862 		{
863 			static UnicodeToTextConverter_Impl g_theConverter;
864 			return g_theConverter;
865 		}
866 
convert(sal_Unicode const * pSrcBuf,sal_Size nSrcChars,sal_Char * pDstBuf,sal_Size nDstBytes,sal_uInt32 nFlags,sal_uInt32 * pInfo,sal_Size * pSrcCvtChars)867 		sal_Size convert(
868 			sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes,
869 			sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars)
870 		{
871 			OSL_ASSERT(m_converter != 0);
872 			return rtl_convertUnicodeToText (
873 				m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars);
874 		}
875 	};
876 } // end namespace private
877 
UnicodeToText(char * buffer,size_t bufLen,const sal_Unicode * uniText,sal_Int32 uniTextLen)878 int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
879 {
880 	sal_uInt32   nInfo = 0;
881 	sal_Size     nSrcChars = 0;
882 
883 	sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert (
884 		uniText, uniTextLen, buffer, bufLen,
885 		OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars);
886 
887 	if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
888 	{
889 		errno = EOVERFLOW;
890 		return 0;
891 	}
892 
893 	/* ensure trailing '\0' */
894 	buffer[nDestBytes] = '\0';
895 	return nDestBytes;
896 }
897 
898 /*****************************************************************************
899  * TextToUnicode
900  ****************************************************************************/
901 
902 namespace /* private */
903 {
904 	class TextToUnicodeConverter_Impl
905 	{
906 		rtl_TextToUnicodeConverter m_converter;
907 
TextToUnicodeConverter_Impl()908 		TextToUnicodeConverter_Impl()
909 			: m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
910 		{}
911 
~TextToUnicodeConverter_Impl()912 		~TextToUnicodeConverter_Impl()
913 		{
914 			rtl_destroyTextToUnicodeConverter (m_converter);
915 		}
916 
917 	public:
getInstance()918 		static TextToUnicodeConverter_Impl & getInstance()
919 		{
920 			static TextToUnicodeConverter_Impl g_theConverter;
921 			return g_theConverter;
922 		}
923 
convert(sal_Char const * pSrcBuf,sal_Size nSrcBytes,sal_Unicode * pDstBuf,sal_Size nDstChars,sal_uInt32 nFlags,sal_uInt32 * pInfo,sal_Size * pSrcCvtBytes)924 		sal_Size convert(
925 			sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars,
926 			sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes)
927 		{
928 			OSL_ASSERT(m_converter != 0);
929 			return rtl_convertTextToUnicode (
930 				m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes);
931 		}
932 	};
933 } // end namespace private
934 
TextToUnicode(const char * text,size_t text_buffer_size,sal_Unicode * unic_text,sal_Int32 unic_text_buffer_size)935 int TextToUnicode(
936 	const char*  text,
937 	size_t       text_buffer_size,
938 	sal_Unicode* unic_text,
939 	sal_Int32    unic_text_buffer_size)
940 {
941 	sal_uInt32 nInfo = 0;
942 	sal_Size   nSrcChars = 0;
943 
944 	sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert(
945 		text,  text_buffer_size, unic_text, unic_text_buffer_size,
946 		OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars);
947 
948 	if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
949 	{
950 		errno = EOVERFLOW;
951 		return 0;
952 	}
953 
954 	/* ensure trailing '\0' */
955 	unic_text[nDestBytes] = '\0';
956 	return nDestBytes;
957 }
958