| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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; |
| } |
| } |
| |
| rtl_freeMemory(szFileMask); // #119939#, memory leak |
| } |
| } |
| |
| 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; |
| } |