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