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.h"
21 :
22 : #include "system.h"
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.h"
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 independend, 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 1999740 : oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
84 : {
85 : sal_Int32 nIndex;
86 1999740 : rtl_uString * pTmp = NULL;
87 :
88 1999740 : sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
89 1999740 : sal_Unicode protocolDelimiter[3] = { ':', '/', '/' };
90 :
91 : /* a valid file url may not start with '/' */
92 1999740 : if( ( 0 == ustrFileURL->length ) || ( '/' == ustrFileURL->buffer[0] ) )
93 : {
94 72 : return osl_File_E_INVAL;
95 : }
96 :
97 : /* Check for non file:// protocols */
98 :
99 1999668 : nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 );
100 1999668 : if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) )
101 : {
102 0 : return osl_File_E_INVAL;
103 : }
104 :
105 : /* search for encoded slashes (%2F) and decode every single token if we find one */
106 :
107 1999668 : nIndex = 0;
108 :
109 1999668 : 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 1999668 : 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 1999668 : if( 7 <= pTmp->length )
150 : {
151 1999668 : rtl_uString * pProtocol = NULL;
152 1999668 : rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
153 :
154 : /* protocol is case insensitive */
155 1999668 : rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
156 :
157 1999668 : if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
158 1999668 : nIndex = 7;
159 :
160 1999668 : 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 1999668 : if( nIndex && ( 10 <= pTmp->length - nIndex ) )
166 : {
167 1999557 : rtl_uString * pServer = NULL;
168 1999557 : rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
169 :
170 : /* server is case insensitive */
171 1999557 : rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
172 :
173 3999114 : if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
174 1999557 : ( 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 1999557 : rtl_uString_release( pServer );
181 : }
182 :
183 1999668 : if( nIndex )
184 1999668 : 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 1999668 : 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 1999668 : rtl_uString_assign ( pustrSystemPath, pTmp );
215 1999668 : rtl_uString_release ( pTmp );
216 1999668 : return osl_File_E_None;
217 : }
218 :
219 1615453 : oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
220 : {
221 : static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
222 :
223 1615453 : rtl_uString *pTmp = NULL;
224 : sal_Int32 nIndex;
225 :
226 1615453 : if( 0 == ustrSystemPath->length )
227 0 : return osl_File_E_INVAL;
228 :
229 : /* temporary hack: if already file url, return ustrSystemPath */
230 :
231 1615453 : 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 0 : 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 1615453 : 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 1615453 : nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
281 1615453 : if( -1 != nIndex )
282 : {
283 : sal_Int32 nSrcIndex;
284 0 : sal_Int32 nDeleted = 0;
285 :
286 : /* if pTmp is not already allocated, copy ustrSystemPath for modification */
287 0 : if( NULL == pTmp )
288 0 : rtl_uString_newFromString( &pTmp, ustrSystemPath );
289 :
290 : /* adapt index to pTmp */
291 0 : nIndex += pTmp->length - ustrSystemPath->length;
292 :
293 : /* remove all occurrences of '//' */
294 0 : for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
295 : {
296 0 : if( ('/' == pTmp->buffer[nSrcIndex]) && ('/' == pTmp->buffer[nIndex]) )
297 0 : nDeleted++;
298 : else
299 0 : pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
300 : }
301 :
302 : /* adjust length member */
303 0 : pTmp->length -= nDeleted;
304 : }
305 :
306 1615453 : if( NULL == pTmp )
307 1615453 : rtl_uString_assign( &pTmp, ustrSystemPath );
308 :
309 : /* file URLs must be URI encoded */
310 1615453 : rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
311 :
312 1615453 : rtl_uString_release( pTmp );
313 :
314 : /* absolute urls should start with 'file://' */
315 1615453 : if( '/' == (*pustrFileURL)->buffer[0] )
316 : {
317 1615453 : rtl_uString *pProtocol = NULL;
318 :
319 1615453 : rtl_uString_newFromAscii( &pProtocol, "file://" );
320 1615453 : rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
321 1615453 : rtl_uString_release( pProtocol );
322 : }
323 :
324 1615453 : return osl_File_E_None;
325 : }
326 :
327 : /*
328 : * relative URLs are not accepted
329 : */
330 1234580 : oslFileError osl_getSystemPathFromFileURL_Ex(
331 : rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath)
332 : {
333 1234580 : rtl_uString* temp = 0;
334 1234580 : oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
335 :
336 1234580 : if (osl_File_E_None == osl_error)
337 : {
338 1234508 : if ('/' == temp->buffer[0])
339 : {
340 1234508 : *pustrSystemPath = temp;
341 : }
342 : else
343 : {
344 0 : rtl_uString_release(temp);
345 0 : osl_error = osl_File_E_INVAL;
346 : }
347 : }
348 :
349 1234580 : 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 18235821 : sal_Unicode* ustrtoend(sal_Unicode* pStr)
361 : {
362 18235821 : return (pStr + rtl_ustr_getLength(pStr));
363 : }
364 :
365 8459055 : sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
366 : {
367 8459055 : sal_Unicode* p = ustrtoend(d);
368 8459055 : *p++ = chr;
369 8459055 : *p = 0;
370 8459055 : return d;
371 : }
372 :
373 1062683 : bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
374 : {
375 1062683 : sal_Unicode* p = ustrtoend(pStr);
376 1062683 : if (p > pStr)
377 1062683 : p--;
378 1062683 : 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 127514 : 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 127514 : sal_Unicode* p = ustrtoend(aPath) - 2;
396 :
397 : // move back to the next path separator
398 : // or to the start of the string
399 807586 : while ((p > aPath) && (*p != '/'))
400 552558 : p--;
401 :
402 127514 : if (p >= aPath)
403 : {
404 127514 : if ('/' == *p)
405 : {
406 127514 : p++;
407 127514 : *p = '\0';
408 : }
409 : else
410 : {
411 0 : *p = '\0';
412 : }
413 : }
414 :
415 127514 : return aPath;
416 : }
417 :
418 1147710 : oslFileError _osl_resolvepath(
419 : /*inout*/ sal_Unicode* path,
420 : /*inout*/ bool* failed)
421 : {
422 1147710 : oslFileError ferr = osl_File_E_None;
423 :
424 1147710 : if (!*failed)
425 : {
426 : char unresolved_path[PATH_MAX];
427 1147710 : 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 1147710 : if (realpath(unresolved_path, resolved_path))
432 : {
433 1147710 : if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
434 0 : return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
435 :
436 : }
437 : else
438 : {
439 0 : if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
440 0 : *failed = true;
441 : else
442 0 : ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
443 : }
444 : }
445 :
446 1147710 : 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 127526 : 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 127526 : 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 127526 : const sal_Unicode* punresolved = unresolved_path.getStr();
463 127526 : sal_Unicode* presolvedsf = path_resolved_so_far;
464 :
465 : // reserve space for leading '/' and trailing '\0'
466 : // do not exceed this limit
467 127526 : 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 127526 : bool realpath_failed = false;
473 : oslFileError ferr;
474 :
475 127526 : path_resolved_so_far[0] = '\0';
476 :
477 7906464 : while (*punresolved != '\0')
478 : {
479 : // ignore '/.' , skip one part back when '/..'
480 :
481 7651412 : if (('.' == *punresolved) && ('/' == *presolvedsf))
482 : {
483 127528 : if ('\0' == *(punresolved + 1))
484 : {
485 0 : punresolved++;
486 0 : continue;
487 : }
488 127521 : else if ('/' == *(punresolved + 1))
489 : {
490 0 : punresolved += 2;
491 0 : continue;
492 : }
493 127521 : else if (('.' == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || ('/' == *(punresolved + 2))))
494 : {
495 127514 : _rmlastpathtoken(path_resolved_so_far);
496 :
497 127514 : presolvedsf = ustrtoend(path_resolved_so_far) - 1;
498 :
499 127514 : if ('/' == *(punresolved + 2))
500 85015 : punresolved += 3;
501 : else
502 42499 : punresolved += 2;
503 :
504 127514 : continue;
505 : }
506 : else // a file or directory name may start with '.'
507 : {
508 7 : if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
509 0 : return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
510 :
511 7 : ustrchrcat(*punresolved++, path_resolved_so_far);
512 :
513 7 : 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 7523891 : else if ('/' == *punresolved)
525 : {
526 1062683 : if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
527 0 : return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
528 :
529 1062683 : ustrchrcat(*punresolved++, path_resolved_so_far);
530 :
531 1062683 : if (!realpath_failed)
532 : {
533 : ferr = _osl_resolvepath(
534 : path_resolved_so_far,
535 1062683 : &realpath_failed);
536 :
537 1062683 : if (osl_File_E_None != ferr)
538 0 : return ferr;
539 :
540 1062683 : if (!_islastchr(path_resolved_so_far, '/'))
541 : {
542 935157 : if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
543 0 : return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
544 :
545 935157 : ustrchrcat('/', path_resolved_so_far);
546 : }
547 : }
548 : }
549 : else // any other character
550 : {
551 6461208 : if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
552 0 : return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
553 :
554 6461208 : ustrchrcat(*punresolved++, path_resolved_so_far);
555 :
556 6461208 : if ('\0' == *punresolved && !realpath_failed)
557 : {
558 : ferr = _osl_resolvepath(
559 : path_resolved_so_far,
560 85027 : &realpath_failed);
561 :
562 85027 : if (osl_File_E_None != ferr)
563 0 : return ferr;
564 : }
565 : }
566 : }
567 :
568 127526 : sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
569 :
570 : OSL_ASSERT(len < PATH_MAX);
571 :
572 127526 : resolved_path = rtl::OUString(path_resolved_so_far, len);
573 :
574 127526 : return osl_File_E_None;
575 : }
576 :
577 : }
578 :
579 127526 : 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 127526 : rtl::OUString relUrl(ustrRelativeURL);
585 127526 : if (relUrl.startsWith("//")) {
586 0 : relUrl = "file:" + relUrl;
587 127526 : } else if (relUrl.startsWith("/")) {
588 0 : relUrl = "file://" + relUrl;
589 : }
590 :
591 : FileBase::RC rc;
592 255052 : rtl::OUString unresolved_path;
593 :
594 127526 : rc = FileBase::getSystemPathFromFileURL(relUrl, unresolved_path);
595 :
596 127526 : if(FileBase::E_None != rc)
597 0 : return oslFileError(rc);
598 :
599 127526 : if (systemPathIsRelativePath(unresolved_path))
600 : {
601 0 : rtl::OUString base_path;
602 0 : rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData);
603 :
604 0 : if (FileBase::E_None != rc)
605 0 : return oslFileError(rc);
606 :
607 0 : rtl::OUString abs_path;
608 0 : systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
609 :
610 0 : unresolved_path = abs_path;
611 : }
612 :
613 255052 : rtl::OUString resolved_path;
614 127526 : rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
615 127526 : if (FileBase::E_None == rc)
616 : {
617 127526 : rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
618 : OSL_ASSERT(FileBase::E_None == rc);
619 : }
620 :
621 255052 : return oslFileError(rc);
622 : }
623 :
624 : namespace
625 : {
626 :
627 : /*********************************************
628 : No separate error code if unicode to text
629 : conversion or getenv fails because for the
630 : caller there is no difference why a file
631 : could not be found in $PATH
632 : ********************************************/
633 :
634 0 : bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
635 : {
636 0 : bool bfound = false;
637 0 : rtl::OUString path("PATH");
638 0 : rtl::OUString env_path;
639 :
640 0 : if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
641 0 : bfound = osl::searchPath(file_path, env_path, result);
642 :
643 0 : return bfound;
644 : }
645 :
646 : /*********************************************
647 : No separate error code if unicode to text
648 : conversion or getcwd fails because for the
649 : caller there is no difference why a file
650 : could not be found in CDW
651 : ********************************************/
652 :
653 0 : bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
654 : {
655 0 : bool bfound = false;
656 0 : rtl::OUString cwd_url;
657 :
658 0 : if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
659 : {
660 0 : rtl::OUString cwd;
661 0 : FileBase::getSystemPathFromFileURL(cwd_url, cwd);
662 0 : bfound = osl::searchPath(file_path, cwd, result);
663 : }
664 0 : return bfound;
665 : }
666 :
667 0 : bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
668 : {
669 0 : return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
670 : }
671 :
672 : }
673 :
674 0 : oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
675 : {
676 : OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
677 :
678 : FileBase::RC rc;
679 0 : rtl::OUString file_path;
680 :
681 : // try to interpret search path as file url else assume it's a system path list
682 0 : rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
683 0 : if (FileBase::E_INVAL == rc)
684 0 : file_path = ustrFilePath;
685 0 : else if (FileBase::E_None != rc)
686 0 : return oslFileError(rc);
687 :
688 0 : bool bfound = false;
689 0 : rtl::OUString result;
690 :
691 0 : if (find_in_searchPath(file_path, ustrSearchPath, result) ||
692 0 : find_in_PATH(file_path, result) ||
693 0 : find_in_CWD(file_path, result))
694 : {
695 0 : rtl::OUString resolved;
696 :
697 0 : if (osl::realpath(result, resolved))
698 : {
699 : #if OSL_DEBUG_LEVEL > 0
700 : oslFileError osl_error =
701 : #endif
702 0 : osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
703 : OSL_ASSERT(osl_File_E_None == osl_error);
704 0 : bfound = true;
705 0 : }
706 : }
707 0 : return bfound ? osl_File_E_None : osl_File_E_NOENT;
708 : }
709 :
710 340073 : oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
711 : {
712 340073 : rtl_uString* ustrSystemPath = NULL;
713 340073 : oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
714 :
715 340073 : if(osl_File_E_None != osl_error)
716 0 : return osl_error;
717 :
718 340073 : osl_systemPathRemoveSeparator(ustrSystemPath);
719 :
720 : /* convert unicode path to text */
721 340073 : if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
722 0 : osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
723 :
724 340073 : rtl_uString_release(ustrSystemPath);
725 :
726 340073 : return osl_error;
727 : }
728 :
729 : namespace
730 : {
731 : class UnicodeToTextConverter_Impl
732 : {
733 : rtl_UnicodeToTextConverter m_converter;
734 :
735 85011 : UnicodeToTextConverter_Impl()
736 85011 : : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
737 85011 : {}
738 :
739 85011 : ~UnicodeToTextConverter_Impl()
740 : {
741 85011 : rtl_destroyUnicodeToTextConverter (m_converter);
742 85011 : }
743 : public:
744 1530378 : static UnicodeToTextConverter_Impl & getInstance()
745 : {
746 1530378 : static UnicodeToTextConverter_Impl g_theConverter;
747 1530378 : return g_theConverter;
748 : }
749 :
750 1530378 : sal_Size convert(
751 : sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes,
752 : sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars)
753 : {
754 : OSL_ASSERT(m_converter != 0);
755 : return rtl_convertUnicodeToText (
756 1530378 : m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars);
757 : }
758 : };
759 : }
760 :
761 1530378 : int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
762 : {
763 1530378 : sal_uInt32 nInfo = 0;
764 1530378 : sal_Size nSrcChars = 0;
765 :
766 1530378 : sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert (
767 : uniText, uniTextLen, buffer, bufLen,
768 3060756 : OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars);
769 :
770 1530378 : if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
771 : {
772 0 : errno = EOVERFLOW;
773 0 : return 0;
774 : }
775 :
776 : /* ensure trailing '\0' */
777 1530378 : buffer[nDestBytes] = '\0';
778 1530378 : return nDestBytes;
779 : }
780 :
781 : namespace
782 : {
783 : class TextToUnicodeConverter_Impl
784 : {
785 : rtl_TextToUnicodeConverter m_converter;
786 :
787 85011 : TextToUnicodeConverter_Impl()
788 85011 : : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
789 85011 : {}
790 :
791 85011 : ~TextToUnicodeConverter_Impl()
792 : {
793 85011 : rtl_destroyTextToUnicodeConverter (m_converter);
794 85011 : }
795 :
796 : public:
797 1147710 : static TextToUnicodeConverter_Impl & getInstance()
798 : {
799 1147710 : static TextToUnicodeConverter_Impl g_theConverter;
800 1147710 : return g_theConverter;
801 : }
802 :
803 1147710 : sal_Size convert(
804 : sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars,
805 : sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes)
806 : {
807 : OSL_ASSERT(m_converter != 0);
808 : return rtl_convertTextToUnicode (
809 1147710 : m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes);
810 : }
811 : };
812 : }
813 :
814 1147710 : int TextToUnicode(
815 : const char* text,
816 : size_t text_buffer_size,
817 : sal_Unicode* unic_text,
818 : sal_Int32 unic_text_buffer_size)
819 : {
820 1147710 : sal_uInt32 nInfo = 0;
821 1147710 : sal_Size nSrcChars = 0;
822 :
823 1147710 : sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert(
824 : text, text_buffer_size, unic_text, unic_text_buffer_size,
825 2295420 : OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars);
826 :
827 1147710 : if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
828 : {
829 0 : errno = EOVERFLOW;
830 0 : return 0;
831 : }
832 :
833 : /* ensure trailing '\0' */
834 1147710 : unic_text[nDestBytes] = '\0';
835 1147710 : return nDestBytes;
836 : }
837 :
838 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|