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