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 whether 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 occurrences 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 '/' divided 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