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