diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2015-11-04 08:01:13 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2015-11-04 08:06:00 +0100 |
commit | 62dbe2e6eb30660f252b4e2c048f4aecf28e41c6 (patch) | |
tree | 9813494969a44c60316aec9af2ac10c41ef1e798 /sal/osl/unx | |
parent | c5fefe46fc9dca3942b2fc33ffd1f7e041d450e6 (diff) |
Clean up osl_getSystemPathFromFileURL implementation
Change-Id: I2daa355c4a46c4edc73c30185f2b31852351c45f
Diffstat (limited to 'sal/osl/unx')
-rw-r--r-- | sal/osl/unx/file_url.cxx | 216 |
1 files changed, 97 insertions, 119 deletions
diff --git a/sal/osl/unx/file_url.cxx b/sal/osl/unx/file_url.cxx index 1d8c1fd0314b..c0cbe5bc4741 100644 --- a/sal/osl/unx/file_url.cxx +++ b/sal/osl/unx/file_url.cxx @@ -21,22 +21,25 @@ #include "system.hxx" +#include <cassert> #include <limits.h> #include <errno.h> #include <strings.h> #include <unistd.h> #include "osl/file.hxx" -#include <osl/security.h> +#include <osl/security.hxx> #include <osl/diagnose.h> #include <osl/thread.h> #include <osl/process.h> #include <rtl/character.hxx> #include <rtl/uri.h> +#include <rtl/uri.hxx> #include <rtl/ustring.hxx> #include <rtl/ustrbuf.h> #include "rtl/textcvt.h" +#include <sal/log.hxx> #include "file_error_transl.hxx" #include "file_path_helper.hxx" @@ -81,36 +84,35 @@ oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uStrin return osl_File_E_None; } -oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath ) -{ - sal_Int32 nIndex; - rtl_uString * pTmp = NULL; - - sal_Unicode encodedSlash[3] = { '%', '2', 'F' }; +namespace { +oslFileError getSystemPathFromFileUrl( + OUString const & url, OUString * path, bool resolveHome) +{ + assert(path != nullptr); // For compatibility with assumptions in other parts of the code base, // assume that anything starting with a slash is a system path instead of a // (relative) file URL (except if it starts with two slashes, in which case // it is a relative URL with an authority component): - if (ustrFileURL->length == 0 - || (ustrFileURL->buffer[0] == '/' - && (ustrFileURL->length == 1 || ustrFileURL->buffer[1] != '/'))) + if (url.isEmpty() + || (url[0] == '/' && (url.getLength() == 1 || url[1] != '/'))) { return osl_File_E_INVAL; } - // Check for non file scheme: - if (rtl::isAsciiAlpha(ustrFileURL->buffer[0])) { - for (sal_Int32 i = 1; i != ustrFileURL->length; ++i) { - auto c = ustrFileURL->buffer[i]; + sal_Int32 i = 0; + if (rtl::isAsciiAlpha(url[0])) { + for (sal_Int32 j = 1; j != url.getLength(); ++j) { + auto c = url[j]; if (c == ':') { if (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( - ustrFileURL->buffer, i, + url.pData->buffer, j, RTL_CONSTASCII_STRINGPARAM("file")) != 0) { return osl_File_E_INVAL; } + i = j + 1; break; } else if (!rtl::isAsciiAlphanumeric(c) && c != '+' && c != '-' && c != '.') @@ -119,121 +121,97 @@ oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rt } } } - - /* search for encoded slashes (%2F) and decode every single token if we find one */ - - nIndex = 0; - - if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) ) - { - rtl_uString * ustrPathToken = NULL; - sal_Int32 nOffset = 7; - - do - { - nOffset += nIndex; - - /* break url down in '/' divided tokens tokens */ - nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, '/' ); - - /* copy token to new string */ - rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset, - -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ ); - - /* decode token */ - rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); - - /* the result should not contain any '/' */ - if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, '/' ) ) - { - rtl_uString_release( pTmp ); - rtl_uString_release( ustrPathToken ); - - return osl_File_E_INVAL; - } - - } while( -1 != nIndex ); - - /* release temporary string and restore index variable */ - rtl_uString_release( ustrPathToken ); - nIndex = 0; - } - - /* protocol and server should not be encoded, so decode the whole string */ - rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); - - /* check if file protocol specified */ - /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ - if( 7 <= pTmp->length ) - { - rtl_uString * pProtocol = NULL; - rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 ); - - /* protocol is case insensitive */ - rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length ); - - if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) ) - nIndex = 7; - - rtl_uString_release( pProtocol ); + // Handle query or fragment: + if (url.indexOf('?', i) != -1 || url.indexOf('#', i) != -1) { + return osl_File_E_INVAL; } - - /* skip "localhost" or "127.0.0.1" if "file://" is specified */ - /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ - if( nIndex && ( 10 <= pTmp->length - nIndex ) ) - { - rtl_uString * pServer = NULL; - rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 ); - - /* server is case insensitive */ - rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length ); - - if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) || - ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) ) + // Handle authority: + if (url.getLength() - i >= 2 && url[i] == '/' && url[i + 1] == '/') { + i += 2; + sal_Int32 j = url.indexOf('/', i); + if (j == -1) { + j = url.getLength(); + } + if (j != i + && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( + url.pData->buffer + i, j - i, + RTL_CONSTASCII_STRINGPARAM("localhost")) + != 0) + && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( + url.pData->buffer + i, j - i, + RTL_CONSTASCII_STRINGPARAM("127.0.0.1")) + != 0)) { - /* don't exclude the '/' */ - nIndex += 9; + return osl_File_E_INVAL; } - - rtl_uString_release( pServer ); + i = j; } - - if( nIndex ) - rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex ); - - /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ - if( '~' == pTmp->buffer[0] ) - { - /* check if another user is specified */ - if( ( 1 == pTmp->length ) || ( '/' == pTmp->buffer[1] ) ) - { - rtl_uString *pTmp2 = NULL; - - /* osl_getHomeDir returns file URL */ - oslSecurity pSecurity = osl_getCurrentSecurity(); - osl_getHomeDir( pSecurity , &pTmp2 ); - osl_freeSecurityHandle( pSecurity ); - - /* remove "file://" prefix */ - rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 ); - - /* replace '~' in original string */ - rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 ); - rtl_uString_release( pTmp2 ); + // Handle empty path: + if (i == url.getLength()) { + *path = "/"; + return osl_File_E_None; + } + // Path must not contain %2F: + if (url.indexOf("%2F", i) != -1 || url.indexOf("%2f", i) != -1) { + return osl_File_E_INVAL; + } + *path = rtl::Uri::decode( + url.copy(i), rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8); + // Path must not contain %2F: + if (path->indexOf('\0') != -1) { + return osl_File_E_INVAL; + } + // Handle ~ notation: + if (resolveHome && path->getLength() >= 2 && (*path)[1] == '~') { + sal_Int32 j = path->indexOf('/', 2); + if (j == -1) { + j = path->getLength(); } - - else - { - /* FIXME: replace ~user with users home directory */ + if (j == 2) { + OUString home; + if (!osl::Security().getHomeDir(home)) { + SAL_WARN("sal.osl", "osl::Security::getHomeDir failed"); + return osl_File_E_INVAL; + } + i = url.indexOf('/', i + 1); + if (i == -1) { + i = url.getLength(); + } else { + ++i; + } + //TODO: cheesy way of ensuring home's path ends in slash: + if (!home.isEmpty() && home[home.getLength() - 1] != '/') { + home += "/"; + } + try { + home = rtl::Uri::convertRelToAbs(home, url.copy(i)); + } catch (rtl::MalformedUriException & e) { + SAL_WARN( + "sal.osl", "rtl::MalformedUriException " << e.getMessage()); + return osl_File_E_INVAL; + } + return getSystemPathFromFileUrl(home, path, false); + } else { + // FIXME: replace ~user with user's home directory return osl_File_E_INVAL; } } - - rtl_uString_assign ( pustrSystemPath, pTmp ); - rtl_uString_release ( pTmp ); return osl_File_E_None; } +} + +oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath ) +{ + OUString path; + auto e = getSystemPathFromFileUrl( + OUString::unacquired(&ustrFileURL), &path, true); + if (e == osl_File_E_None) { + rtl_uString_assign(pustrSystemPath, path.pData); + } + return e; +} + oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL ) { static const sal_Unicode pDoubleSlash[2] = { '/', '/' }; |