summaryrefslogtreecommitdiff
path: root/sal/osl/w32/file_dirvol.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/w32/file_dirvol.cxx')
-rw-r--r--sal/osl/w32/file_dirvol.cxx1867
1 files changed, 1867 insertions, 0 deletions
diff --git a/sal/osl/w32/file_dirvol.cxx b/sal/osl/w32/file_dirvol.cxx
new file mode 100644
index 000000000000..09bdec7988c3
--- /dev/null
+++ b/sal/osl/w32/file_dirvol.cxx
@@ -0,0 +1,1867 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define UNICODE
+#define _UNICODE
+#define _WIN32_WINNT_0x0500
+#include "systools/win32/uwinapi.h"
+
+#include "osl/file.h"
+
+#include "file_url.h"
+#include "file_error.h"
+
+#include "path_helper.hxx"
+
+#include "osl/diagnose.h"
+#include "osl/time.h"
+#include "rtl/alloc.h"
+#include "rtl/ustring.hxx"
+
+#include <tchar.h>
+#ifdef __MINGW32__
+#include <ctype.h>
+#endif
+
+//#####################################################
+#define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0])))
+
+static const wchar_t UNC_PREFIX[] = L"\\\\";
+static const wchar_t BACKSLASH = '\\';
+static const wchar_t SLASH = '/';
+
+//#####################################################
+extern "C" BOOL TimeValueToFileTime(const TimeValue *cpTimeVal, FILETIME *pFTime)
+{
+ SYSTEMTIME BaseSysTime;
+ FILETIME BaseFileTime;
+ FILETIME FTime;
+ __int64 localTime;
+ BOOL fSuccess = FALSE;
+
+ BaseSysTime.wYear = 1970;
+ BaseSysTime.wMonth = 1;
+ BaseSysTime.wDayOfWeek = 0;
+ BaseSysTime.wDay = 1;
+ BaseSysTime.wHour = 0;
+ BaseSysTime.wMinute = 0;
+ BaseSysTime.wSecond = 0;
+ BaseSysTime.wMilliseconds = 0;
+
+ if (cpTimeVal==NULL)
+ return fSuccess;
+
+ if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) )
+ {
+ __int64 timeValue;
+ localTime=cpTimeVal->Seconds*(__int64)10000000+cpTimeVal->Nanosec/100;
+ *(__int64 *)&FTime=localTime;
+ fSuccess = 0 <= (timeValue= *((__int64 *)&BaseFileTime) + *((__int64 *) &FTime));
+ if (fSuccess)
+ *(__int64 *)pFTime=timeValue;
+ }
+ return fSuccess;
+}
+
+//#####################################################
+extern "C" BOOL FileTimeToTimeValue(const FILETIME *cpFTime, TimeValue *pTimeVal)
+{
+ SYSTEMTIME BaseSysTime;
+ FILETIME BaseFileTime;
+ BOOL fSuccess = FALSE; /* Assume failure */
+
+ BaseSysTime.wYear = 1970;
+ BaseSysTime.wMonth = 1;
+ BaseSysTime.wDayOfWeek = 0;
+ BaseSysTime.wDay = 1;
+ BaseSysTime.wHour = 0;
+ BaseSysTime.wMinute = 0;
+ BaseSysTime.wSecond = 0;
+ BaseSysTime.wMilliseconds = 0;
+
+ if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) )
+ {
+ __int64 Value;
+
+ fSuccess = 0 <= (Value = *((__int64 *)cpFTime) - *((__int64 *)&BaseFileTime));
+
+ if ( fSuccess )
+ {
+ pTimeVal->Seconds = (unsigned long) (Value / 10000000L);
+ pTimeVal->Nanosec = (unsigned long)((Value % 10000000L) * 100);
+ }
+ }
+ return fSuccess;
+}
+
+//#####################################################
+namespace /* private */
+{
+ //#####################################################
+ struct Component
+ {
+ Component() :
+ begin_(0), end_(0)
+ {}
+
+ bool isPresent() const
+ { return (static_cast<sal_IntPtr>(end_ - begin_) > 0); }
+
+ const sal_Unicode* begin_;
+ const sal_Unicode* end_;
+ };
+
+ //#####################################################
+ struct UNCComponents
+ {
+ Component server_;
+ Component share_;
+ Component resource_;
+ };
+
+ //#####################################################
+ inline bool is_UNC_path(const sal_Unicode* path)
+ { return (0 == wcsncmp(UNC_PREFIX, reinterpret_cast<LPCWSTR>(path), ELEMENTS_OF_ARRAY(UNC_PREFIX) - 1)); }
+
+ //#####################################################
+ inline bool is_UNC_path(const rtl::OUString& path)
+ { return is_UNC_path(path.getStr()); }
+
+ //#####################################################
+ void parse_UNC_path(const sal_Unicode* path, UNCComponents* puncc)
+ {
+ OSL_PRECOND(is_UNC_path(path), "Precondition violated: No UNC path");
+ OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) != -1, "Path must not contain slashes");
+
+ const sal_Unicode* pend = path + rtl_ustr_getLength(path);
+ const sal_Unicode* ppos = path + 2;
+
+ puncc->server_.begin_ = ppos;
+ while ((ppos < pend) && (*ppos != BACKSLASH))
+ ppos++;
+
+ puncc->server_.end_ = ppos;
+
+ if (BACKSLASH == *ppos)
+ {
+ puncc->share_.begin_ = ++ppos;
+ while ((ppos < pend) && (*ppos != BACKSLASH))
+ ppos++;
+
+ puncc->share_.end_ = ppos;
+
+ if (BACKSLASH == *ppos)
+ {
+ puncc->resource_.begin_ = ++ppos;
+ while (ppos < pend)
+ ppos++;
+
+ puncc->resource_.end_ = ppos;
+ }
+ }
+
+ OSL_POSTCOND(puncc->server_.isPresent() && puncc->share_.isPresent(), \
+ "Postcondition violated: Invalid UNC path detected");
+ }
+
+ //#####################################################
+ void parse_UNC_path(const rtl::OUString& path, UNCComponents* puncc)
+ { parse_UNC_path(path.getStr(), puncc); }
+
+
+ //#####################################################
+ bool has_path_parent(const sal_Unicode* path)
+ {
+ // Has the given path a parent or are we already there,
+ // e.g. 'c:\' or '\\server\share\'?
+
+ bool has_parent = false;
+ if (is_UNC_path(path))
+ {
+ UNCComponents unc_comp;
+ parse_UNC_path(path, &unc_comp);
+ has_parent = unc_comp.resource_.isPresent();
+ }
+ else
+ {
+ has_parent = !osl::systemPathIsLogicalDrivePattern(path);
+ }
+ return has_parent;
+ }
+
+ //#####################################################
+ inline bool has_path_parent(const rtl::OUString& path)
+ { return has_path_parent(path.getStr()); }
+
+} // end namespace private
+
+//#####################################################
+// volume handling functions
+//#####################################################
+
+//#####################################################
+oslFileError SAL_CALL osl_unmountVolumeDevice( oslVolumeDeviceHandle Handle )
+{
+ if ( Handle )
+ return osl_File_E_None;
+ else
+ return osl_File_E_INVAL;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_automountVolumeDevice( oslVolumeDeviceHandle Handle )
+{
+ if ( Handle )
+ return osl_File_E_None;
+ else
+ return osl_File_E_INVAL;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
+{
+ if ( Handle )
+ {
+ rtl_uString_acquire( (rtl_uString *)Handle );
+ return osl_File_E_None;
+ }
+ else
+ return osl_File_E_INVAL;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
+{
+ if ( Handle )
+ {
+ rtl_uString_release( (rtl_uString *)Handle );
+ return osl_File_E_None;
+ }
+ else
+ return osl_File_E_INVAL;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle, rtl_uString **pstrPath )
+{
+ if ( Handle && pstrPath )
+ {
+ rtl_uString_assign( pstrPath, (rtl_uString *)Handle );
+ return osl_File_E_None;
+ }
+ else
+ return osl_File_E_INVAL;
+}
+
+//##################################################################
+// directory handling functions
+//##################################################################
+
+#define DIRECTORYITEM_DRIVE 0
+#define DIRECTORYITEM_FILE 1
+#define DIRECTORYITEM_SERVER 2
+
+struct DirectoryItem_Impl
+{
+ UINT uType;
+ union {
+ WIN32_FIND_DATA FindData;
+ TCHAR cDriveString[MAX_PATH];
+ };
+ rtl_uString* m_pFullPath;
+ BOOL bFullPathNormalized;
+ int nRefCount;
+};
+
+//#####################################################
+
+#define DIRECTORYTYPE_LOCALROOT 0
+#define DIRECTORYTYPE_NETROOT 1
+#define DIRECTORYTYPE_NETRESORCE 2
+#define DIRECTORYTYPE_FILESYSTEM 3
+
+struct Directory_Impl
+{
+ UINT uType;
+ union {
+ HANDLE hDirectory;
+ HANDLE hEnumDrives;
+ };
+ rtl_uString* m_pDirectoryPath;
+};
+
+//#####################################################
+
+typedef struct tagDRIVEENUM
+{
+ LPCTSTR lpIdent;
+ TCHAR cBuffer[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256];
+ LPCTSTR lpCurrent;
+} DRIVEENUM, * PDRIVEENUM, FAR * LPDRIVEENUM;
+
+//#####################################################
+
+static HANDLE WINAPI OpenLogicalDrivesEnum(void)
+{
+ LPDRIVEENUM pEnum = (LPDRIVEENUM)HeapAlloc( GetProcessHeap(), 0, sizeof(DRIVEENUM) );
+ if ( pEnum )
+ {
+ DWORD dwNumCopied = GetLogicalDriveStrings( (sizeof(pEnum->cBuffer) - 1) / sizeof(TCHAR), pEnum->cBuffer );
+
+ if ( dwNumCopied && dwNumCopied < sizeof(pEnum->cBuffer) / sizeof(TCHAR) )
+ {
+ pEnum->lpCurrent = pEnum->cBuffer;
+ pEnum->lpIdent = L"tagDRIVEENUM";
+ }
+ else
+ {
+ HeapFree( GetProcessHeap(), 0, pEnum );
+ pEnum = NULL;
+ }
+ }
+ return pEnum ? (HANDLE)pEnum : INVALID_HANDLE_VALUE;
+}
+
+//#####################################################
+static BOOL WINAPI EnumLogicalDrives(HANDLE hEnum, LPTSTR lpBuffer)
+{
+ BOOL fSuccess = FALSE;
+ LPDRIVEENUM pEnum = (LPDRIVEENUM)hEnum;
+
+ if ( pEnum )
+ {
+ int nLen = _tcslen( pEnum->lpCurrent );
+
+ if ( nLen )
+ {
+ CopyMemory( lpBuffer, pEnum->lpCurrent, (nLen + 1) * sizeof(TCHAR) );
+ pEnum->lpCurrent += nLen + 1;
+ fSuccess = TRUE;
+ }
+ else
+ SetLastError( ERROR_NO_MORE_FILES );
+ }
+ else
+ SetLastError( ERROR_INVALID_HANDLE );
+
+ return fSuccess;
+}
+
+//#####################################################
+static BOOL WINAPI CloseLogicalDrivesEnum(HANDLE hEnum)
+{
+ BOOL fSuccess = FALSE;
+ LPDRIVEENUM pEnum = (LPDRIVEENUM)hEnum;
+
+ if ( pEnum )
+ {
+ HeapFree( GetProcessHeap(), 0, pEnum );
+ fSuccess = TRUE;
+ }
+ else
+ SetLastError( ERROR_INVALID_HANDLE );
+
+ return fSuccess;
+}
+
+//#####################################################
+typedef struct tagDIRECTORY
+{
+ HANDLE hFind;
+ WIN32_FIND_DATA aFirstData;
+} DIRECTORY, *PDIRECTORY, FAR *LPDIRECTORY;
+
+//#####################################################
+static HANDLE WINAPI OpenDirectory( rtl_uString* pPath)
+{
+ LPDIRECTORY pDirectory = NULL;
+
+ if ( pPath )
+ {
+ sal_uInt32 nLen = rtl_uString_getLength( pPath );
+ if ( nLen )
+ {
+ TCHAR* pSuffix = 0;
+ sal_uInt32 nSuffLen = 0;
+
+ if ( pPath->buffer[nLen - 1] != L'\\' )
+ {
+ pSuffix = L"\\*.*";
+ nSuffLen = 4;
+ }
+ else
+ {
+ pSuffix = L"*.*";
+ nSuffLen = 3;
+ }
+
+ TCHAR* szFileMask = reinterpret_cast< TCHAR* >( rtl_allocateMemory( sizeof( TCHAR ) * ( nLen + nSuffLen + 1 ) ) );
+
+ _tcscpy( szFileMask, reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pPath ) ) );
+ _tcscat( szFileMask, pSuffix );
+
+ pDirectory = (LPDIRECTORY)HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY));
+ pDirectory->hFind = FindFirstFile(szFileMask, &pDirectory->aFirstData);
+
+ if (!IsValidHandle(pDirectory->hFind))
+ {
+ if ( GetLastError() != ERROR_NO_MORE_FILES )
+ {
+ HeapFree(GetProcessHeap(), 0, pDirectory);
+ pDirectory = NULL;
+ }
+ }
+ }
+ }
+
+ return (HANDLE)pDirectory;
+}
+
+//#####################################################
+BOOL WINAPI EnumDirectory(HANDLE hDirectory, LPWIN32_FIND_DATA pFindData)
+{
+ BOOL fSuccess = FALSE;
+ LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory;
+
+ if ( pDirectory )
+ {
+ BOOL fValid;
+
+ do
+ {
+ if ( pDirectory->aFirstData.cFileName[0] )
+ {
+ *pFindData = pDirectory->aFirstData;
+ fSuccess = TRUE;
+ pDirectory->aFirstData.cFileName[0] = 0;
+ }
+ else if ( IsValidHandle( pDirectory->hFind ) )
+ fSuccess = FindNextFile( pDirectory->hFind, pFindData );
+ else
+ {
+ fSuccess = FALSE;
+ SetLastError( ERROR_NO_MORE_FILES );
+ }
+
+ fValid = fSuccess && _tcscmp( TEXT("."), pFindData->cFileName ) != 0 && _tcscmp( TEXT(".."), pFindData->cFileName ) != 0;
+
+ } while( fSuccess && !fValid );
+ }
+ else
+ SetLastError( ERROR_INVALID_HANDLE );
+
+ return fSuccess;
+}
+
+//#####################################################
+static BOOL WINAPI CloseDirectory(HANDLE hDirectory)
+{
+ BOOL fSuccess = FALSE;
+ LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory;
+
+ if (pDirectory)
+ {
+ if (IsValidHandle(pDirectory->hFind))
+ fSuccess = FindClose(pDirectory->hFind);
+
+ fSuccess = HeapFree(GetProcessHeap(), 0, pDirectory) && fSuccess;
+ }
+ else
+ SetLastError(ERROR_INVALID_HANDLE);
+
+ return fSuccess;
+}
+
+//#####################################################
+static oslFileError osl_openLocalRoot(
+ rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
+{
+ rtl_uString *strSysPath = NULL;
+ oslFileError error;
+
+ if ( !pDirectory )
+ return osl_File_E_INVAL;
+
+ *pDirectory = NULL;
+
+ error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysPath, sal_False );
+ if ( osl_File_E_None == error )
+ {
+ Directory_Impl *pDirImpl;
+
+ pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory( sizeof(Directory_Impl)));
+ ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
+ rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strSysPath );
+
+ /* Append backslash if neccessary */
+
+ /* @@@ToDo
+ use function ensure backslash
+ */
+ sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
+ if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
+ {
+ rtl_uString* pCurDir = 0;
+ rtl_uString* pBackSlash = 0;
+
+ rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
+ rtl_uString_newFromAscii( &pBackSlash, "\\" );
+ rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
+ rtl_uString_release( pBackSlash );
+ rtl_uString_release( pCurDir );
+ }
+
+ pDirImpl->uType = DIRECTORYTYPE_LOCALROOT;
+ pDirImpl->hEnumDrives = OpenLogicalDrivesEnum();
+
+ /* @@@ToDo
+ Use IsValidHandle(...)
+ */
+ if ( pDirImpl->hEnumDrives != INVALID_HANDLE_VALUE )
+ {
+ *pDirectory = (oslDirectory)pDirImpl;
+ error = osl_File_E_None;
+ }
+ else
+ {
+ if ( pDirImpl )
+ {
+ if ( pDirImpl->m_pDirectoryPath )
+ {
+ rtl_uString_release( pDirImpl->m_pDirectoryPath );
+ pDirImpl->m_pDirectoryPath = 0;
+ }
+
+ rtl_freeMemory(pDirImpl);
+ pDirImpl = 0;
+ }
+
+ error = oslTranslateFileError( GetLastError() );
+ }
+
+ rtl_uString_release( strSysPath );
+ }
+ return error;
+}
+
+//#####################################################
+static oslFileError SAL_CALL osl_openFileDirectory(
+ rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
+{
+ oslFileError error = osl_File_E_None;
+
+ if ( !pDirectory )
+ return osl_File_E_INVAL;
+ *pDirectory = NULL;
+
+ Directory_Impl *pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl)));
+ ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
+ rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strDirectoryPath );
+
+ /* Append backslash if neccessary */
+
+ /* @@@ToDo
+ use function ensure backslash
+ */
+ sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
+ if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
+ {
+ rtl_uString* pCurDir = 0;
+ rtl_uString* pBackSlash = 0;
+
+ rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
+ rtl_uString_newFromAscii( &pBackSlash, "\\" );
+ rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
+ rtl_uString_release( pBackSlash );
+ rtl_uString_release( pCurDir );
+ }
+
+
+ pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM;
+ pDirImpl->hDirectory = OpenDirectory( pDirImpl->m_pDirectoryPath );
+
+ if ( !pDirImpl->hDirectory )
+ {
+ error = oslTranslateFileError( GetLastError() );
+
+ if ( pDirImpl->m_pDirectoryPath )
+ {
+ rtl_uString_release( pDirImpl->m_pDirectoryPath );
+ pDirImpl->m_pDirectoryPath = 0;
+ }
+
+ rtl_freeMemory(pDirImpl), pDirImpl = 0;
+ }
+
+ *pDirectory = (oslDirectory)(pDirImpl);
+ return error;
+}
+
+//#####################################################
+static oslFileError SAL_CALL osl_openNetworkServer(
+ rtl_uString *strSysDirPath, oslDirectory *pDirectory)
+{
+ NETRESOURCEW aNetResource;
+ HANDLE hEnum;
+ DWORD dwError;
+
+ ZeroMemory( &aNetResource, sizeof(aNetResource) );
+
+ aNetResource.lpRemoteName = reinterpret_cast<LPWSTR>(strSysDirPath->buffer);
+
+ dwError = WNetOpenEnumW(
+ RESOURCE_GLOBALNET,
+ RESOURCETYPE_DISK,
+ RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER,
+ &aNetResource,
+ &hEnum );
+
+ if ( ERROR_SUCCESS == dwError )
+ {
+ Directory_Impl *pDirImpl;
+
+ pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl)));
+ ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
+ pDirImpl->uType = DIRECTORYTYPE_NETROOT;
+ pDirImpl->hDirectory = hEnum;
+ *pDirectory = (oslDirectory)pDirImpl;
+ }
+ return oslTranslateFileError( dwError );
+}
+
+//#############################################
+static DWORD create_dir_with_callback(
+ rtl_uString * dir_path,
+ oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
+ void* pData)
+{
+ // Create the specified directory and call the
+ // user specified callback function. On success
+ // the function returns ERROR_SUCCESS else a Win32 error code.
+
+ BOOL bCreated = FALSE;
+
+ bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( dir_path )), NULL );
+
+ if ( bCreated )
+ {
+ if (aDirectoryCreationCallbackFunc)
+ {
+ rtl::OUString url;
+ _osl_getFileURLFromSystemPath(dir_path, &(url.pData));
+ aDirectoryCreationCallbackFunc(pData, url.pData);
+ }
+ return ERROR_SUCCESS;
+ }
+ return GetLastError();
+}
+
+//#############################################
+static int path_make_parent(sal_Unicode* path)
+{
+ /* Cut off the last part of the given path to
+ get the parent only, e.g. 'c:\dir\subdir' ->
+ 'c:\dir' or '\\share\sub\dir' -> '\\share\sub'
+ @return The position where the path has been cut
+ off (this is the posistion of the last backslash).
+ If there are no more parents 0 will be returned,
+ e.g. 'c:\' or '\\Share' have no more parents */
+
+ OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) != -1, "Path must not contain slashes");
+ OSL_PRECOND(has_path_parent(path), "Path must have a parent");
+
+ sal_Unicode* pos_last_backslash = path + rtl_ustr_lastIndexOfChar(path, BACKSLASH);
+ *pos_last_backslash = 0;
+ return (pos_last_backslash - path);
+}
+
+//#############################################
+static DWORD create_dir_recursively_(
+ rtl_uString * dir_path,
+ oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
+ void* pData)
+{
+ OSL_PRECOND(
+ rtl_ustr_lastIndexOfChar_WithLength(dir_path->buffer, dir_path->length, BACKSLASH) != dir_path->length,
+ "Path must not end with a backslash");
+
+ DWORD w32_error = create_dir_with_callback(
+ dir_path, aDirectoryCreationCallbackFunc, pData);
+ if (w32_error == ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ if ((w32_error != ERROR_PATH_NOT_FOUND) || !has_path_parent(dir_path->buffer))
+ return w32_error;
+
+ int pos = path_make_parent(dir_path->buffer); // dir_path->buffer[pos] = 0, restore below
+
+ w32_error = create_dir_recursively_(
+ dir_path, aDirectoryCreationCallbackFunc, pData);
+
+ dir_path->buffer[pos] = BACKSLASH; // restore
+
+ if (ERROR_SUCCESS != w32_error)
+ return w32_error;
+
+ return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
+}
+
+//#############################################
+oslFileError SAL_CALL osl_createDirectoryPath(
+ rtl_uString* aDirectoryUrl,
+ oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
+ void* pData)
+{
+ if (aDirectoryUrl == NULL)
+ return osl_File_E_INVAL;
+
+ rtl::OUString sys_path;
+ oslFileError osl_error =
+ _osl_getSystemPathFromFileURL(aDirectoryUrl, &sys_path.pData, sal_False);
+
+ if (osl_error != osl_File_E_None)
+ return osl_error;
+
+ osl::systemPathRemoveSeparator(sys_path);
+
+ // const_cast because sys_path is a local copy
+ // which we want to modify inplace instead of
+ // coyp it into another buffer on the heap again
+ return oslTranslateFileError(create_dir_recursively_(
+ sys_path.pData, aDirectoryCreationCallbackFunc, pData));
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_createDirectory(rtl_uString* strPath)
+{
+ rtl_uString *strSysPath = NULL;
+ oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
+
+ if ( osl_File_E_None == error )
+ {
+ BOOL bCreated = FALSE;
+
+ bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strSysPath )), NULL );
+
+ if ( !bCreated )
+ {
+ /*@@@ToDo
+ The following case is a hack because the ucb or the webtop had some
+ problems with the error code that CreateDirectory returns in
+ case the path is only a logical drive, should be removed!
+ */
+
+ const sal_Unicode *pBuffer = rtl_uString_getStr( strSysPath );
+ sal_Int32 nLen = rtl_uString_getLength( strSysPath );
+
+ if (
+ ( ( pBuffer[0] >= 'A' && pBuffer[0] <= 'Z' ) ||
+ ( pBuffer[0] >= 'a' && pBuffer[0] <= 'z' ) ) &&
+ pBuffer[1] == ':' && ( nLen ==2 || ( nLen == 3 && pBuffer[2] == '\\' ) )
+ )
+ SetLastError( ERROR_ALREADY_EXISTS );
+
+ error = oslTranslateFileError( GetLastError() );
+ }
+
+ rtl_uString_release( strSysPath );
+ }
+ return error;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_removeDirectory(rtl_uString* strPath)
+{
+ rtl_uString *strSysPath = NULL;
+ oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
+
+ if ( osl_File_E_None == error )
+ {
+ if ( RemoveDirectory( reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )) ) )
+ error = osl_File_E_None;
+ else
+ error = oslTranslateFileError( GetLastError() );
+
+ rtl_uString_release( strSysPath );
+ }
+ return error;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_openDirectory(rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
+{
+ oslFileError error;
+
+ if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath->buffer, "file:///" ) )
+ error = osl_openLocalRoot( strDirectoryPath, pDirectory );
+ else
+ {
+ rtl_uString *strSysDirectoryPath = NULL;
+ DWORD dwPathType;
+
+ error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysDirectoryPath, sal_False );
+
+ if ( osl_File_E_None != error )
+ return error;
+
+ dwPathType = IsValidFilePath( strSysDirectoryPath, NULL, VALIDATEPATH_NORMAL, NULL );
+
+ if ( dwPathType & PATHTYPE_IS_SERVER )
+ {
+ error = osl_openNetworkServer( strSysDirectoryPath, pDirectory );
+ }
+ else
+ error = osl_openFileDirectory( strSysDirectoryPath, pDirectory );
+
+ rtl_uString_release( strSysDirectoryPath );
+ }
+ return error;
+}
+
+//#####################################################
+static oslFileError SAL_CALL osl_getNextNetResource(
+ oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint )
+{
+ Directory_Impl *pDirImpl = (Directory_Impl *)Directory;
+ DirectoryItem_Impl *pItemImpl = NULL;
+ BYTE buffer[16384];
+ LPNETRESOURCEW lpNetResource = (LPNETRESOURCEW)buffer;
+ DWORD dwError, dwCount, dwBufSize;
+
+ uHint = uHint; /* to get no warning */
+
+ if ( !pItem )
+ return osl_File_E_INVAL;
+ *pItem = NULL;
+
+ if ( !pDirImpl )
+ return osl_File_E_INVAL;
+
+ dwCount = 1;
+ dwBufSize = sizeof(buffer);
+ dwError = WNetEnumResource( pDirImpl->hDirectory, &dwCount, lpNetResource, &dwBufSize );
+
+ switch ( dwError )
+ {
+ case NO_ERROR:
+ case ERROR_MORE_DATA:
+ {
+ pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
+ if ( !pItemImpl )
+ return osl_File_E_NOMEM;
+
+ ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
+ pItemImpl->uType = DIRECTORYITEM_DRIVE;
+ osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
+
+ wcscpy( pItemImpl->cDriveString, lpNetResource->lpRemoteName );
+
+ *pItem = pItemImpl;
+ }
+ return osl_File_E_None;
+ case ERROR_NO_MORE_ITEMS:
+ return osl_File_E_NOENT;
+ default:
+ return oslTranslateFileError( dwError );
+ }
+}
+
+//#####################################################
+static oslFileError SAL_CALL osl_getNextDrive(
+ oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint )
+{
+ Directory_Impl *pDirImpl = (Directory_Impl *)Directory;
+ DirectoryItem_Impl *pItemImpl = NULL;
+ BOOL fSuccess;
+
+ uHint = uHint; /* avoid warnings */
+
+ if ( !pItem )
+ return osl_File_E_INVAL;
+ *pItem = NULL;
+
+ if ( !pDirImpl )
+ return osl_File_E_INVAL;
+
+ pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
+ if ( !pItemImpl )
+ return osl_File_E_NOMEM;
+
+ ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
+ pItemImpl->uType = DIRECTORYITEM_DRIVE;
+ osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
+ fSuccess = EnumLogicalDrives( pDirImpl->hEnumDrives, pItemImpl->cDriveString );
+
+ if ( fSuccess )
+ {
+ *pItem = pItemImpl;
+ return osl_File_E_None;
+ }
+ else
+ {
+ if ( pItemImpl->m_pFullPath )
+ {
+ rtl_uString_release( pItemImpl->m_pFullPath );
+ pItemImpl->m_pFullPath = 0;
+ }
+
+ rtl_freeMemory( pItemImpl );
+ return oslTranslateFileError( GetLastError() );
+ }
+}
+
+//#####################################################
+static oslFileError SAL_CALL osl_getNextFileItem(
+ oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint)
+{
+ Directory_Impl *pDirImpl = (Directory_Impl *)Directory;
+ DirectoryItem_Impl *pItemImpl = NULL;
+ BOOL fFound;
+
+ uHint = uHint; /* avoid warnings */
+
+ if ( !pItem )
+ return osl_File_E_INVAL;
+ *pItem = NULL;
+
+ if ( !pDirImpl )
+ return osl_File_E_INVAL;
+
+ pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
+ if ( !pItemImpl )
+ return osl_File_E_NOMEM;
+
+ memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
+ fFound = EnumDirectory( pDirImpl->hDirectory, &pItemImpl->FindData );
+
+ if ( fFound )
+ {
+ pItemImpl->uType = DIRECTORYITEM_FILE;
+ pItemImpl->nRefCount = 1;
+
+ rtl_uString* pTmpFileName = 0;
+ rtl_uString_newFromStr( &pTmpFileName, reinterpret_cast<const sal_Unicode *>(pItemImpl->FindData.cFileName) );
+ rtl_uString_newConcat( &pItemImpl->m_pFullPath, pDirImpl->m_pDirectoryPath, pTmpFileName );
+ rtl_uString_release( pTmpFileName );
+
+ pItemImpl->bFullPathNormalized = FALSE;
+ *pItem = (oslDirectoryItem)pItemImpl;
+ return osl_File_E_None;
+ }
+ else
+ {
+ if ( pItemImpl->m_pFullPath )
+ {
+ rtl_uString_release( pItemImpl->m_pFullPath );
+ pItemImpl->m_pFullPath = 0;
+ }
+
+ rtl_freeMemory( pItemImpl );
+ return oslTranslateFileError( GetLastError() );
+ }
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_getNextDirectoryItem(
+ oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint)
+{
+ Directory_Impl *pDirImpl = (Directory_Impl *)Directory;
+
+ /* Assume failure */
+
+ if ( !pItem )
+ return osl_File_E_INVAL;
+ *pItem = NULL;
+
+ if ( !pDirImpl )
+ return osl_File_E_INVAL;
+
+ switch ( pDirImpl->uType )
+ {
+ case DIRECTORYTYPE_LOCALROOT:
+ return osl_getNextDrive( Directory, pItem, uHint );
+ case DIRECTORYTYPE_NETROOT:
+ return osl_getNextNetResource( Directory, pItem, uHint );
+ case DIRECTORYTYPE_FILESYSTEM:
+ return osl_getNextFileItem( Directory, pItem, uHint );
+ default:
+ return osl_File_E_INVAL;
+ }
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_closeDirectory(oslDirectory Directory)
+{
+ Directory_Impl *pDirImpl = (Directory_Impl *)Directory;
+ oslFileError eError = osl_File_E_INVAL;
+
+ if ( pDirImpl )
+ {
+ switch ( pDirImpl->uType )
+ {
+ case DIRECTORYTYPE_FILESYSTEM:
+ eError = CloseDirectory( pDirImpl->hDirectory ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
+ break;
+ case DIRECTORYTYPE_LOCALROOT:
+ eError = CloseLogicalDrivesEnum( pDirImpl->hEnumDrives ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
+ break;
+ case DIRECTORYTYPE_NETROOT:
+ {
+ DWORD err = WNetCloseEnum(pDirImpl->hDirectory);
+ eError = (err == NO_ERROR) ? osl_File_E_None : oslTranslateFileError(err);
+ }
+ break;
+ default:
+ OSL_ENSURE( 0, "Invalid directory type" );
+ break;
+ }
+
+ if ( pDirImpl->m_pDirectoryPath )
+ {
+ rtl_uString_release( pDirImpl->m_pDirectoryPath );
+ pDirImpl->m_pDirectoryPath = 0;
+ }
+
+ rtl_freeMemory(pDirImpl);
+ }
+ return eError;
+}
+
+//#####################################################
+/* Different types of paths */
+typedef enum _PATHTYPE
+{
+ PATHTYPE_SYNTAXERROR = 0,
+ PATHTYPE_NETROOT,
+ PATHTYPE_NETSERVER,
+ PATHTYPE_VOLUME,
+ PATHTYPE_FILE
+} PATHTYPE;
+
+oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString *strFilePath, oslDirectoryItem *pItem)
+{
+ oslFileError error = osl_File_E_None;
+ rtl_uString* strSysFilePath = NULL;
+ PATHTYPE type = PATHTYPE_FILE;
+ DWORD dwPathType;
+
+ /* Assume failure */
+
+ if ( !pItem )
+ return osl_File_E_INVAL;
+
+ *pItem = NULL;
+
+
+ error = _osl_getSystemPathFromFileURL( strFilePath, &strSysFilePath, sal_False );
+
+ if ( osl_File_E_None != error )
+ return error;
+
+ dwPathType = IsValidFilePath( strSysFilePath, NULL, VALIDATEPATH_NORMAL, NULL );
+
+ if ( dwPathType & PATHTYPE_IS_VOLUME )
+ type = PATHTYPE_VOLUME;
+ else if ( dwPathType & PATHTYPE_IS_SERVER )
+ type = PATHTYPE_NETSERVER;
+ else
+ type = PATHTYPE_FILE;
+
+ switch ( type )
+ {
+ case PATHTYPE_NETSERVER:
+ {
+ DirectoryItem_Impl* pItemImpl =
+ reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
+
+ if ( !pItemImpl )
+ error = osl_File_E_NOMEM;
+
+ if ( osl_File_E_None == error )
+ {
+ ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
+ pItemImpl->uType = DIRECTORYITEM_SERVER;
+
+ osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
+ rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath );
+
+ // Assign a title anyway
+ {
+ int iSrc = 2;
+ int iDst = 0;
+
+ while( iSrc < strSysFilePath->length && strSysFilePath->buffer[iSrc] && strSysFilePath->buffer[iSrc] != '\\' )
+ {
+ pItemImpl->FindData.cFileName[iDst++] = strSysFilePath->buffer[iSrc++];
+ }
+ }
+
+ *pItem = pItemImpl;
+ }
+ }
+ break;
+ case PATHTYPE_VOLUME:
+ {
+ DirectoryItem_Impl* pItemImpl =
+ reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
+
+ if ( !pItemImpl )
+ error = osl_File_E_NOMEM;
+
+ if ( osl_File_E_None == error )
+ {
+ ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
+ pItemImpl->uType = DIRECTORYITEM_DRIVE;
+
+ osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
+
+ _tcscpy( pItemImpl->cDriveString, reinterpret_cast<LPCTSTR>(strSysFilePath->buffer) );
+ pItemImpl->cDriveString[0] = _toupper( pItemImpl->cDriveString[0] );
+
+ if ( pItemImpl->cDriveString[_tcslen(pItemImpl->cDriveString) - 1] != '\\' )
+ _tcscat( pItemImpl->cDriveString, TEXT( "\\" ) );
+
+ *pItem = pItemImpl;
+ }
+ }
+ break;
+ case PATHTYPE_SYNTAXERROR:
+ case PATHTYPE_NETROOT:
+ case PATHTYPE_FILE:
+ {
+ HANDLE hFind;
+ WIN32_FIND_DATA aFindData;
+
+ if ( strSysFilePath->length > 0 && strSysFilePath->buffer[strSysFilePath->length - 1] == '\\' )
+ rtl_uString_newFromStr_WithLength( &strSysFilePath, strSysFilePath->buffer, strSysFilePath->length - 1 );
+
+ hFind = FindFirstFile( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(strSysFilePath)), &aFindData );
+
+ if ( hFind != INVALID_HANDLE_VALUE )
+ {
+ DirectoryItem_Impl *pItemImpl =
+ reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
+
+ ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
+ osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
+
+ CopyMemory( &pItemImpl->FindData, &aFindData, sizeof(WIN32_FIND_DATA) );
+ rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath );
+
+ // MT: This costs 600ms startup time on fast v60x!
+ // GetCaseCorrectPathName( pItemImpl->szFullPath, pItemImpl->szFullPath, sizeof(pItemImpl->szFullPath) );
+
+ pItemImpl->uType = DIRECTORYITEM_FILE;
+ *pItem = pItemImpl;
+ FindClose( hFind );
+ }
+ else
+ error = oslTranslateFileError( GetLastError() );
+ }
+ break;
+ }
+
+ if ( strSysFilePath )
+ rtl_uString_release( strSysFilePath );
+
+ return error;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item )
+{
+ DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item;
+
+ if ( !pItemImpl )
+ return osl_File_E_INVAL;
+
+ pItemImpl->nRefCount++;
+ return osl_File_E_None;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
+{
+ DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item;
+
+ if ( !pItemImpl )
+ return osl_File_E_INVAL;
+
+ if ( ! --pItemImpl->nRefCount )
+ {
+ if ( pItemImpl->m_pFullPath )
+ {
+ rtl_uString_release( pItemImpl->m_pFullPath );
+ pItemImpl->m_pFullPath = 0;
+ }
+
+ rtl_freeMemory( pItemImpl );
+ }
+
+ return osl_File_E_None;
+}
+
+//#####################################################
+// volume / file info handling functions
+//#####################################################
+
+//#####################################################
+static inline bool is_floppy_A_present()
+{ return (GetLogicalDrives() & 1); }
+
+//#####################################################
+static inline bool is_floppy_B_present()
+{ return (GetLogicalDrives() & 2); }
+
+//#####################################################
+bool is_floppy_volume_mount_point(const rtl::OUString& path)
+{
+ // determines if a volume mount point shows to a floppy
+ // disk by comparing the unique volume names
+ static const LPCWSTR FLOPPY_A = L"A:\\";
+ static const LPCWSTR FLOPPY_B = L"B:\\";
+
+ rtl::OUString p(path);
+ osl::systemPathEnsureSeparator(p);
+
+ TCHAR vn[51];
+ if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn)))
+ {
+ TCHAR vnfloppy[51];
+ if (is_floppy_A_present() &&
+ GetVolumeNameForVolumeMountPoint(FLOPPY_A, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) &&
+ (0 == wcscmp(vn, vnfloppy)))
+ return true;
+
+ if (is_floppy_B_present() &&
+ GetVolumeNameForVolumeMountPoint(FLOPPY_B, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) &&
+ (0 == wcscmp(vn, vnfloppy)))
+ return true;
+ }
+ return false;
+}
+
+//################################################
+static bool is_floppy_drive(const rtl::OUString& path)
+{
+ static const LPCWSTR FLOPPY_DRV_LETTERS = TEXT("AaBb");
+
+ // we must take into account that even a floppy
+ // drive may be mounted to a directory so checking
+ // for the drive letter alone is not sufficient
+ // we must compare the unique volume name with
+ // that of the available floppy disks
+
+ const sal_Unicode* pszPath = path.getStr();
+ return ((wcschr(FLOPPY_DRV_LETTERS, pszPath[0]) && (L':' == pszPath[1])) || is_floppy_volume_mount_point(path));
+}
+
+//#####################################################
+static bool is_volume_mount_point(const rtl::OUString& path)
+{
+ rtl::OUString p(path);
+ osl::systemPathRemoveSeparator(p);
+
+ bool is_volume_root = false;
+
+ if (!is_floppy_drive(p))
+ {
+ DWORD fattr = GetFileAttributes(reinterpret_cast<LPCTSTR>(p.getStr()));
+
+ if ((INVALID_FILE_ATTRIBUTES != fattr) &&
+ (FILE_ATTRIBUTE_REPARSE_POINT & fattr))
+ {
+ WIN32_FIND_DATA find_data;
+ HANDLE h_find = FindFirstFile(reinterpret_cast<LPCTSTR>(p.getStr()), &find_data);
+
+ if (IsValidHandle(h_find) &&
+ (FILE_ATTRIBUTE_REPARSE_POINT & find_data.dwFileAttributes) &&
+ (IO_REPARSE_TAG_MOUNT_POINT == find_data.dwReserved0))
+ {
+ is_volume_root = true;
+ }
+ if (IsValidHandle(h_find))
+ FindClose(h_find);
+ }
+ }
+ return is_volume_root;
+}
+
+//#############################################
+static UINT get_volume_mount_point_drive_type(const rtl::OUString& path)
+{
+ if (0 == path.getLength())
+ return GetDriveType(NULL);
+
+ rtl::OUString p(path);
+ osl::systemPathEnsureSeparator(p);
+
+ TCHAR vn[51];
+ if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn)))
+ return GetDriveType(vn);
+
+ return DRIVE_NO_ROOT_DIR;
+}
+
+//#############################################
+static inline bool is_drivetype_request(sal_uInt32 field_mask)
+{
+ return (field_mask & osl_VolumeInfo_Mask_Attributes);
+}
+
+//#############################################
+static oslFileError osl_get_drive_type(
+ const rtl::OUString& path, oslVolumeInfo* pInfo)
+{
+ // GetDriveType fails on empty volume mount points
+ // see Knowledge Base Q244089
+ UINT drive_type;
+ if (is_volume_mount_point(path))
+ drive_type = get_volume_mount_point_drive_type(path);
+ else
+ drive_type = GetDriveType(reinterpret_cast<LPCTSTR>(path.getStr()));
+
+ if (DRIVE_NO_ROOT_DIR == drive_type)
+ return oslTranslateFileError(ERROR_INVALID_DRIVE);
+
+ pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
+
+ switch (drive_type)
+ {
+ case DRIVE_CDROM:
+ pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable;
+ break;
+ case DRIVE_REMOVABLE:
+ pInfo->uAttributes |= osl_Volume_Attribute_Removeable;
+ if (is_floppy_drive(path))
+ pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk;
+ break;
+ case DRIVE_FIXED:
+ pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk;
+ break;
+ case DRIVE_RAMDISK:
+ pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk;
+ break;
+ case DRIVE_REMOTE:
+ pInfo->uAttributes |= osl_Volume_Attribute_Remote;
+ break;
+ case DRIVE_UNKNOWN:
+ pInfo->uAttributes = 0;
+ break;
+ default:
+ pInfo->uValidFields &= ~osl_VolumeInfo_Mask_Attributes;
+ pInfo->uAttributes = 0;
+ break;
+ }
+ return osl_File_E_None;
+}
+
+//#############################################
+static inline bool is_volume_space_info_request(sal_uInt32 field_mask)
+{
+ return (field_mask &
+ (osl_VolumeInfo_Mask_TotalSpace |
+ osl_VolumeInfo_Mask_UsedSpace |
+ osl_VolumeInfo_Mask_FreeSpace));
+}
+
+//#############################################
+static void get_volume_space_information(
+ const rtl::OUString& path, oslVolumeInfo *pInfo)
+{
+ BOOL ret = GetDiskFreeSpaceEx(
+ reinterpret_cast<LPCTSTR>(path.getStr()),
+ (PULARGE_INTEGER)&(pInfo->uFreeSpace),
+ (PULARGE_INTEGER)&(pInfo->uTotalSpace),
+ NULL);
+
+ if (ret)
+ {
+ pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace;
+ pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace |
+ osl_VolumeInfo_Mask_UsedSpace |
+ osl_VolumeInfo_Mask_FreeSpace;
+ }
+}
+
+//#############################################
+static inline bool is_filesystem_attributes_request(sal_uInt32 field_mask)
+{
+ return (field_mask &
+ (osl_VolumeInfo_Mask_MaxNameLength |
+ osl_VolumeInfo_Mask_MaxPathLength |
+ osl_VolumeInfo_Mask_FileSystemName |
+ osl_VolumeInfo_Mask_FileSystemCaseHandling));
+}
+
+//#############################################
+static oslFileError get_filesystem_attributes(
+ const rtl::OUString& path, sal_uInt32 field_mask, oslVolumeInfo* pInfo)
+{
+ pInfo->uAttributes = 0;
+
+ // osl_get_drive_type must be called first because
+ // this function resets osl_VolumeInfo_Mask_Attributes
+ // on failure
+ if (is_drivetype_request(field_mask))
+ {
+ oslFileError osl_error = osl_get_drive_type(path, pInfo);
+ if (osl_File_E_None != osl_error)
+ return osl_error;
+ }
+ if (is_filesystem_attributes_request(field_mask))
+ {
+ /* the following two parameters can not be longer than MAX_PATH+1 */
+ WCHAR vn[MAX_PATH+1];
+ WCHAR fsn[MAX_PATH+1];
+
+ DWORD serial;
+ DWORD mcl;
+ DWORD flags;
+
+ LPCTSTR pszPath = reinterpret_cast<LPCTSTR>(path.getStr());
+ if (GetVolumeInformation(pszPath, vn, MAX_PATH+1, &serial, &mcl, &flags, fsn, MAX_PATH+1))
+ {
+ // Currently sal does not use this value, instead MAX_PATH is used
+ pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength;
+ pInfo->uMaxNameLength = mcl;
+
+ // Should the uMaxPathLength be set to 32767, "\\?\" prefix allowes it
+ pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength;
+ pInfo->uMaxPathLength = MAX_PATH;
+
+ pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName;
+ rtl_uString_newFromStr(&pInfo->ustrFileSystemName, reinterpret_cast<const sal_Unicode*>(fsn));
+
+ // volumes (even NTFS) will always be considered case
+ // insensitive because the Win32 API is not able to
+ // deal with case sensitive volumes see M$ Knowledge Base
+ // article 100625 that's why we never set the attribute
+ // osl_Volume_Attribute_Case_Sensitive
+
+ if (flags & FS_CASE_IS_PRESERVED)
+ pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved;
+
+ pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
+ }
+ }
+ return osl_File_E_None;
+}
+
+//#####################################################
+static bool path_get_parent(rtl::OUString& path)
+{
+ OSL_PRECOND(path.lastIndexOf(SLASH) == -1, "Path must not have slashes");
+
+ if (!has_path_parent(path))
+ {
+ sal_Int32 i = path.lastIndexOf(BACKSLASH);
+ if (-1 < i)
+ {
+ path = rtl::OUString(path.getStr(), i);
+ return true;
+ }
+ }
+ return false;
+}
+
+//#####################################################
+static void path_travel_to_volume_root(const rtl::OUString& system_path, rtl::OUString& volume_root)
+{
+ rtl::OUString sys_path(system_path);
+
+ while(!is_volume_mount_point(sys_path) && path_get_parent(sys_path))
+ /**/;
+
+ volume_root = sys_path;
+ osl::systemPathEnsureSeparator(volume_root);
+}
+
+//#############################################
+oslFileError SAL_CALL osl_getVolumeInformation(
+ rtl_uString *ustrURL, oslVolumeInfo *pInfo, sal_uInt32 uFieldMask )
+{
+ if (!pInfo)
+ return osl_File_E_INVAL;
+
+ rtl::OUString system_path;
+ oslFileError error = _osl_getSystemPathFromFileURL(ustrURL, &system_path.pData, sal_False);
+
+ if (osl_File_E_None != error)
+ return error;
+
+ rtl::OUString volume_root;
+ path_travel_to_volume_root(system_path, volume_root);
+
+ pInfo->uValidFields = 0;
+
+ if ((error = get_filesystem_attributes(volume_root, uFieldMask, pInfo)) != osl_File_E_None)
+ return error;
+
+ if (is_volume_space_info_request(uFieldMask))
+ get_volume_space_information(volume_root, pInfo);
+
+ if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle)
+ {
+ pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle;
+ osl_getFileURLFromSystemPath(volume_root.pData, (rtl_uString**)&pInfo->pDeviceHandle);
+ }
+
+ return osl_File_E_None;
+}
+
+//#####################################################
+static oslFileError SAL_CALL osl_getDriveInfo(
+ oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask)
+{
+ DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item;
+ TCHAR cDrive[3] = TEXT("A:");
+ TCHAR cRoot[4] = TEXT("A:\\");
+
+ if ( !pItemImpl )
+ return osl_File_E_INVAL;
+
+ pStatus->uValidFields = 0;
+
+ cDrive[0] = pItemImpl->cDriveString[0];
+ cRoot[0] = pItemImpl->cDriveString[0];
+
+ if ( uFieldMask & osl_FileStatus_Mask_FileName )
+ {
+ if ( pItemImpl->cDriveString[0] == '\\' && pItemImpl->cDriveString[1] == '\\' )
+ {
+ LPCWSTR lpFirstBkSlash = wcschr( &pItemImpl->cDriveString[2], '\\' );
+
+ if ( lpFirstBkSlash && lpFirstBkSlash[1] )
+ {
+ LPCWSTR lpLastBkSlash = wcschr( &lpFirstBkSlash[1], '\\' );
+
+ if ( lpLastBkSlash )
+ rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]), lpLastBkSlash - lpFirstBkSlash - 1 );
+ else
+ rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]) );
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
+ }
+ }
+ else switch ( GetDriveType( cRoot ) )
+ {
+ case DRIVE_REMOTE:
+ {
+ TCHAR szBuffer[1024];
+ DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szBuffer);
+ DWORD dwBufsize = dwBufsizeConst;
+
+ DWORD dwResult = WNetGetConnection( cDrive, szBuffer, &dwBufsize );
+ if ( NO_ERROR == dwResult )
+ {
+ TCHAR szFileName[dwBufsizeConst + 16];
+
+ swprintf( szFileName, L"%s [%s]", cDrive, szBuffer );
+ rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) );
+ }
+ else
+ rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) );
+ }
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
+ break;
+ case DRIVE_FIXED:
+ {
+ TCHAR szVolumeNameBuffer[1024];
+ DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szVolumeNameBuffer);
+
+ if ( GetVolumeInformation( cRoot, szVolumeNameBuffer, dwBufsizeConst, NULL, NULL, NULL, NULL, 0 ) )
+ {
+ TCHAR szFileName[dwBufsizeConst + 16];
+
+ swprintf( szFileName, L"%s [%s]", cDrive, szVolumeNameBuffer );
+ rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) );
+ }
+ else
+ rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) );
+ }
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
+ break;
+ case DRIVE_CDROM:
+ case DRIVE_REMOVABLE:
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
+ rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cRoot) );
+ break;
+ case DRIVE_UNKNOWN:
+ default:
+ break;
+ }
+ }
+
+ pStatus->eType = osl_File_Type_Volume;
+ pStatus->uValidFields |= osl_FileStatus_Mask_Type;
+
+ if ( uFieldMask & osl_FileStatus_Mask_FileURL )
+ {
+ rtl_uString *ustrSystemPath = NULL;
+
+ rtl_uString_newFromStr( &ustrSystemPath, reinterpret_cast<const sal_Unicode*>(pItemImpl->cDriveString) );
+ osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL );
+ rtl_uString_release( ustrSystemPath );
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
+ }
+ return osl_File_E_None;
+}
+
+//#####################################################
+static oslFileError SAL_CALL osl_getServerInfo(
+ oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask )
+{
+ DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item;
+ if ( !pItemImpl )
+ return osl_File_E_INVAL;
+
+ pStatus->uValidFields = 0;
+
+ // pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
+
+ // if ( _tcscmp( pItemImpl->FindData.cFileName, TEXT(".") ) == 0 )
+ // rtl_uString_newFromAscii( &pStatus->ustrFileName, "/" );
+ // else
+ // rtl_uString_newFromStr( &pStatus->ustrFileName, pItemImpl->FindData.cFileName );
+
+ pStatus->eType = osl_File_Type_Directory;
+ pStatus->uValidFields |= osl_FileStatus_Mask_Type;
+
+ if ( uFieldMask & osl_FileStatus_Mask_FileURL )
+ {
+ osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL );
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
+ }
+ return osl_File_E_None;
+}
+
+//#############################################
+oslFileError SAL_CALL osl_getFileStatus(
+ oslDirectoryItem Item,
+ oslFileStatus *pStatus,
+ sal_uInt32 uFieldMask )
+{
+ DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item;
+
+ if ( !pItemImpl )
+ return osl_File_E_INVAL;
+
+ switch ( pItemImpl->uType )
+ {
+ case DIRECTORYITEM_DRIVE:
+ return osl_getDriveInfo( Item, pStatus, uFieldMask );
+ case DIRECTORYITEM_SERVER:
+ return osl_getServerInfo( Item, pStatus, uFieldMask );
+ default:
+ break;
+ }
+
+ if ( uFieldMask & osl_FileStatus_Mask_Validate )
+ {
+ HANDLE hFind = FindFirstFile( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ), &pItemImpl->FindData );
+
+ if ( hFind != INVALID_HANDLE_VALUE )
+ FindClose( hFind );
+ else
+ return oslTranslateFileError( GetLastError() );
+
+ uFieldMask &= ~ osl_FileStatus_Mask_Validate;
+ }
+
+ /* If no fields to retrieve left ignore pStatus */
+ if ( !uFieldMask )
+ return osl_File_E_None;
+
+ /* Otherwise, this must be a valid pointer */
+ if ( !pStatus )
+ return osl_File_E_INVAL;
+
+ if ( pStatus->uStructSize != sizeof(oslFileStatus) )
+ return osl_File_E_INVAL;
+
+ pStatus->uValidFields = 0;
+
+ /* File time stamps */
+
+ if ( (uFieldMask & osl_FileStatus_Mask_ModifyTime) &&
+ FileTimeToTimeValue( &pItemImpl->FindData.ftLastWriteTime, &pStatus->aModifyTime ) )
+ pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime;
+
+ if ( (uFieldMask & osl_FileStatus_Mask_AccessTime) &&
+ FileTimeToTimeValue( &pItemImpl->FindData.ftLastAccessTime, &pStatus->aAccessTime ) )
+ pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime;
+
+ if ( (uFieldMask & osl_FileStatus_Mask_CreationTime) &&
+ FileTimeToTimeValue( &pItemImpl->FindData.ftCreationTime, &pStatus->aCreationTime ) )
+ pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime;
+
+ /* Most of the fields are already set, regardless of requiered fields */
+
+ rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(pItemImpl->FindData.cFileName) );
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
+
+ if ((FILE_ATTRIBUTE_REPARSE_POINT & pItemImpl->FindData.dwFileAttributes) &&
+ (IO_REPARSE_TAG_MOUNT_POINT == pItemImpl->FindData.dwReserved0))
+ pStatus->eType = osl_File_Type_Volume;
+ else if (pItemImpl->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ pStatus->eType = osl_File_Type_Directory;
+ else
+ pStatus->eType = osl_File_Type_Regular;
+
+ pStatus->uValidFields |= osl_FileStatus_Mask_Type;
+
+ pStatus->uAttributes = pItemImpl->FindData.dwFileAttributes;
+ pStatus->uValidFields |= osl_FileStatus_Mask_Attributes;
+
+ pStatus->uFileSize = (sal_uInt64)pItemImpl->FindData.nFileSizeLow + ((sal_uInt64)pItemImpl->FindData.nFileSizeHigh << 32);
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileSize;
+
+ if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL )
+ {
+ osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrLinkTargetURL );
+
+ pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
+ }
+
+ if ( uFieldMask & osl_FileStatus_Mask_FileURL )
+ {
+ if ( !pItemImpl->bFullPathNormalized )
+ {
+ sal_uInt32 nLen = rtl_uString_getLength( pItemImpl->m_pFullPath );
+ ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
+ sal_uInt32 nNewLen = GetCaseCorrectPathName( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ),
+ ::osl::mingw_reinterpret_cast<LPTSTR>( aBuffer ),
+ aBuffer.getBufSizeInSymbols(),
+ sal_True );
+
+ if ( nNewLen )
+ {
+ rtl_uString_newFromStr( &pItemImpl->m_pFullPath, aBuffer );
+ pItemImpl->bFullPathNormalized = TRUE;
+ }
+ }
+
+ osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL );
+ pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
+ }
+
+ return osl_File_E_None;
+}
+
+//#####################################################
+// file attributes handling functions
+//#####################################################
+
+//#############################################
+oslFileError SAL_CALL osl_setFileAttributes(
+ rtl_uString *ustrFileURL,
+ sal_uInt64 uAttributes )
+{
+ oslFileError error;
+ rtl_uString *ustrSysPath = NULL;
+ DWORD dwFileAttributes;
+ BOOL fSuccess;
+
+ // Converts the normalized path into a systempath
+ error = _osl_getSystemPathFromFileURL( ustrFileURL, &ustrSysPath, sal_False );
+
+ if ( osl_File_E_None != error )
+ return error;
+
+ dwFileAttributes = GetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)) );
+
+ if ( (DWORD)-1 != dwFileAttributes )
+ {
+ dwFileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
+
+ if ( uAttributes & osl_File_Attribute_ReadOnly )
+ dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
+
+ if ( uAttributes & osl_File_Attribute_Hidden )
+ dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+
+ fSuccess = SetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)), dwFileAttributes );
+ }
+ else
+ fSuccess = FALSE;
+
+ if ( !fSuccess )
+ error = oslTranslateFileError( GetLastError() );
+
+ rtl_uString_release( ustrSysPath );
+
+ return error;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_setFileTime(
+ rtl_uString *filePath,
+ const TimeValue *aCreationTime,
+ const TimeValue *aLastAccessTime,
+ const TimeValue *aLastWriteTime)
+{
+ oslFileError error;
+ rtl_uString *sysPath=NULL;
+ FILETIME *lpCreationTime=NULL;
+ FILETIME *lpLastAccessTime=NULL;
+ FILETIME *lpLastWriteTime=NULL;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ HANDLE hFile;
+ BOOL fSuccess;
+
+
+ error=_osl_getSystemPathFromFileURL(filePath, &sysPath, sal_False);
+
+ if (error==osl_File_E_INVAL)
+ return error;
+
+ hFile=CreateFileW(reinterpret_cast<LPCWSTR>(rtl_uString_getStr(sysPath)), GENERIC_WRITE, 0, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ rtl_uString_release(sysPath);
+
+ if (hFile==INVALID_HANDLE_VALUE)
+ return osl_File_E_NOENT;
+
+ if (TimeValueToFileTime(aCreationTime, &ftCreationTime))
+ lpCreationTime=&ftCreationTime;
+
+ if (TimeValueToFileTime(aLastAccessTime, &ftLastAccessTime))
+ lpLastAccessTime=&ftLastAccessTime;
+
+ if (TimeValueToFileTime(aLastWriteTime, &ftLastWriteTime))
+ lpLastWriteTime=&ftLastWriteTime;
+
+ fSuccess=SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
+
+ CloseHandle(hFile);
+
+ if (!fSuccess)
+ return osl_File_E_INVAL;
+ else
+ return osl_File_E_None;
+}