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