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