xref: /AOO41X/main/sal/osl/os2/file_url.cxx (revision 82ad63bb6dc89acbfb1fbbff425b72ac9d3d2c31)
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 #include <ctype.h>
25 #include "system.h"
26 
27 #ifndef _LIMITS_H
28 #include <limits.h>
29 #endif
30 
31 #ifndef _ERRNO_H
32 #include <errno.h>
33 #endif
34 
35 #ifndef _STDLIB_H_
36 #include <stdlib.h>
37 #endif
38 
39 #ifndef _STRINGS_H
40 #include <strings.h>
41 #endif
42 
43 #ifndef _UNISTD_H
44 #include <unistd.h>
45 #endif
46 #include <osl/file.h>
47 #include <osl/security.h>
48 #include <rtl/uri.h>
49 #include <osl/diagnose.h>
50 #include <rtl/ustring.hxx>
51 #include <rtl/ustrbuf.h>
52 
53 #ifndef _OSL_TREAD_H_
54 #include <osl/thread.h>
55 #endif
56 #include <osl/file.hxx>
57 #include <osl/mutex.h>
58 #include <osl/process.h>
59 #include "file_error_transl.h"
60 
61 #ifndef _FILE_URL_H_
62 #include "file_url.h"
63 #endif
64 #include "file_path_helper.hxx"
65 
66 #ifndef _OSL_UUNXAPI_HXX_
67 #include "uunxapi.hxx"
68 #endif
69 
70 #include <wchar.h>
71 #include <wctype.h>
72 
73 /***************************************************
74 
75  General note
76 
77  This file contains the part that handles File URLs.
78 
79  File URLs as scheme specific notion of URIs
80  (RFC2396) may be handled platform independend, but
81  will not in osl which is considered wrong.
82  Future version of osl should handle File URLs this
83  way. In rtl/uri there is already an URI parser etc.
84  so this code should be consolidated.
85 
86  **************************************************/
87 
88 oslMutex g_CurrentDirectoryMutex;
89 
90 
91 /***************************************************
92  * forward
93  **************************************************/
94 
95 void _osl_warnFile(const char*, rtl_uString*);
96 rtl_uString*  oslMakeUStrFromPsz(const sal_Char* pszStr,rtl_uString** uStr);
97 
98 extern "C" int UnicodeToText(char *, size_t, const sal_Unicode *, sal_Int32);
99 extern "C" int TextToUnicode(const char* text, size_t text_buffer_size, sal_Unicode* unic_text, sal_Int32 unic_text_buffer_size);
100 
101 #define CHAR_POINTER(THE_OUSTRING) ::rtl::OUStringToOString (THE_OUSTRING, RTL_TEXTENCODING_UTF8).pData->buffer
102 
103 /***************************************************
104  * namespace directives
105  **************************************************/
106 
107 using namespace osl;
108 
109 /******************************************************************************
110  *
111  *                  Exported Module Functions
112  *
113  *****************************************************************************/
114 
115 /* a slightly modified version of Pchar in rtl/source/uri.c */
116 const sal_Bool uriCharClass[128] =
117 {
118   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */
119   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120   0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./  */
121   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */
122   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */
123   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */
124   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */
125   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0  /* pqrstuvwxyz{|}~  */
126 };
127 
128 
129 /* check for top wrong usage strings */
130 /*
131 static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len )
132 {
133     rtl_uString *pTmp = NULL;
134     sal_Bool bRet;
135 
136     rtl_uString_newFromStr_WithLength( &pTmp, path, len );
137 
138     rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length );
139 
140     bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) ||
141            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) ||
142            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) ||
143            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) ||
144            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) );
145 
146     rtl_uString_release( pTmp );
147     return bRet;
148 }
149 */
150 
151 
152 /****************************************************************************/
153 /*  osl_getFileURLFromSystemPath */
154 /****************************************************************************/
155 
IsValidFilePathComponent(LPCTSTR lpComponent,LPCTSTR * lppComponentEnd,DWORD dwFlags)156 BOOL WINAPI IsValidFilePathComponent(
157     LPCTSTR lpComponent, LPCTSTR *lppComponentEnd, DWORD dwFlags)
158 {
159     LPCTSTR lpComponentEnd = NULL;
160     LPCTSTR lpCurrent = lpComponent;
161     BOOL    fValid = TRUE;  /* Assume success */
162     TCHAR   cLast = 0;
163 
164     /* Path component length must not exceed MAX_PATH */
165 
166     while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < _MAX_PATH )
167     {
168         switch ( *lpCurrent )
169         {
170             /* Both backslash and slash determine the end of a path component */
171         case '\0':
172         case '/':
173         case '\\':
174             switch ( cLast )
175             {
176                 /* Component must not end with '.' or blank and can't be empty */
177 
178             case '.':
179                 if ( dwFlags & VALIDATEPATH_ALLOW_ELLIPSE )
180                 {
181                     if ( 1 == lpCurrent - lpComponent )
182                     {
183                         /* Current directory is O.K. */
184                         lpComponentEnd = lpCurrent;
185                         break;
186                     }
187                     else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent )
188                     {
189                         /* Parent directory is O.K. */
190                         lpComponentEnd = lpCurrent;
191                         break;
192                     }
193                 }
194             case 0:
195             case ' ':
196                 lpComponentEnd = lpCurrent - 1;
197                 fValid = FALSE;
198                 break;
199             default:
200                 lpComponentEnd = lpCurrent;
201                 break;
202             }
203             break;
204             /* '?' and '*' are valid wildcards but not valid file name characters */
205         case '?':
206         case '*':
207             if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS )
208                 break;
209             /* The following characters are reserved */
210         case '<':
211         case '>':
212         case '\"':
213         case '|':
214         case ':':
215             lpComponentEnd = lpCurrent;
216             fValid = FALSE;
217             break;
218         default:
219             /* Characters below ASCII 32 are not allowed */
220             if ( *lpCurrent < ' ' )
221             {
222                 lpComponentEnd = lpCurrent;
223                 fValid = FALSE;
224             }
225             break;
226         }
227         cLast = *lpCurrent++;
228     }
229 
230     /*  If we don't reached the end of the component the length of the component was to long
231         ( See condition of while loop ) */
232     if ( !lpComponentEnd )
233     {
234         fValid = FALSE;
235         lpComponentEnd = lpCurrent;
236     }
237 
238     /* Test wether the component specifies a device name what is not allowed */
239 
240     // MT: PERFORMANCE:
241     // This is very expensive. A lot of calls to _tcsicmp.
242     // in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp!
243     // Possible optimizations
244     // - Array should be const static
245     // - Sorted array, use binary search
246     // - More intelligent check for com1-9, lpt1-9
247     // Maybe make szComponent upper case, don't search case intensitive
248     // Talked to HRO: Could be removed. Shouldn't be used in OOo, and if used for something like a filename, it will lead to an error anyway.
249     /*
250     if ( fValid )
251     {
252         LPCTSTR alpDeviceNames[] =
253         {
254             TEXT("CON"),
255             TEXT("PRN"),
256             TEXT("AUX"),
257             TEXT("CLOCK$"),
258             TEXT("NUL"),
259             TEXT("LPT1"),
260             TEXT("LPT2"),
261             TEXT("LPT3"),
262             TEXT("LPT4"),
263             TEXT("LPT5"),
264             TEXT("LPT6"),
265             TEXT("LPT7"),
266             TEXT("LPT8"),
267             TEXT("LPT9"),
268             TEXT("COM1"),
269             TEXT("COM2"),
270             TEXT("COM3"),
271             TEXT("COM4"),
272             TEXT("COM5"),
273             TEXT("COM6"),
274             TEXT("COM7"),
275             TEXT("COM8"),
276             TEXT("COM9")
277         };
278 
279         TCHAR   szComponent[MAX_PATH];
280         int     nComponentLength;
281         LPCTSTR lpDot;
282         int     i;
283 
284         // A device name with an extension is also invalid
285         lpDot = _tcschr( lpComponent, '.' );
286 
287         if ( !lpDot || lpDot > lpComponentEnd )
288             nComponentLength = lpComponentEnd - lpComponent;
289         else
290             nComponentLength = lpDot - lpComponent;
291 
292         _tcsncpy( szComponent, lpComponent, nComponentLength );
293         szComponent[nComponentLength] = 0;
294 
295         for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ )
296         {
297             if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) )
298             {
299                 lpComponentEnd = lpComponent;
300                 fValid = FALSE;
301                 break;
302             }
303         }
304     }
305     */
306 
307     if ( fValid )
308     {
309         // Empty components are not allowed
310         if ( lpComponentEnd - lpComponent < 1 )
311             fValid = FALSE;
312 
313         // If we reached the end of the string NULL is returned
314         else if ( !*lpComponentEnd )
315             lpComponentEnd = NULL;
316 
317     }
318 
319     if ( lppComponentEnd )
320         *lppComponentEnd = lpComponentEnd;
321 
322     return fValid;
323 }
324 
325 //#####################################################
IsValidFilePath(LPCTSTR lpszPath,LPCTSTR * lppError,DWORD dwFlags)326 DWORD WINAPI IsValidFilePath(LPCTSTR lpszPath, LPCTSTR *lppError, DWORD dwFlags)
327 {
328     LPCTSTR lpComponent;
329     BOOL    fValid = TRUE;
330     DWORD   dwPathType = PATHTYPE_ERROR;
331 
332     if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
333         dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE;
334 
335     if ( !lpszPath )
336     {
337         fValid = FALSE;
338         lpComponent = lpszPath;
339     }
340 
341     /* Test for UNC path notation */
342     if ( 2 == _tcsspn( lpszPath, CHARSET_SEPARATOR ) )
343     {
344         /* Place the pointer behind the leading to backslashes */
345 
346         lpComponent = lpszPath + 2;
347 
348         fValid = IsValidFilePathComponent( lpComponent, &lpComponent, VALIDATEPATH_ALLOW_ELLIPSE );
349 
350         /* So far we have a valid servername. Now let's see if we also have a network resource */
351 
352         dwPathType = PATHTYPE_ABSOLUTE_UNC;
353 
354         if ( fValid )
355         {
356             if ( lpComponent &&  !*++lpComponent )
357                 lpComponent = NULL;
358 
359             if ( !lpComponent )
360             {
361 #if 0
362                 /* We only have a Server specification what is invalid */
363 
364                 lpComponent = lpszPath;
365                 fValid = FALSE;
366 #else
367                 dwPathType |= PATHTYPE_IS_SERVER;
368 #endif
369             }
370             else
371             {
372                 /* Now test the network resource */
373 
374                 fValid = IsValidFilePathComponent( lpComponent, &lpComponent, 0 );
375 
376                 /* If we now reached the end of the path, everything is O.K. */
377 
378 
379                 if ( fValid && (!lpComponent || lpComponent && !*++lpComponent ) )
380                 {
381                     lpComponent = NULL;
382                     dwPathType |= PATHTYPE_IS_VOLUME;
383                 }
384             }
385         }
386     }
387 
388     /* Local path verification. Must start with <drive>: */
389     else if ( _istalpha( lpszPath[0] ) && ':' == lpszPath[1] )
390     {
391         /* Place pointer behind correct drive specification */
392 
393         lpComponent = lpszPath + 2;
394 
395         if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
396             lpComponent++;
397         else if ( *lpComponent )
398             fValid = FALSE;
399 
400         dwPathType = PATHTYPE_ABSOLUTE_LOCAL;
401 
402         /* Now we are behind the backslash or it was a simple drive without backslash */
403 
404         if ( fValid && !*lpComponent )
405         {
406             lpComponent = NULL;
407             dwPathType |= PATHTYPE_IS_VOLUME;
408         }
409     }
410 
411     /* Can be a relative path */
412     else if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
413     {
414         lpComponent = lpszPath;
415 
416         /* Relative path can start with a backslash */
417 
418         if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
419         {
420             lpComponent++;
421             if ( !*lpComponent )
422                 lpComponent = NULL;
423         }
424 
425         dwPathType = PATHTYPE_RELATIVE;
426     }
427 
428     /* Anything else is an error */
429     else
430     {
431         fValid = FALSE;
432         lpComponent = lpszPath;
433     }
434 
435     /* Now validate each component of the path */
436     while ( fValid && lpComponent )
437     {
438         fValid = IsValidFilePathComponent( lpComponent, &lpComponent, dwFlags );
439 
440         if ( fValid && lpComponent )
441         {
442             lpComponent++;
443 
444             /* If the string behind the backslash is empty, we've done */
445 
446             if ( !*lpComponent )
447                 lpComponent = NULL;
448         }
449     }
450 
451     if ( fValid && _tcslen( lpszPath ) >= _MAX_PATH )
452     {
453         fValid = FALSE;
454         lpComponent = lpszPath + _MAX_PATH;
455     }
456 
457     if ( lppError )
458         *lppError = lpComponent;
459 
460     return fValid ? dwPathType : PATHTYPE_ERROR;
461 }
462 
_osl_decodeURL(rtl_String * strUTF8,rtl_uString ** pstrDecodedURL)463 sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL )
464 {
465     sal_Char        *pBuffer;
466     const sal_Char  *pSrcEnd;
467     const sal_Char  *pSrc;
468     sal_Char        *pDest;
469     sal_Int32       nSrcLen;
470     sal_Bool        bValidEncoded = sal_True;   /* Assume success */
471 
472     /* The resulting decoded string length is shorter or equal to the source length */
473 
474     nSrcLen = rtl_string_getLength(strUTF8);
475     pBuffer = reinterpret_cast<sal_Char*>(rtl_allocateMemory(nSrcLen + 1));
476 
477     pDest = pBuffer;
478     pSrc = rtl_string_getStr(strUTF8);
479     pSrcEnd = pSrc + nSrcLen;
480 
481     /* Now decode the URL what should result in an UTF8 string */
482     while ( bValidEncoded && pSrc < pSrcEnd )
483     {
484         switch ( *pSrc )
485         {
486         case '%':
487             {
488                 sal_Char    aToken[3];
489                 sal_Char    aChar;
490 
491                 pSrc++;
492                 aToken[0] = *pSrc++;
493                 aToken[1] = *pSrc++;
494                 aToken[2] = 0;
495 
496                 aChar = (sal_Char)strtoul( aToken, NULL, 16 );
497 
498                 /* The chars are path delimiters and must not be encoded */
499 
500                 if ( 0 == aChar || '\\' == aChar || '/' == aChar || ':' == aChar )
501                     bValidEncoded = sal_False;
502                 else
503                     *pDest++ = aChar;
504             }
505             break;
506         default:
507             *pDest++ = *pSrc++;
508             break;
509         }
510     }
511 
512     *pDest++ = 0;
513 
514     if ( bValidEncoded ) {
515         rtl_string2UString( pstrDecodedURL, pBuffer, rtl_str_getLength(pBuffer), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
516         OSL_ASSERT(*pstrDecodedURL != 0);
517     }
518 
519     rtl_freeMemory( pBuffer );
520 
521     return bValidEncoded;
522 }
523 
524 //#############################################
_osl_encodeURL(rtl_uString * strURL,rtl_String ** pstrEncodedURL)525 void _osl_encodeURL( rtl_uString *strURL, rtl_String **pstrEncodedURL )
526 {
527     /* Encode non ascii characters within the URL */
528 
529     rtl_String      *strUTF8 = NULL;
530     sal_Char        *pszEncodedURL;
531     const sal_Char  *pURLScan;
532     sal_Char        *pURLDest;
533     sal_Int32       nURLScanLen;
534     sal_Int32       nURLScanCount;
535 
536     rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
537 
538     pszEncodedURL = (sal_Char*) rtl_allocateMemory( (rtl_string_getLength( strUTF8 ) * 3 + 1)  * sizeof(sal_Char) );
539 
540     pURLDest = pszEncodedURL;
541     pURLScan = rtl_string_getStr( strUTF8 );
542     nURLScanLen = rtl_string_getLength( strUTF8 );
543     nURLScanCount = 0;
544 
545     while ( nURLScanCount < nURLScanLen )
546     {
547         sal_Char    cCurrent = *pURLScan;
548 
549         switch ( cCurrent )
550         {
551         default:
552             if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) )
553             {
554                 sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent );
555                 pURLDest += 3;
556                 break;
557             }
558         case '!':
559         case '\'':
560         case '(':
561         case ')':
562         case '*':
563         case '-':
564         case '.':
565         case '_':
566         case '~':
567         case '$':
568         case '&':
569         case '+':
570         case ',':
571         case '=':
572         case '@':
573         case ':':
574         case '/':
575         case '\\':
576         case '|':
577             *pURLDest++ = cCurrent;
578             break;
579         case 0:
580             break;
581         }
582 
583         pURLScan++;
584         nURLScanCount++;
585     }
586 
587 
588     *pURLDest = 0;
589 
590     rtl_string_release( strUTF8 );
591     rtl_string_newFromStr( pstrEncodedURL, pszEncodedURL );
592     rtl_freeMemory( pszEncodedURL );
593 }
594 
595 //#############################################
_osl_getFileURLFromSystemPath(rtl_uString * strPath,rtl_uString ** pstrURL)596 oslFileError SAL_CALL _osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** pstrURL )
597 {
598     oslFileError nError = osl_File_E_INVAL; /* Assume failure */
599     rtl_uString *strTempURL = NULL;
600     DWORD dwPathType = PATHTYPE_ERROR;
601 
602     if (strPath)
603         dwPathType = IsValidFilePath(strPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE);
604 
605     if (dwPathType)
606     {
607         rtl_uString *strTempPath = NULL;
608 
609         /* Replace backslashes */
610 
611         rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' );
612 
613         switch ( dwPathType & PATHTYPE_MASK_TYPE )
614         {
615         case PATHTYPE_RELATIVE:
616             rtl_uString_assign( &strTempURL, strTempPath );
617             nError = osl_File_E_None;
618             break;
619         case PATHTYPE_ABSOLUTE_UNC:
620             rtl_uString_newFromAscii( &strTempURL, "file:" );
621             rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
622             nError = osl_File_E_None;
623             break;
624         case PATHTYPE_ABSOLUTE_LOCAL:
625             rtl_uString_newFromAscii( &strTempURL, "file:///" );
626             rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
627             nError = osl_File_E_None;
628             break;
629         default:
630             break;
631         }
632 
633         /* Release temp path */
634 
635         rtl_uString_release( strTempPath );
636     }
637 
638     if ( osl_File_E_None == nError )
639     {
640         rtl_String  *strEncodedURL = NULL;
641 
642         /* Encode the URL */
643 
644         _osl_encodeURL( strTempURL, &strEncodedURL );
645 
646         /* Provide URL via unicode string */
647 
648         rtl_string2UString( pstrURL, rtl_string_getStr(strEncodedURL), rtl_string_getLength(strEncodedURL), RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS );
649         OSL_ASSERT(*pstrURL != 0);
650         rtl_string_release( strEncodedURL );
651     }
652 
653     /* Release temp URL */
654 
655     if ( strTempURL )
656         rtl_uString_release( strTempURL );
657 
658     /*
659     OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath );
660     */
661 
662     return nError;
663 }
664 
osl_getFileURLFromSystemPath(rtl_uString * ustrSystemPath,rtl_uString ** pustrFileURL)665 oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
666 {
667     return _osl_getFileURLFromSystemPath( ustrSystemPath, pustrFileURL );
668 #if 0
669     static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
670 
671     rtl_uString *pTmp = NULL;
672     sal_Int32 nIndex;
673 
674     if( 0 == ustrSystemPath->length )
675         return osl_File_E_INVAL;
676 
677     /* YD convert '\' to '/' */
678     rtl_ustr_replaceChar( ustrSystemPath->buffer, '\\', '/' );
679 
680     /* temporary hack: if already file url, return ustrSystemPath */
681     if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) )
682     {
683     /*
684         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) )
685         {
686             OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" );
687             rtl_uString_assign( pustrFileURL, ustrSystemPath );
688         }
689         else
690         {
691             rtl_uString *pTmp2 = NULL;
692 
693             OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" );
694             rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 );
695             rtl_uString_newFromAscii( &pTmp2, "file://" );
696             rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 );
697             rtl_uString_release( pTmp2 );
698         }
699         return osl_File_E_None;
700         */
701         return osl_File_E_INVAL;
702     }
703 
704 
705     /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
706     if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] )
707     {
708         /* check if another user is specified */
709         if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) )
710         {
711             /* osl_getHomeDir returns file URL */
712             osl_getHomeDir( osl_getCurrentSecurity(), &pTmp );
713 
714             /* remove "file://" prefix */
715             rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 );
716 
717             /* replace '~' in original string */
718             rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp );
719         }
720 
721         else
722         {
723             /* FIXME: replace ~user with users home directory */
724             return osl_File_E_INVAL;
725         }
726     }
727 
728     /* check if initial string contains double instances of '/' */
729     nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
730     if( -1 != nIndex )
731     {
732         sal_Int32 nSrcIndex;
733         sal_Int32 nDeleted = 0;
734 
735         /* if pTmp is not already allocated, copy ustrSystemPath for modification */
736         if( NULL == pTmp )
737             rtl_uString_newFromString( &pTmp, ustrSystemPath );
738 
739         /* adapt index to pTmp */
740         nIndex += pTmp->length - ustrSystemPath->length;
741 
742         /* remove all occurances of '//' */
743         for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
744         {
745             if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) )
746                 nDeleted++;
747             else
748                 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
749         }
750 
751         /* adjust length member */
752         pTmp->length -= nDeleted;
753     }
754 
755     if( NULL == pTmp )
756         rtl_uString_assign( &pTmp, ustrSystemPath );
757 
758     /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
759     /*
760     OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
761     */
762 
763     /* file URLs must be URI encoded */
764     rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
765 
766     rtl_uString_release( pTmp );
767 
768     /* absolute urls should start with 'file://' */
769     if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] )
770     {
771         rtl_uString *pProtocol = NULL;
772 
773         rtl_uString_newFromAscii( &pProtocol, "file://" );
774         rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
775         rtl_uString_release( pProtocol );
776     }
777 
778     return osl_File_E_None;
779 #endif
780 }
781 
782 //#############################################
_osl_getSystemPathFromFileURL(rtl_uString * strURL,rtl_uString ** pustrPath,sal_Bool bAllowRelative)783 oslFileError SAL_CALL _osl_getSystemPathFromFileURL( rtl_uString *strURL, rtl_uString **pustrPath, sal_Bool bAllowRelative )
784 {
785     rtl_String          *strUTF8 = NULL;
786     rtl_uString         *strDecodedURL = NULL;
787     rtl_uString         *strTempPath = NULL;
788     const sal_Unicode   *pDecodedURL;
789     sal_uInt32          nDecodedLen;
790     sal_Bool            bValidEncoded;
791     oslFileError        nError = osl_File_E_INVAL;  /* Assume failure */
792 
793     /*  If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from
794         having a mixed encoded URL later */
795 
796     rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
797 
798     /* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */
799 
800     OSL_ENSURE_FILE(
801         strUTF8->length == strURL->length ||
802         0 != rtl_ustr_ascii_shortenedCompare_WithLength( strURL->buffer, strURL->length, "file:\\\\", 7 )
803         ,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL );
804 
805     bValidEncoded = _osl_decodeURL( strUTF8, &strDecodedURL );
806 
807     /* Release the encoded UTF8 string */
808 
809     rtl_string_release( strUTF8 );
810 
811 
812     if ( bValidEncoded )
813     {
814         /* Replace backslashes and pipes */
815 
816         rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '/', '\\' );
817         rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '|', ':' );
818 
819         pDecodedURL = rtl_uString_getStr( strDecodedURL );
820         nDecodedLen = rtl_uString_getLength( strDecodedURL );
821 
822         /* Must start with "file://" */
823 
824         if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\", 7 ) )
825         {
826             sal_uInt32  nSkip;
827 
828             if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) )
829                 nSkip = 8;
830             else if (
831                 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\localhost\\", 17 ) ||
832                 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\127.0.0.1\\", 17 )
833             )
834                 nSkip = 17;
835             else
836                 nSkip = 7;
837 
838             /* Indicates local root */
839             if ( nDecodedLen == nSkip )
840                 rtl_uString_newFromStr_WithLength( &strTempPath, (const sal_Unicode*)WSTR_SYSTEM_ROOT_PATH, ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 );
841             else
842                 rtl_uString_newFromStr_WithLength( &strTempPath, pDecodedURL + nSkip, nDecodedLen - nSkip );
843 
844             if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_ELLIPSE ) )
845                 nError = osl_File_E_None;
846         }
847         else if ( bAllowRelative )  /* This maybe a relative file URL */
848         {
849             rtl_uString_assign( &strTempPath, strDecodedURL );
850 
851             if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE ) )
852                 nError = osl_File_E_None;
853         }
854     /*
855         else
856             OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL );
857      */
858 
859     }
860 
861     if ( strDecodedURL )
862         rtl_uString_release( strDecodedURL );
863 
864     if ( osl_File_E_None == nError )
865         rtl_uString_assign( pustrPath, strTempPath );
866 
867     if ( strTempPath )
868         rtl_uString_release( strTempPath );
869 
870     /*
871     OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL );
872     */
873 
874     return nError;
875 }
876 
877 /****************************************************************************/
878 /*  osl_getSystemPathFromFileURL */
879 /****************************************************************************/
880 
osl_getSystemPathFromFileURL(rtl_uString * ustrFileURL,rtl_uString ** pustrSystemPath)881 oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
882 {
883     return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, sal_True );
884 #if 0
885     sal_Int32 nIndex = 0;
886     rtl_uString * pTmp = NULL;
887 
888     sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
889 
890     /* temporary hack: if already system path, return ustrFileURL */
891     /*
892     if( (sal_Unicode) '/' == ustrFileURL->buffer[0] )
893     {
894         OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" );
895         rtl_uString_assign( pustrSystemPath, ustrFileURL );
896         return osl_File_E_None;
897     }
898     */
899 
900     /* a valid file url may not start with '/' */
901     if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) )
902     {
903         return osl_File_E_INVAL;
904     }
905 
906     /* search for encoded slashes (%2F) and decode every single token if we find one */
907     if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) )
908     {
909         rtl_uString * ustrPathToken = NULL;
910         sal_Int32 nOffset = 7;
911 
912         do
913         {
914             nOffset += nIndex;
915 
916             /* break url down in '/' devided tokens tokens */
917             nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' );
918 
919             /* copy token to new string */
920             rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset,
921                 -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ );
922 
923             /* decode token */
924             rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
925 
926             /* the result should not contain any '/' */
927             if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) )
928             {
929                 rtl_uString_release( pTmp );
930                 rtl_uString_release( ustrPathToken );
931 
932                 return osl_File_E_INVAL;
933             }
934 
935         } while( -1 != nIndex );
936 
937         /* release temporary string and restore index variable */
938         rtl_uString_release( ustrPathToken );
939         nIndex = 0;
940     }
941 
942     /* protocol and server should not be encoded, so decode the whole string */
943     rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
944 
945     /* check if file protocol specified */
946     /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
947     if( 7 <= pTmp->length )
948     {
949         rtl_uString * pProtocol = NULL;
950         rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
951 
952         /* protocol is case insensitive */
953         rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
954 
955         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
956             nIndex = 7;
957 
958         rtl_uString_release( pProtocol );
959     }
960 
961     /* skip "localhost" or "127.0.0.1" if "file://" is specified */
962     /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
963     if( nIndex && ( 10 <= pTmp->length - nIndex ) )
964     {
965         rtl_uString * pServer = NULL;
966         rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
967 
968         /* server is case insensitive */
969         rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
970 
971         if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
972             ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) )
973         {
974             /* don't exclude the '/' */
975             nIndex += 9;
976         }
977 
978         rtl_uString_release( pServer );
979     }
980 
981     if( nIndex )
982         rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex );
983 
984     /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
985     if( (sal_Unicode) '~' == pTmp->buffer[0] )
986     {
987         /* check if another user is specified */
988         if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) )
989         {
990             rtl_uString *pTmp2 = NULL;
991 
992             /* osl_getHomeDir returns file URL */
993             osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 );
994 
995             /* remove "file://" prefix */
996             rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 );
997 
998             /* replace '~' in original string */
999             rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 );
1000             rtl_uString_release( pTmp2 );
1001         }
1002 
1003         else
1004         {
1005             /* FIXME: replace ~user with users home directory */
1006             return osl_File_E_INVAL;
1007         }
1008     }
1009 
1010     /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
1011     /*
1012     OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
1013     */
1014 
1015     *pustrSystemPath = pTmp;
1016     return osl_File_E_None;
1017 #endif // 0
1018 }
1019 
1020 
1021 /****************************************************************************
1022  * osl_getSystemPathFromFileURL_Ex - helper function
1023  * clients may specify if they want to accept relative
1024  * URLs or not
1025  ****************************************************************************/
1026 
osl_getSystemPathFromFileURL_Ex(rtl_uString * ustrFileURL,rtl_uString ** pustrSystemPath,sal_Bool bAllowRelative)1027 oslFileError osl_getSystemPathFromFileURL_Ex(
1028     rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative)
1029 {
1030     return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, bAllowRelative);
1031 #if 0
1032     rtl_uString* temp = 0;
1033     oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
1034 
1035     if (osl_File_E_None == osl_error)
1036     {
1037         if (bAllowRelative
1038             || (UNICHAR_SLASH == temp->buffer[0])
1039             || (UNICHAR_COLON == temp->buffer[1] && UNICHAR_SLASH == temp->buffer[2]))
1040         {
1041             *pustrSystemPath = temp;
1042         }
1043         else
1044         {
1045             rtl_uString_release(temp);
1046             osl_error = osl_File_E_INVAL;
1047         }
1048     }
1049 
1050     return osl_error;
1051 #endif
1052 }
1053 
1054 namespace /* private */
1055 {
1056 
1057 #if 0 // YD
1058 
1059     /******************************************************
1060      * Helper function, return a pinter to the final '\0'
1061      * of a string
1062      ******************************************************/
1063 
1064     sal_Unicode* ustrtoend(sal_Unicode* pStr)
1065     {
1066         return (pStr + rtl_ustr_getLength(pStr));
1067     }
1068 
1069     /*********************************************
1070 
1071      ********************************************/
1072     sal_Unicode* ustrcpy(const sal_Unicode* s, sal_Unicode* d)
1073     {
1074         const sal_Unicode* sc = s;
1075         sal_Unicode*       dc = d;
1076 
1077         while ((*dc++ = *sc++))
1078             /**/;
1079 
1080         return d;
1081     }
1082 
1083     /*********************************************
1084 
1085      ********************************************/
1086 
1087     sal_Unicode* ustrncpy(const sal_Unicode* s, sal_Unicode* d, unsigned int n)
1088     {
1089         const sal_Unicode* sc = s;
1090         sal_Unicode*       dc = d;
1091         unsigned int       i  = n;
1092 
1093         while (i--)
1094             *dc++ = *sc++;
1095 
1096         if (n)
1097             *dc = 0;
1098 
1099         return d;
1100     }
1101 
1102     /*********************************************
1103 
1104      ********************************************/
1105 
1106     sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
1107     {
1108         sal_Unicode* p = ustrtoend(d);
1109         *p++ = chr;
1110         *p   = 0;
1111         return d;
1112     }
1113 
1114     /*********************************************
1115 
1116      ********************************************/
1117 
1118     sal_Unicode* ustrcat(const sal_Unicode* s, sal_Unicode* d)
1119     {
1120         sal_Unicode* dc = ustrtoend(d);
1121         ustrcpy(s, dc);
1122         return d;
1123     }
1124 
1125     /******************************************************
1126      *
1127      ******************************************************/
1128 
1129     bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
1130     {
1131         sal_Unicode* p = ustrtoend(pStr);
1132         if (p > pStr)
1133             p--;
1134         return (*p == Chr);
1135     }
1136 
1137     /******************************************************
1138      * Ensure that the given string has the specified last
1139      * character if necessary append it
1140      ******************************************************/
1141 
1142     sal_Unicode* _strensurelast(sal_Unicode* pStr, sal_Unicode Chr)
1143     {
1144         if (!_islastchr(pStr, Chr))
1145             ustrchrcat(Chr, pStr);
1146         return pStr;
1147     }
1148 
1149     /******************************************************
1150      * Remove the last part of a path, a path that has
1151      * only a '/' or no '/' at all will be returned
1152      * unmodified
1153      ******************************************************/
1154 
1155     sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath)
1156     {
1157         /*  we always may skip -2 because we
1158             may at least stand on a '/' but
1159             either there is no other character
1160             before this '/' or it's another
1161             character than the '/'
1162         */
1163         sal_Unicode* p = ustrtoend(aPath) - 2;
1164 
1165         // move back to the next path separator
1166         // or to the start of the string
1167         while ((p > aPath) && (*p != UNICHAR_SLASH))
1168             p--;
1169 
1170         if (p >= aPath)
1171         {
1172             if (UNICHAR_SLASH == *p)
1173             {
1174                 p++;
1175                *p = '\0';
1176             }
1177             else
1178             {
1179                 *p = '\0';
1180             }
1181         }
1182 
1183         return aPath;
1184     }
1185 
1186     /******************************************************
1187      *
1188      ******************************************************/
1189 
1190     oslFileError _osl_resolvepath(
1191         /*inout*/ sal_Unicode* path,
1192         /*inout*/ sal_Unicode* current_pos,
1193         /*in   */ sal_Unicode* sentinel,
1194         /*inout*/ bool* failed)
1195     {
1196         oslFileError ferr = osl_File_E_None;
1197 
1198         if (!*failed)
1199         {
1200             char unresolved_path[PATH_MAX];
1201             if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path)))
1202                 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1203 
1204             char resolved_path[PATH_MAX];
1205             if (realpath(unresolved_path, resolved_path))
1206             {
1207                 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
1208                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1209 
1210                 current_pos = ustrtoend(path) - 1;
1211             }
1212             else
1213             {
1214                 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
1215                     *failed = true;
1216                 else
1217                     ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
1218             }
1219         }
1220 
1221         return ferr;
1222     }
1223 
1224     /******************************************************
1225      * Works even with non existing paths. The resulting
1226      * path must not exceed PATH_MAX else
1227      * osl_File_E_NAMETOOLONG is the result
1228      ******************************************************/
1229 
1230     oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path)
1231     {
1232         // the given unresolved path must not exceed PATH_MAX
1233         if (unresolved_path.getLength() >= (PATH_MAX - 2))
1234             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1235 
1236         sal_Unicode        path_resolved_so_far[PATH_MAX];
1237         const sal_Unicode* punresolved = unresolved_path.getStr();
1238         sal_Unicode*       presolvedsf = path_resolved_so_far;
1239 
1240         // reserve space for leading '/' and trailing '\0'
1241         // do not exceed this limit
1242         sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2;
1243 
1244         // if realpath fails with error ENOTDIR, EACCES or ENOENT
1245         // we will not call it again, because _osl_realpath should also
1246         // work with non existing directories etc.
1247         bool realpath_failed = false;
1248         oslFileError ferr;
1249 
1250         path_resolved_so_far[0] = '\0';
1251 
1252         while (*punresolved != '\0')
1253         {
1254             // ignore '/.' , skip one part back when '/..'
1255 
1256             if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf))
1257             {
1258                 if ('\0' == *(punresolved + 1))
1259                 {
1260                     punresolved++;
1261                     continue;
1262                 }
1263                 else if (UNICHAR_SLASH == *(punresolved + 1))
1264                 {
1265                     punresolved += 2;
1266                     continue;
1267                 }
1268                 else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2))))
1269                 {
1270                     _rmlastpathtoken(path_resolved_so_far);
1271 
1272                     presolvedsf = ustrtoend(path_resolved_so_far) - 1;
1273 
1274                     if (UNICHAR_SLASH == *(punresolved + 2))
1275                         punresolved += 3;
1276                     else
1277                         punresolved += 2;
1278 
1279                     continue;
1280                 }
1281                 else // a file or directory name may start with '.'
1282                 {
1283                     if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1284                         return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1285 
1286                     ustrchrcat(*punresolved++, path_resolved_so_far);
1287 
1288                     if ('\0' == *punresolved && !realpath_failed)
1289                     {
1290                         ferr = _osl_resolvepath(
1291                             path_resolved_so_far,
1292                             presolvedsf,
1293                             sentinel,
1294                             &realpath_failed);
1295 
1296                         if (osl_File_E_None != ferr)
1297                             return ferr;
1298                     }
1299                 }
1300             }
1301             else if (UNICHAR_SLASH == *punresolved)
1302             {
1303                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1304                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1305 
1306                 ustrchrcat(*punresolved++, path_resolved_so_far);
1307 
1308                 if (!realpath_failed)
1309                 {
1310                     ferr = _osl_resolvepath(
1311                         path_resolved_so_far,
1312                         presolvedsf,
1313                         sentinel,
1314                         &realpath_failed);
1315 
1316                     if (osl_File_E_None != ferr)
1317                         return ferr;
1318 
1319                     if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH))
1320                     {
1321                         if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1322                             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1323 
1324                         ustrchrcat(UNICHAR_SLASH, path_resolved_so_far);
1325                     }
1326                 }
1327             }
1328             else // any other character
1329             {
1330                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1331                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1332 
1333                 ustrchrcat(*punresolved++, path_resolved_so_far);
1334 
1335                 if ('\0' == *punresolved && !realpath_failed)
1336                 {
1337                     ferr = _osl_resolvepath(
1338                         path_resolved_so_far,
1339                         presolvedsf,
1340                         sentinel,
1341                         &realpath_failed);
1342 
1343                     if (osl_File_E_None != ferr)
1344                         return ferr;
1345                 }
1346             }
1347         }
1348 
1349         sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
1350 
1351         OSL_ASSERT(len < PATH_MAX);
1352 
1353         resolved_path = rtl::OUString(path_resolved_so_far, len);
1354 
1355         return osl_File_E_None;
1356     }
1357 
1358 #endif // 0 // YD
1359 
1360 } // end namespace private
1361 
1362 #if OSL_DEBUG_LEVEL > 0
1363 
1364     //#####################################################
_osl_warnFile(const char * message,rtl_uString * ustrFile)1365     void _osl_warnFile( const char *message, rtl_uString *ustrFile )
1366     {
1367         char szBuffer[2048];
1368 
1369         if (ustrFile)
1370         {
1371             rtl_String  *strFile = NULL;
1372 
1373             rtl_uString2String( &strFile, rtl_uString_getStr( ustrFile ), rtl_uString_getLength( ustrFile ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
1374             snprintf( szBuffer, sizeof(szBuffer), message, strFile->buffer );
1375             rtl_string_release( strFile );
1376 
1377             message = szBuffer;
1378         }
1379         OSL_ENSURE( 0, message );
1380     }
1381 
1382 #endif // OSL_DEBUG_LEVEL > 0
1383 
1384 /******************************************************
1385  * osl_getAbsoluteFileURL
1386  ******************************************************/
1387 
1388 //oslFileError osl_getAbsoluteFileURL(rtl_uString*  ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
osl_getAbsoluteFileURL(rtl_uString * ustrBaseURL,rtl_uString * ustrRelativeURL,rtl_uString ** pustrAbsoluteURL)1389 oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL )
1390 {
1391     oslFileError    eError;
1392     rtl_uString     *ustrRelSysPath = NULL;
1393     rtl_uString     *ustrBaseSysPath = NULL;
1394 
1395     if ( ustrBaseURL && ustrBaseURL->length )
1396     {
1397         eError = _osl_getSystemPathFromFileURL( ustrBaseURL, &ustrBaseSysPath, sal_False );
1398         OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" );
1399 
1400         eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_True );
1401     }
1402     else
1403     {
1404         eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_False );
1405         OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" );
1406     }
1407 
1408     if ( !eError )
1409     {
1410         CHAR    szBuffer[_MAX_PATH];
1411         CHAR    szRelSysPath[_MAX_PATH];
1412         CHAR    szCurrentDir[_MAX_PATH];
1413         int     result;
1414         char*   cwd;
1415         int     rc;
1416 
1417 /*@@@ToDo
1418   Bad, bad hack, this only works if the base path
1419   really exists which is not necessary according
1420   to RFC2396
1421   The whole FileURL implementation should be merged
1422   with the rtl/uri class.
1423 */
1424         if ( ustrBaseSysPath )
1425         {
1426             CHAR    szBaseSysPath[_MAX_PATH];
1427 
1428             if (!g_CurrentDirectoryMutex)
1429                 g_CurrentDirectoryMutex = osl_createMutex();
1430 
1431             osl_acquireMutex( g_CurrentDirectoryMutex );
1432 
1433             cwd = getcwd( szCurrentDir, sizeof(szCurrentDir) );
1434             UnicodeToText( szBaseSysPath, sizeof(szBaseSysPath), ustrBaseSysPath->buffer, ustrBaseSysPath->length);
1435             rc = chdir( szBaseSysPath);
1436         }
1437 
1438         UnicodeToText( szRelSysPath, sizeof(szRelSysPath), ustrRelSysPath->buffer, ustrRelSysPath->length);
1439         result = !_abspath( szBuffer, szRelSysPath, sizeof(szBuffer));
1440 
1441         if ( ustrBaseSysPath )
1442         {
1443             rc = chdir( szCurrentDir );
1444 
1445             osl_releaseMutex( g_CurrentDirectoryMutex );
1446         }
1447 
1448         if ( result )
1449         {
1450                 rtl_uString *ustrAbsSysPath = NULL;
1451 
1452                 oslMakeUStrFromPsz( szBuffer, &ustrAbsSysPath);
1453 
1454                 eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL );
1455 
1456                 if ( ustrAbsSysPath )
1457                     rtl_uString_release( ustrAbsSysPath );
1458         }
1459         else
1460             eError = osl_File_E_INVAL;
1461     }
1462 
1463     if ( ustrBaseSysPath )
1464         rtl_uString_release( ustrBaseSysPath );
1465 
1466     if ( ustrRelSysPath )
1467         rtl_uString_release( ustrRelSysPath );
1468 
1469     return  eError;
1470 #if 0
1471     FileBase::RC  rc;
1472     rtl::OUString unresolved_path;
1473 
1474     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path);
1475 
1476     if(FileBase::E_None != rc)
1477         return oslFileError(rc);
1478 
1479     if (systemPathIsRelativePath(unresolved_path))
1480     {
1481         rtl::OUString base_path;
1482         rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False);
1483 
1484         if (FileBase::E_None != rc)
1485             return oslFileError(rc);
1486 
1487         rtl::OUString abs_path;
1488         systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
1489 
1490         unresolved_path = abs_path;
1491     }
1492 
1493     rtl::OUString resolved_path;
1494     rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
1495 
1496     if (FileBase::E_None == rc)
1497     {
1498         rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
1499         OSL_ASSERT(FileBase::E_None == rc);
1500     }
1501 
1502     return oslFileError(rc);
1503 #endif // 0
1504 }
1505 
1506 
1507 namespace /* private */
1508 {
1509 
1510     /*********************************************
1511      No separate error code if unicode to text
1512      conversion or getenv fails because for the
1513      caller there is no difference why a file
1514      could not be found in $PATH
1515      ********************************************/
1516 
find_in_PATH(const rtl::OUString & file_path,rtl::OUString & result)1517     bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
1518     {
1519         bool          bfound = false;
1520         rtl::OUString path   = rtl::OUString::createFromAscii("PATH");
1521         rtl::OUString env_path;
1522 
1523         if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
1524             bfound = osl::searchPath(file_path, env_path, result);
1525 
1526         return bfound;
1527     }
1528 
1529     /*********************************************
1530      No separate error code if unicode to text
1531      conversion or getcwd fails because for the
1532      caller there is no difference why a file
1533      could not be found in CDW
1534      ********************************************/
1535 
find_in_CWD(const rtl::OUString & file_path,rtl::OUString & result)1536     bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
1537     {
1538         bool bfound = false;
1539         rtl::OUString cwd_url;
1540 
1541         if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
1542         {
1543             rtl::OUString cwd;
1544             FileBase::getSystemPathFromFileURL(cwd_url, cwd);
1545             bfound = osl::searchPath(file_path, cwd, result);
1546         }
1547         return bfound;
1548     }
1549 
1550     /*********************************************
1551 
1552      ********************************************/
1553 
find_in_searchPath(const rtl::OUString & file_path,rtl_uString * search_path,rtl::OUString & result)1554     bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
1555     {
1556         return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
1557     }
1558 
1559 } // end namespace private
1560 
1561 
1562 /****************************************************************************
1563  *  osl_searchFileURL
1564  ***************************************************************************/
1565 
osl_searchFileURL(rtl_uString * ustrFilePath,rtl_uString * ustrSearchPath,rtl_uString ** pustrURL)1566 oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
1567 {
1568     OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
1569 
1570     FileBase::RC  rc;
1571     rtl::OUString file_path;
1572 
1573     // try to interpret search path as file url else assume it's a system path list
1574     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
1575     if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc))
1576         file_path = ustrFilePath;
1577     else if (FileBase::E_None != rc)
1578         return oslFileError(rc);
1579 
1580     bool          bfound = false;
1581     rtl::OUString result;
1582 
1583     if (find_in_searchPath(file_path, ustrSearchPath, result) ||
1584         find_in_PATH(file_path, result) ||
1585         find_in_CWD(file_path, result))
1586     {
1587         rtl::OUString resolved;
1588 
1589         if (osl::realpath(result, resolved))
1590         {
1591 #if OSL_DEBUG_LEVEL > 0
1592             oslFileError osl_error =
1593 #endif
1594                 osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
1595             OSL_ASSERT(osl_File_E_None == osl_error);
1596             bfound = true;
1597         }
1598     }
1599     return bfound ? osl_File_E_None : osl_File_E_NOENT;
1600 }
1601 
1602 
1603 /****************************************************************************
1604  * FileURLToPath
1605  ***************************************************************************/
1606 
FileURLToPath(char * buffer,size_t bufLen,rtl_uString * ustrFileURL)1607 oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
1608 {
1609     rtl_uString* ustrSystemPath = NULL;
1610     oslFileError osl_error      = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
1611 
1612     if(osl_File_E_None != osl_error)
1613         return osl_error;
1614 
1615     osl_systemPathRemoveSeparator(ustrSystemPath);
1616 
1617     /* convert unicode path to text */
1618     if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
1619         osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
1620 
1621     rtl_uString_release(ustrSystemPath);
1622 
1623     return osl_error;
1624 }
1625