summaryrefslogtreecommitdiff
path: root/sal/osl/w32/file_url.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/w32/file_url.cxx')
-rw-r--r--sal/osl/w32/file_url.cxx119
1 files changed, 74 insertions, 45 deletions
diff --git a/sal/osl/w32/file_url.cxx b/sal/osl/w32/file_url.cxx
index a0cb52257b96..e71da15a66b9 100644
--- a/sal/osl/w32/file_url.cxx
+++ b/sal/osl/w32/file_url.cxx
@@ -28,6 +28,7 @@
#include "file_error.hxx"
#include <rtl/alloc.h>
+#include <rtl/character.hxx>
#include <rtl/ustring.hxx>
#include <osl/mutex.h>
#include <o3tl/char16_t2wchar_t.hxx>
@@ -40,8 +41,6 @@
// FileURL functions
-oslMutex g_CurrentDirectoryMutex = nullptr; /* Initialized in dllentry.c */
-
static bool IsValidFilePathComponent(
sal_Unicode const * lpComponent, sal_Unicode const **lppComponentEnd,
DWORD dwFlags)
@@ -991,9 +990,40 @@ oslFileError SAL_CALL osl_searchFileURL(
return error;
}
+namespace
+{
+bool startsWithDriveColon(const rtl_uString* path)
+{
+ return rtl::isAsciiAlpha(path->buffer[0]) && path->buffer[1] == ':';
+}
+bool startsWithDriveColonSlash(const rtl_uString* path)
+{
+ return startsWithDriveColon(path) && path->buffer[2] == '\\';
+}
+// An absolute path starts either with \\ (an UNC or device path like \\.\ or \\?\)
+// or with a ASCII alpha character followed by colon followed by backslash.
+bool isAbsolute(const rtl_uString* path)
+{
+ return (path->buffer[0] == '\\' && path->buffer[1] == '\\') || startsWithDriveColonSlash(path);
+}
+bool onSameDrive(const rtl_uString* path1, const rtl_uString* path2)
+{
+ return rtl::toAsciiUpperCase(path1->buffer[0]) == rtl::toAsciiUpperCase(path2->buffer[0])
+ && rtl::toAsciiUpperCase(path1->buffer[1]) == rtl::toAsciiUpperCase(path2->buffer[1]);
+}
+OUString combinePath(rtl_uString* basePath, const sal_Unicode* relPath)
+{
+ const bool needSep = basePath->buffer[basePath->length - 1] != '\\' && relPath[0] != '\\';
+ const auto sSeparator = needSep ? std::u16string_view(u"\\") : std::u16string_view();
+ if (basePath->buffer[basePath->length - 1] == '\\' && relPath[0] == '\\')
+ ++relPath; // avoid two agjacent backslashes
+ return OUString::unacquired(&basePath) + sSeparator + relPath;
+}
+}
+
oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL )
{
- oslFileError eError;
+ oslFileError eError = osl_File_E_None;
rtl_uString *ustrRelSysPath = nullptr;
rtl_uString *ustrBaseSysPath = nullptr;
@@ -1001,64 +1031,63 @@ oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uStr
{
eError = osl_getSystemPathFromFileURL_( ustrBaseURL, &ustrBaseSysPath, false );
OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" );
-
- eError = osl_getSystemPathFromFileURL_( ustrRelativeURL, &ustrRelSysPath, true );
}
- else
+ if (eError == osl_File_E_None)
{
- eError = osl_getSystemPathFromFileURL_( ustrRelativeURL, &ustrRelSysPath, false );
+ eError = osl_getSystemPathFromFileURL_(ustrRelativeURL, &ustrRelSysPath,
+ ustrBaseSysPath != nullptr);
OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" );
}
if ( !eError )
{
- ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
- ::osl::LongPathBuffer< sal_Unicode > aCurrentDir( MAX_LONG_PATH );
- LPWSTR lpFilePart = nullptr;
- DWORD dwResult;
-
-/*@@@ToDo
- Bad, bad hack, this only works if the base path
- really exists which is not necessary according
- to RFC2396
- The whole FileURL implementation should be merged
- with the rtl/uri class.
-*/
- if ( ustrBaseSysPath )
- {
- osl_acquireMutex( g_CurrentDirectoryMutex );
-
- GetCurrentDirectoryW( aCurrentDir.getBufSizeInSymbols(), o3tl::toW(aCurrentDir) );
- SetCurrentDirectoryW( o3tl::toW(ustrBaseSysPath->buffer) );
- }
-
- dwResult = GetFullPathNameW( o3tl::toW(ustrRelSysPath->buffer), aBuffer.getBufSizeInSymbols(), o3tl::toW(aBuffer), &lpFilePart );
+ OUString sResultPath;
- if ( ustrBaseSysPath )
+ // If ustrRelSysPath is absolute, we don't need ustrBaseSysPath.
+ if (ustrBaseSysPath && !isAbsolute(ustrRelSysPath))
{
- SetCurrentDirectoryW( o3tl::toW(aCurrentDir) );
+ // ustrBaseSysPath is known here to be a valid absolute path -> its first two characters
+ // are ASCII (either alpha + colon, or double backslashes)
- osl_releaseMutex( g_CurrentDirectoryMutex );
- }
+ // Don't use SetCurrentDirectoryW together with GetFullPathNameW, because:
+ // (a) it needs synchronization and may affect threads that may access relative paths;
+ // (b) it would fail or give wrong results for non-existing base path (possible in URL).
- if ( dwResult )
- {
- if ( dwResult >= aBuffer.getBufSizeInSymbols() )
- eError = osl_File_E_INVAL;
- else
+ if (startsWithDriveColon(ustrRelSysPath))
{
- rtl_uString *ustrAbsSysPath = nullptr;
-
- rtl_uString_newFromStr( &ustrAbsSysPath, aBuffer );
-
- eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL );
+ // Special case: a path relative to a specific drive's current directory.
+ // Should we error out here?
- if ( ustrAbsSysPath )
- rtl_uString_release( ustrAbsSysPath );
+ if (onSameDrive(ustrRelSysPath, ustrBaseSysPath))
+ {
+ // If ustrBaseSysPath defines a path on the same drive, combine them
+ sResultPath = combinePath(ustrBaseSysPath, ustrRelSysPath->buffer + 2);
+ }
+ else
+ {
+ // Otherwise just call GetFullPathNameW to get current directory on that drive
+ osl::LongPathBuffer<wchar_t> aBuf(MAX_LONG_PATH);
+ DWORD dwResult = GetFullPathNameW(o3tl::toW(ustrRelSysPath->buffer),
+ aBuf.getBufSizeInSymbols(), aBuf, nullptr);
+ if (dwResult)
+ {
+ if (dwResult >= aBuf.getBufSizeInSymbols())
+ eError = osl_File_E_INVAL;
+ else
+ sResultPath = o3tl::toU(aBuf);
+ }
+ else
+ eError = oslTranslateFileError(GetLastError());
+ }
}
+ else
+ sResultPath = combinePath(ustrBaseSysPath, ustrRelSysPath->buffer);
}
else
- eError = oslTranslateFileError( GetLastError() );
+ sResultPath = OUString::unacquired(&ustrRelSysPath);
+
+ if (eError == osl_File_E_None)
+ eError = osl_getFileURLFromSystemPath(sResultPath.pData, pustrAbsoluteURL);
}
if ( ustrBaseSysPath )