lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sal / osl / w32 / file_dirvol.cxx
blobb8f8ad4e261fe3a22427c07523295380e02e5b1a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <systools/win32/uwinapi.h>
22 #include "file_url.hxx"
23 #include "filetime.hxx"
24 #include "file_error.hxx"
26 #include "path_helper.hxx"
28 #include <rtl/alloc.h>
29 #include <rtl/ustring.hxx>
30 #include <rtl/character.hxx>
31 #include <sal/log.hxx>
32 #include <o3tl/char16_t2wchar_t.hxx>
34 static const wchar_t UNC_PREFIX[] = L"\\\\";
35 static const wchar_t BACKSLASH = '\\';
36 static const wchar_t SLASH = '/';
38 BOOL TimeValueToFileTime(const TimeValue *cpTimeVal, FILETIME *pFTime)
40 SYSTEMTIME BaseSysTime;
41 FILETIME BaseFileTime;
42 FILETIME FTime;
43 BOOL fSuccess = FALSE;
45 BaseSysTime.wYear = 1970;
46 BaseSysTime.wMonth = 1;
47 BaseSysTime.wDayOfWeek = 0;
48 BaseSysTime.wDay = 1;
49 BaseSysTime.wHour = 0;
50 BaseSysTime.wMinute = 0;
51 BaseSysTime.wSecond = 0;
52 BaseSysTime.wMilliseconds = 0;
54 if (cpTimeVal==nullptr)
55 return fSuccess;
57 if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) )
59 __int64 timeValue;
61 __int64 localTime = cpTimeVal->Seconds*__int64(10000000)+cpTimeVal->Nanosec/100;
62 osl::detail::setFiletime(FTime, localTime);
63 fSuccess = 0 <= (timeValue= osl::detail::getFiletime(BaseFileTime) + osl::detail::getFiletime(FTime));
64 if (fSuccess)
65 osl::detail::setFiletime(*pFTime, timeValue);
67 return fSuccess;
70 BOOL FileTimeToTimeValue(const FILETIME *cpFTime, TimeValue *pTimeVal)
72 SYSTEMTIME BaseSysTime;
73 FILETIME BaseFileTime;
74 BOOL fSuccess = FALSE; /* Assume failure */
76 BaseSysTime.wYear = 1970;
77 BaseSysTime.wMonth = 1;
78 BaseSysTime.wDayOfWeek = 0;
79 BaseSysTime.wDay = 1;
80 BaseSysTime.wHour = 0;
81 BaseSysTime.wMinute = 0;
82 BaseSysTime.wSecond = 0;
83 BaseSysTime.wMilliseconds = 0;
85 if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) )
87 __int64 Value;
89 fSuccess = 0 <= (Value = osl::detail::getFiletime(*cpFTime) - osl::detail::getFiletime(BaseFileTime));
91 if ( fSuccess )
93 pTimeVal->Seconds = static_cast<unsigned long>(Value / 10000000L);
94 pTimeVal->Nanosec = static_cast<unsigned long>((Value % 10000000L) * 100);
97 return fSuccess;
100 namespace
103 struct Component
105 Component() :
106 begin_(nullptr), end_(nullptr)
109 bool isPresent() const
110 { return (static_cast<sal_IntPtr>(end_ - begin_) > 0); }
112 const sal_Unicode* begin_;
113 const sal_Unicode* end_;
116 struct UNCComponents
118 Component server_;
119 Component share_;
120 Component resource_;
123 inline bool is_UNC_path(const sal_Unicode* path)
124 { return (0 == wcsncmp(UNC_PREFIX, o3tl::toW(path), SAL_N_ELEMENTS(UNC_PREFIX) - 1)); }
126 void parse_UNC_path(const sal_Unicode* path, UNCComponents* puncc)
128 OSL_PRECOND(is_UNC_path(path), "Precondition violated: No UNC path");
129 OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) == -1, "Path must not contain slashes");
131 const sal_Unicode* pend = path + rtl_ustr_getLength(path);
132 const sal_Unicode* ppos = path + 2;
134 puncc->server_.begin_ = ppos;
135 while ((ppos < pend) && (*ppos != BACKSLASH))
136 ppos++;
138 puncc->server_.end_ = ppos;
140 if (BACKSLASH == *ppos)
142 puncc->share_.begin_ = ++ppos;
143 while ((ppos < pend) && (*ppos != BACKSLASH))
144 ppos++;
146 puncc->share_.end_ = ppos;
148 if (BACKSLASH == *ppos)
150 puncc->resource_.begin_ = ++ppos;
151 while (ppos < pend)
152 ppos++;
154 puncc->resource_.end_ = ppos;
158 SAL_WARN_IF(!puncc->server_.isPresent() || !puncc->share_.isPresent(),
159 "sal.osl",
160 "Postcondition violated: Invalid UNC path detected");
163 bool has_path_parent(const sal_Unicode* path)
165 // Has the given path a parent or are we already there,
166 // e.g. 'c:\' or '\\server\share\'?
168 bool has_parent = false;
169 if (is_UNC_path(path))
171 UNCComponents unc_comp;
172 parse_UNC_path(path, &unc_comp);
173 has_parent = unc_comp.resource_.isPresent();
175 else
177 has_parent = !osl::systemPathIsLogicalDrivePattern(path);
179 return has_parent;
182 inline bool has_path_parent(const OUString& path)
183 { return has_path_parent(path.getStr()); }
187 oslFileError SAL_CALL osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
189 if ( Handle )
191 rtl_uString_acquire( static_cast<rtl_uString *>(Handle) );
192 return osl_File_E_None;
194 else
195 return osl_File_E_INVAL;
198 oslFileError SAL_CALL osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
200 if ( Handle )
202 rtl_uString_release( static_cast<rtl_uString *>(Handle) );
203 return osl_File_E_None;
205 else
206 return osl_File_E_INVAL;
209 oslFileError SAL_CALL osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle, rtl_uString **pstrPath )
211 if ( Handle && pstrPath )
213 rtl_uString_assign( pstrPath, static_cast<rtl_uString *>(Handle) );
214 return osl_File_E_None;
216 else
217 return osl_File_E_INVAL;
220 #define DIRECTORYITEM_DRIVE 0
221 #define DIRECTORYITEM_FILE 1
222 #define DIRECTORYITEM_SERVER 2
224 struct DirectoryItem_Impl
226 UINT uType;
227 union {
228 WIN32_FIND_DATAW FindData;
229 WCHAR cDriveString[MAX_PATH];
231 rtl_uString* m_pFullPath;
232 BOOL bFullPathNormalized;
233 int nRefCount;
236 #define DIRECTORYTYPE_LOCALROOT 0
237 #define DIRECTORYTYPE_NETROOT 1
238 #define DIRECTORYTYPE_FILESYSTEM 3
240 struct Directory_Impl
242 UINT uType;
243 union {
244 HANDLE hDirectory;
245 HANDLE hEnumDrives;
247 rtl_uString* m_pDirectoryPath;
250 typedef struct tagDRIVEENUM
252 LPCWSTR lpIdent;
253 WCHAR cBuffer[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256];
254 LPCWSTR lpCurrent;
255 } DRIVEENUM, * PDRIVEENUM, FAR * LPDRIVEENUM;
257 static HANDLE WINAPI OpenLogicalDrivesEnum()
259 LPDRIVEENUM pEnum = static_cast<LPDRIVEENUM>(HeapAlloc( GetProcessHeap(), 0, sizeof(DRIVEENUM) ));
260 if ( pEnum )
262 DWORD dwNumCopied = GetLogicalDriveStringsW( SAL_N_ELEMENTS(pEnum->cBuffer) - 1, pEnum->cBuffer );
264 if ( dwNumCopied && dwNumCopied < SAL_N_ELEMENTS(pEnum->cBuffer) )
266 pEnum->lpCurrent = pEnum->cBuffer;
267 pEnum->lpIdent = L"tagDRIVEENUM";
269 else
271 HeapFree( GetProcessHeap(), 0, pEnum );
272 pEnum = nullptr;
275 return pEnum ? static_cast<HANDLE>(pEnum) : INVALID_HANDLE_VALUE;
278 static BOOL WINAPI EnumLogicalDrives(HANDLE hEnum, LPWSTR lpBuffer)
280 BOOL fSuccess = FALSE;
281 LPDRIVEENUM pEnum = static_cast<LPDRIVEENUM>(hEnum);
283 if ( pEnum )
285 int nLen = wcslen( pEnum->lpCurrent );
287 if ( nLen )
289 CopyMemory( lpBuffer, pEnum->lpCurrent, (nLen + 1) * sizeof(WCHAR) );
290 pEnum->lpCurrent += nLen + 1;
291 fSuccess = TRUE;
293 else
294 SetLastError( ERROR_NO_MORE_FILES );
296 else
297 SetLastError( ERROR_INVALID_HANDLE );
299 return fSuccess;
302 static BOOL WINAPI CloseLogicalDrivesEnum(HANDLE hEnum)
304 BOOL fSuccess = FALSE;
305 LPDRIVEENUM pEnum = static_cast<LPDRIVEENUM>(hEnum);
307 if ( pEnum )
309 HeapFree( GetProcessHeap(), 0, pEnum );
310 fSuccess = TRUE;
312 else
313 SetLastError( ERROR_INVALID_HANDLE );
315 return fSuccess;
318 typedef struct tagDIRECTORY
320 HANDLE hFind;
321 WIN32_FIND_DATAW aFirstData;
322 } DIRECTORY, *PDIRECTORY, FAR *LPDIRECTORY;
324 static HANDLE WINAPI OpenDirectory( rtl_uString* pPath)
326 LPDIRECTORY pDirectory = nullptr;
328 if ( pPath )
330 sal_uInt32 nLen = rtl_uString_getLength( pPath );
331 if ( nLen )
333 const WCHAR* pSuffix = nullptr;
334 sal_uInt32 nSuffLen = 0;
336 if ( pPath->buffer[nLen - 1] != L'\\' )
338 pSuffix = L"\\*.*";
339 nSuffLen = 4;
341 else
343 pSuffix = L"*.*";
344 nSuffLen = 3;
347 WCHAR* szFileMask = static_cast< WCHAR* >( malloc( sizeof( WCHAR ) * ( nLen + nSuffLen + 1 ) ) );
349 wcscpy( szFileMask, o3tl::toW(rtl_uString_getStr( pPath )) );
350 wcscat( szFileMask, pSuffix );
352 pDirectory = static_cast<LPDIRECTORY>(HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY)));
353 pDirectory->hFind = FindFirstFileW(szFileMask, &pDirectory->aFirstData);
355 if (!IsValidHandle(pDirectory->hFind))
357 if ( GetLastError() != ERROR_NO_MORE_FILES )
359 HeapFree(GetProcessHeap(), 0, pDirectory);
360 pDirectory = nullptr;
363 free(szFileMask);
367 return static_cast<HANDLE>(pDirectory);
370 static BOOL WINAPI EnumDirectory(HANDLE hDirectory, LPWIN32_FIND_DATAW pFindData)
372 BOOL fSuccess = FALSE;
373 LPDIRECTORY pDirectory = static_cast<LPDIRECTORY>(hDirectory);
375 if ( pDirectory )
377 BOOL fValid;
381 if ( pDirectory->aFirstData.cFileName[0] )
383 *pFindData = pDirectory->aFirstData;
384 fSuccess = TRUE;
385 pDirectory->aFirstData.cFileName[0] = 0;
387 else if ( IsValidHandle( pDirectory->hFind ) )
388 fSuccess = FindNextFileW( pDirectory->hFind, pFindData );
389 else
391 fSuccess = FALSE;
392 SetLastError( ERROR_NO_MORE_FILES );
395 fValid = fSuccess && wcscmp( L".", pFindData->cFileName ) != 0 && wcscmp( L"..", pFindData->cFileName ) != 0;
397 } while( fSuccess && !fValid );
399 else
400 SetLastError( ERROR_INVALID_HANDLE );
402 return fSuccess;
405 static BOOL WINAPI CloseDirectory(HANDLE hDirectory)
407 BOOL fSuccess = FALSE;
408 LPDIRECTORY pDirectory = static_cast<LPDIRECTORY>(hDirectory);
410 if (pDirectory)
412 if (IsValidHandle(pDirectory->hFind))
413 fSuccess = FindClose(pDirectory->hFind);
415 fSuccess = HeapFree(GetProcessHeap(), 0, pDirectory) && fSuccess;
417 else
418 SetLastError(ERROR_INVALID_HANDLE);
420 return fSuccess;
423 static oslFileError osl_openLocalRoot(
424 rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
426 rtl_uString *strSysPath = nullptr;
427 oslFileError error;
429 if ( !pDirectory )
430 return osl_File_E_INVAL;
432 *pDirectory = nullptr;
434 error = osl_getSystemPathFromFileURL_( strDirectoryPath, &strSysPath, false );
435 if ( osl_File_E_None == error )
437 Directory_Impl *pDirImpl;
439 pDirImpl = static_cast<Directory_Impl*>(malloc( sizeof(Directory_Impl)));
440 ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
441 rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strSysPath );
443 /* Append backslash if necessary */
445 /* @@@ToDo
446 use function ensure backslash
448 sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
449 if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
451 rtl_uString* pCurDir = nullptr;
452 rtl_uString* pBackSlash = nullptr;
454 rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
455 rtl_uString_newFromAscii( &pBackSlash, "\\" );
456 rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
457 rtl_uString_release( pBackSlash );
458 rtl_uString_release( pCurDir );
461 pDirImpl->uType = DIRECTORYTYPE_LOCALROOT;
462 pDirImpl->hEnumDrives = OpenLogicalDrivesEnum();
464 /* @@@ToDo
465 Use IsValidHandle(...)
467 if ( pDirImpl->hEnumDrives != INVALID_HANDLE_VALUE )
469 *pDirectory = static_cast<oslDirectory>(pDirImpl);
470 error = osl_File_E_None;
472 else
474 if ( pDirImpl )
476 if ( pDirImpl->m_pDirectoryPath )
478 rtl_uString_release( pDirImpl->m_pDirectoryPath );
479 pDirImpl->m_pDirectoryPath = nullptr;
482 free(pDirImpl);
483 pDirImpl = nullptr;
486 error = oslTranslateFileError( GetLastError() );
489 rtl_uString_release( strSysPath );
491 return error;
494 static oslFileError osl_openFileDirectory(
495 rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
497 oslFileError error = osl_File_E_None;
499 if ( !pDirectory )
500 return osl_File_E_INVAL;
501 *pDirectory = nullptr;
503 Directory_Impl *pDirImpl = static_cast<Directory_Impl*>(malloc(sizeof(Directory_Impl)));
504 ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
505 rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strDirectoryPath );
507 /* Append backslash if necessary */
509 /* @@@ToDo
510 use function ensure backslash
512 sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
513 if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
515 rtl_uString* pCurDir = nullptr;
516 rtl_uString* pBackSlash = nullptr;
518 rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
519 rtl_uString_newFromAscii( &pBackSlash, "\\" );
520 rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
521 rtl_uString_release( pBackSlash );
522 rtl_uString_release( pCurDir );
525 pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM;
526 pDirImpl->hDirectory = OpenDirectory( pDirImpl->m_pDirectoryPath );
528 if ( !pDirImpl->hDirectory )
530 error = oslTranslateFileError( GetLastError() );
532 if ( pDirImpl->m_pDirectoryPath )
534 rtl_uString_release( pDirImpl->m_pDirectoryPath );
535 pDirImpl->m_pDirectoryPath = nullptr;
538 free(pDirImpl);
539 pDirImpl = nullptr;
542 *pDirectory = static_cast<oslDirectory>(pDirImpl);
543 return error;
546 static oslFileError osl_openNetworkServer(
547 rtl_uString *strSysDirPath, oslDirectory *pDirectory)
549 NETRESOURCEW aNetResource;
550 HANDLE hEnum;
551 DWORD dwError;
553 ZeroMemory( &aNetResource, sizeof(aNetResource) );
555 aNetResource.lpRemoteName = o3tl::toW(strSysDirPath->buffer);
557 dwError = WNetOpenEnumW(
558 RESOURCE_GLOBALNET,
559 RESOURCETYPE_DISK,
560 RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER,
561 &aNetResource,
562 &hEnum );
564 if ( ERROR_SUCCESS == dwError )
566 Directory_Impl *pDirImpl;
568 pDirImpl = static_cast<Directory_Impl*>(malloc(sizeof(Directory_Impl)));
569 ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
570 pDirImpl->uType = DIRECTORYTYPE_NETROOT;
571 pDirImpl->hDirectory = hEnum;
572 *pDirectory = static_cast<oslDirectory>(pDirImpl);
574 return oslTranslateFileError( dwError );
577 static DWORD create_dir_with_callback(
578 rtl_uString * dir_path,
579 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
580 void* pData)
582 // Create the specified directory and call the
583 // user specified callback function. On success
584 // the function returns ERROR_SUCCESS else a Win32 error code.
586 BOOL bCreated = CreateDirectoryW( o3tl::toW(rtl_uString_getStr( dir_path )), nullptr );
588 if ( bCreated )
590 if (aDirectoryCreationCallbackFunc)
592 OUString url;
593 osl_getFileURLFromSystemPath(dir_path, &(url.pData));
594 aDirectoryCreationCallbackFunc(pData, url.pData);
596 return ERROR_SUCCESS;
598 return GetLastError();
601 static int path_make_parent(sal_Unicode* path)
603 /* Cut off the last part of the given path to
604 get the parent only, e.g. 'c:\dir\subdir' ->
605 'c:\dir' or '\\share\sub\dir' -> '\\share\sub'
606 @return The position where the path has been cut
607 off (this is the position of the last backslash).
608 If there are no more parents 0 will be returned,
609 e.g. 'c:\' or '\\Share' have no more parents */
611 OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) == -1, "Path must not contain slashes");
612 OSL_PRECOND(has_path_parent(path), "Path must have a parent");
614 sal_Unicode* pos_last_backslash = path + rtl_ustr_lastIndexOfChar(path, BACKSLASH);
615 *pos_last_backslash = 0;
616 return (pos_last_backslash - path);
619 static DWORD create_dir_recursively_(
620 rtl_uString * dir_path,
621 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
622 void* pData)
624 OSL_PRECOND(
625 rtl_ustr_lastIndexOfChar_WithLength(dir_path->buffer, dir_path->length, BACKSLASH) != dir_path->length,
626 "Path must not end with a backslash");
628 DWORD w32_error = create_dir_with_callback(
629 dir_path, aDirectoryCreationCallbackFunc, pData);
630 if (w32_error == ERROR_SUCCESS)
631 return ERROR_SUCCESS;
633 if ((w32_error != ERROR_PATH_NOT_FOUND) || !has_path_parent(dir_path->buffer))
634 return w32_error;
636 int pos = path_make_parent(dir_path->buffer); // dir_path->buffer[pos] = 0, restore below
638 w32_error = create_dir_recursively_(
639 dir_path, aDirectoryCreationCallbackFunc, pData);
641 dir_path->buffer[pos] = BACKSLASH; // restore
643 if (ERROR_SUCCESS != w32_error && ERROR_ALREADY_EXISTS != w32_error)
644 return w32_error;
646 return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
649 oslFileError SAL_CALL osl_createDirectoryPath(
650 rtl_uString* aDirectoryUrl,
651 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
652 void* pData)
654 if (aDirectoryUrl == nullptr)
655 return osl_File_E_INVAL;
657 OUString sys_path;
658 oslFileError osl_error =
659 osl_getSystemPathFromFileURL_(aDirectoryUrl, &sys_path.pData, false);
661 if (osl_error != osl_File_E_None)
662 return osl_error;
664 osl::systemPathRemoveSeparator(sys_path);
666 // const_cast because sys_path is a local copy
667 // which we want to modify inplace instead of
668 // copy it into another buffer on the heap again
669 return oslTranslateFileError(create_dir_recursively_(
670 sys_path.pData, aDirectoryCreationCallbackFunc, pData));
673 oslFileError SAL_CALL osl_createDirectory(rtl_uString* strPath)
675 return osl_createDirectoryWithFlags(
676 strPath, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write);
679 oslFileError osl_createDirectoryWithFlags(rtl_uString * strPath, sal_uInt32)
681 rtl_uString *strSysPath = nullptr;
682 oslFileError error = osl_getSystemPathFromFileURL_( strPath, &strSysPath, false );
684 if ( osl_File_E_None == error )
686 BOOL bCreated = CreateDirectoryW( o3tl::toW(rtl_uString_getStr( strSysPath )), nullptr );
688 if ( !bCreated )
690 /*@@@ToDo
691 The following case is a hack because the ucb or the webtop had some
692 problems with the error code that CreateDirectory returns in
693 case the path is only a logical drive, should be removed!
696 const sal_Unicode *pBuffer = rtl_uString_getStr( strSysPath );
697 sal_Int32 nLen = rtl_uString_getLength( strSysPath );
699 if (
700 ( ( pBuffer[0] >= 'A' && pBuffer[0] <= 'Z' ) ||
701 ( pBuffer[0] >= 'a' && pBuffer[0] <= 'z' ) ) &&
702 pBuffer[1] == ':' && ( nLen ==2 || ( nLen == 3 && pBuffer[2] == '\\' ) )
704 SetLastError( ERROR_ALREADY_EXISTS );
706 error = oslTranslateFileError( GetLastError() );
709 rtl_uString_release( strSysPath );
711 return error;
714 oslFileError SAL_CALL osl_removeDirectory(rtl_uString* strPath)
716 rtl_uString *strSysPath = nullptr;
717 oslFileError error = osl_getSystemPathFromFileURL_( strPath, &strSysPath, false );
719 if ( osl_File_E_None == error )
721 if ( RemoveDirectoryW( o3tl::toW(rtl_uString_getStr( strSysPath ) )) )
722 error = osl_File_E_None;
723 else
724 error = oslTranslateFileError( GetLastError() );
726 rtl_uString_release( strSysPath );
728 return error;
731 oslFileError SAL_CALL osl_openDirectory(rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
733 oslFileError error;
735 if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath->buffer, "file:///" ) )
736 error = osl_openLocalRoot( strDirectoryPath, pDirectory );
737 else
739 rtl_uString *strSysDirectoryPath = nullptr;
740 DWORD dwPathType;
742 error = osl_getSystemPathFromFileURL_( strDirectoryPath, &strSysDirectoryPath, false );
744 if ( osl_File_E_None != error )
745 return error;
747 dwPathType = IsValidFilePath( strSysDirectoryPath, VALIDATEPATH_NORMAL, nullptr );
749 if ( dwPathType & PATHTYPE_IS_SERVER )
751 error = osl_openNetworkServer( strSysDirectoryPath, pDirectory );
753 else
754 error = osl_openFileDirectory( strSysDirectoryPath, pDirectory );
756 rtl_uString_release( strSysDirectoryPath );
758 return error;
761 static oslFileError osl_getNextNetResource(
762 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/ )
764 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
765 DirectoryItem_Impl *pItemImpl = nullptr;
766 BYTE buffer[16384];
767 LPNETRESOURCEW lpNetResource = reinterpret_cast<LPNETRESOURCEW>(buffer);
768 DWORD dwError, dwCount, dwBufSize;
770 if ( !pItem )
771 return osl_File_E_INVAL;
772 *pItem = nullptr;
774 if ( !pDirImpl )
775 return osl_File_E_INVAL;
777 dwCount = 1;
778 dwBufSize = sizeof(buffer);
779 dwError = WNetEnumResourceW( pDirImpl->hDirectory, &dwCount, lpNetResource, &dwBufSize );
781 switch ( dwError )
783 case NO_ERROR:
784 case ERROR_MORE_DATA:
786 pItemImpl = static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
787 if ( !pItemImpl )
788 return osl_File_E_NOMEM;
790 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
791 pItemImpl->uType = DIRECTORYITEM_DRIVE;
792 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
794 wcscpy( pItemImpl->cDriveString, lpNetResource->lpRemoteName );
796 *pItem = pItemImpl;
798 return osl_File_E_None;
799 case ERROR_NO_MORE_ITEMS:
800 return osl_File_E_NOENT;
801 default:
802 return oslTranslateFileError( dwError );
806 static oslFileError osl_getNextDrive(
807 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/ )
809 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
810 DirectoryItem_Impl *pItemImpl = nullptr;
811 BOOL fSuccess;
813 if ( !pItem )
814 return osl_File_E_INVAL;
815 *pItem = nullptr;
817 if ( !pDirImpl )
818 return osl_File_E_INVAL;
820 pItemImpl = static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
821 if ( !pItemImpl )
822 return osl_File_E_NOMEM;
824 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
825 pItemImpl->uType = DIRECTORYITEM_DRIVE;
826 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
827 fSuccess = EnumLogicalDrives( pDirImpl->hEnumDrives, pItemImpl->cDriveString );
829 if ( fSuccess )
831 *pItem = pItemImpl;
832 return osl_File_E_None;
834 else
836 if ( pItemImpl->m_pFullPath )
838 rtl_uString_release( pItemImpl->m_pFullPath );
839 pItemImpl->m_pFullPath = nullptr;
842 free( pItemImpl );
843 return oslTranslateFileError( GetLastError() );
847 static oslFileError osl_getNextFileItem(
848 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/)
850 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
851 DirectoryItem_Impl *pItemImpl = nullptr;
852 BOOL fFound;
854 if ( !pItem )
855 return osl_File_E_INVAL;
856 *pItem = nullptr;
858 if ( !pDirImpl )
859 return osl_File_E_INVAL;
861 pItemImpl = static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
862 if ( !pItemImpl )
863 return osl_File_E_NOMEM;
865 memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
866 fFound = EnumDirectory( pDirImpl->hDirectory, &pItemImpl->FindData );
868 if ( fFound )
870 pItemImpl->uType = DIRECTORYITEM_FILE;
871 pItemImpl->nRefCount = 1;
873 rtl_uString* pTmpFileName = nullptr;
874 rtl_uString_newFromStr( &pTmpFileName, o3tl::toU(pItemImpl->FindData.cFileName) );
875 rtl_uString_newConcat( &pItemImpl->m_pFullPath, pDirImpl->m_pDirectoryPath, pTmpFileName );
876 rtl_uString_release( pTmpFileName );
878 pItemImpl->bFullPathNormalized = FALSE;
879 *pItem = static_cast<oslDirectoryItem>(pItemImpl);
880 return osl_File_E_None;
882 else
884 if ( pItemImpl->m_pFullPath )
886 rtl_uString_release( pItemImpl->m_pFullPath );
887 pItemImpl->m_pFullPath = nullptr;
890 free( pItemImpl );
891 return oslTranslateFileError( GetLastError() );
895 oslFileError SAL_CALL osl_getNextDirectoryItem(
896 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint)
898 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
900 /* Assume failure */
902 if ( !pItem )
903 return osl_File_E_INVAL;
904 *pItem = nullptr;
906 if ( !pDirImpl )
907 return osl_File_E_INVAL;
909 switch ( pDirImpl->uType )
911 case DIRECTORYTYPE_LOCALROOT:
912 return osl_getNextDrive( Directory, pItem, uHint );
913 case DIRECTORYTYPE_NETROOT:
914 return osl_getNextNetResource( Directory, pItem, uHint );
915 case DIRECTORYTYPE_FILESYSTEM:
916 return osl_getNextFileItem( Directory, pItem, uHint );
917 default:
918 return osl_File_E_INVAL;
922 oslFileError SAL_CALL osl_closeDirectory(oslDirectory Directory)
924 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
925 oslFileError eError = osl_File_E_INVAL;
927 if ( pDirImpl )
929 switch ( pDirImpl->uType )
931 case DIRECTORYTYPE_FILESYSTEM:
932 eError = CloseDirectory( pDirImpl->hDirectory ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
933 break;
934 case DIRECTORYTYPE_LOCALROOT:
935 eError = CloseLogicalDrivesEnum( pDirImpl->hEnumDrives ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
936 break;
937 case DIRECTORYTYPE_NETROOT:
939 DWORD err = WNetCloseEnum(pDirImpl->hDirectory);
940 eError = (err == NO_ERROR) ? osl_File_E_None : oslTranslateFileError(err);
942 break;
943 default:
944 OSL_FAIL( "Invalid directory type" );
945 break;
948 if ( pDirImpl->m_pDirectoryPath )
950 rtl_uString_release( pDirImpl->m_pDirectoryPath );
951 pDirImpl->m_pDirectoryPath = nullptr;
954 free(pDirImpl);
956 return eError;
959 /* Different types of paths */
960 enum PATHTYPE
962 PATHTYPE_SYNTAXERROR = 0,
963 PATHTYPE_NETROOT,
964 PATHTYPE_NETSERVER,
965 PATHTYPE_VOLUME,
966 PATHTYPE_FILE
969 oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString *strFilePath, oslDirectoryItem *pItem)
971 oslFileError error = osl_File_E_None;
972 rtl_uString* strSysFilePath = nullptr;
973 PATHTYPE type = PATHTYPE_FILE;
974 DWORD dwPathType;
976 /* Assume failure */
978 if ( !pItem )
979 return osl_File_E_INVAL;
981 *pItem = nullptr;
983 error = osl_getSystemPathFromFileURL_( strFilePath, &strSysFilePath, false );
985 if ( osl_File_E_None != error )
986 return error;
988 dwPathType = IsValidFilePath( strSysFilePath, VALIDATEPATH_NORMAL, nullptr );
990 if ( dwPathType & PATHTYPE_IS_VOLUME )
991 type = PATHTYPE_VOLUME;
992 else if ( dwPathType & PATHTYPE_IS_SERVER )
993 type = PATHTYPE_NETSERVER;
994 else
995 type = PATHTYPE_FILE;
997 switch ( type )
999 case PATHTYPE_NETSERVER:
1001 DirectoryItem_Impl* pItemImpl =
1002 static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
1004 if ( !pItemImpl )
1005 error = osl_File_E_NOMEM;
1007 if ( osl_File_E_None == error )
1009 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1010 pItemImpl->uType = DIRECTORYITEM_SERVER;
1012 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
1013 rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath );
1015 // Assign a title anyway
1017 int iSrc = 2;
1018 int iDst = 0;
1020 while( iSrc < strSysFilePath->length && strSysFilePath->buffer[iSrc] && strSysFilePath->buffer[iSrc] != '\\' )
1022 pItemImpl->FindData.cFileName[iDst++] = strSysFilePath->buffer[iSrc++];
1026 *pItem = pItemImpl;
1029 break;
1030 case PATHTYPE_VOLUME:
1032 DirectoryItem_Impl* pItemImpl =
1033 static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
1035 if ( !pItemImpl )
1036 error = osl_File_E_NOMEM;
1038 if ( osl_File_E_None == error )
1040 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1041 pItemImpl->uType = DIRECTORYITEM_DRIVE;
1043 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
1045 wcscpy( pItemImpl->cDriveString, o3tl::toW(strSysFilePath->buffer) );
1046 pItemImpl->cDriveString[0] = rtl::toAsciiUpperCase( pItemImpl->cDriveString[0] );
1048 if ( pItemImpl->cDriveString[wcslen(pItemImpl->cDriveString) - 1] != '\\' )
1049 wcscat( pItemImpl->cDriveString, L"\\" );
1051 *pItem = pItemImpl;
1054 break;
1055 case PATHTYPE_SYNTAXERROR:
1056 case PATHTYPE_NETROOT:
1057 case PATHTYPE_FILE:
1059 HANDLE hFind;
1060 WIN32_FIND_DATAW aFindData;
1062 if ( strSysFilePath->length > 0 && strSysFilePath->buffer[strSysFilePath->length - 1] == '\\' )
1063 rtl_uString_newFromStr_WithLength( &strSysFilePath, strSysFilePath->buffer, strSysFilePath->length - 1 );
1065 hFind = FindFirstFileW( o3tl::toW(rtl_uString_getStr(strSysFilePath)), &aFindData );
1067 if ( hFind != INVALID_HANDLE_VALUE )
1069 DirectoryItem_Impl *pItemImpl =
1070 static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
1072 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1073 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
1075 CopyMemory( &pItemImpl->FindData, &aFindData, sizeof(WIN32_FIND_DATAW) );
1076 rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath );
1078 // MT: This costs 600ms startup time on fast v60x!
1079 // GetCaseCorrectPathName( pItemImpl->szFullPath, pItemImpl->szFullPath, sizeof(pItemImpl->szFullPath) );
1081 pItemImpl->uType = DIRECTORYITEM_FILE;
1082 *pItem = pItemImpl;
1083 FindClose( hFind );
1085 else
1086 error = oslTranslateFileError( GetLastError() );
1088 break;
1091 if ( strSysFilePath )
1092 rtl_uString_release( strSysFilePath );
1094 return error;
1097 oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item )
1099 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1101 if ( !pItemImpl )
1102 return osl_File_E_INVAL;
1104 pItemImpl->nRefCount++;
1105 return osl_File_E_None;
1108 oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
1110 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1112 if ( !pItemImpl )
1113 return osl_File_E_INVAL;
1115 if ( ! --pItemImpl->nRefCount )
1117 if ( pItemImpl->m_pFullPath )
1119 rtl_uString_release( pItemImpl->m_pFullPath );
1120 pItemImpl->m_pFullPath = nullptr;
1123 free( pItemImpl );
1126 return osl_File_E_None;
1129 sal_Bool
1130 SAL_CALL osl_identicalDirectoryItem( oslDirectoryItem a, oslDirectoryItem b)
1132 DirectoryItem_Impl *pA = static_cast<DirectoryItem_Impl *>(a);
1133 DirectoryItem_Impl *pB = static_cast<DirectoryItem_Impl *>(b);
1134 if (a == b)
1135 return true;
1136 /* same name => same item, unless renaming / moving madness has occurred */
1137 if (pA->m_pFullPath == pB->m_pFullPath)
1138 return true;
1140 // FIXME: as/when/if this is used in anger on Windows we could
1141 // do better here.
1143 return false;
1146 static inline bool is_floppy_A_present()
1147 { return (GetLogicalDrives() & 1); }
1149 static inline bool is_floppy_B_present()
1150 { return (GetLogicalDrives() & 2); }
1152 static bool is_floppy_volume_mount_point(const OUString& path)
1154 // determines if a volume mount point shows to a floppy
1155 // disk by comparing the unique volume names
1156 static const LPCWSTR FLOPPY_A = L"A:\\";
1157 static const LPCWSTR FLOPPY_B = L"B:\\";
1159 OUString p(path);
1160 osl::systemPathEnsureSeparator(p);
1162 WCHAR vn[51];
1163 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p.getStr()), vn, SAL_N_ELEMENTS(vn)))
1165 WCHAR vnfloppy[51];
1166 if (is_floppy_A_present() &&
1167 GetVolumeNameForVolumeMountPointW(FLOPPY_A, vnfloppy, SAL_N_ELEMENTS(vnfloppy)) &&
1168 (0 == wcscmp(vn, vnfloppy)))
1169 return true;
1171 if (is_floppy_B_present() &&
1172 GetVolumeNameForVolumeMountPointW(FLOPPY_B, vnfloppy, SAL_N_ELEMENTS(vnfloppy)) &&
1173 (0 == wcscmp(vn, vnfloppy)))
1174 return true;
1176 return false;
1179 static bool is_floppy_drive(const OUString& path)
1181 static const LPCWSTR FLOPPY_DRV_LETTERS = L"AaBb";
1183 // we must take into account that even a floppy
1184 // drive may be mounted to a directory so checking
1185 // for the drive letter alone is not sufficient
1186 // we must compare the unique volume name with
1187 // that of the available floppy disks
1189 const sal_Unicode* pszPath = path.getStr();
1190 return ((wcschr(FLOPPY_DRV_LETTERS, pszPath[0]) && (L':' == pszPath[1])) || is_floppy_volume_mount_point(path));
1193 static bool is_volume_mount_point(const OUString& path)
1195 OUString p(path);
1196 osl::systemPathRemoveSeparator(p);
1198 bool is_volume_root = false;
1200 if (!is_floppy_drive(p))
1202 DWORD fattr = GetFileAttributesW(o3tl::toW(p.getStr()));
1204 if ((INVALID_FILE_ATTRIBUTES != fattr) &&
1205 (FILE_ATTRIBUTE_REPARSE_POINT & fattr))
1207 WIN32_FIND_DATAW find_data;
1208 HANDLE h_find = FindFirstFileW(o3tl::toW(p.getStr()), &find_data);
1210 if (IsValidHandle(h_find) &&
1211 (FILE_ATTRIBUTE_REPARSE_POINT & find_data.dwFileAttributes) &&
1212 (IO_REPARSE_TAG_MOUNT_POINT == find_data.dwReserved0))
1214 is_volume_root = true;
1216 if (IsValidHandle(h_find))
1217 FindClose(h_find);
1220 return is_volume_root;
1223 static UINT get_volume_mount_point_drive_type(const OUString& path)
1225 if (0 == path.getLength())
1226 return GetDriveTypeW(nullptr);
1228 OUString p(path);
1229 osl::systemPathEnsureSeparator(p);
1231 WCHAR vn[51];
1232 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p.getStr()), vn, SAL_N_ELEMENTS(vn)))
1233 return GetDriveTypeW(vn);
1235 return DRIVE_NO_ROOT_DIR;
1238 static inline bool is_drivetype_request(sal_uInt32 field_mask)
1240 return (field_mask & osl_VolumeInfo_Mask_Attributes);
1243 static oslFileError osl_get_drive_type(
1244 const OUString& path, oslVolumeInfo* pInfo)
1246 // GetDriveType fails on empty volume mount points
1247 // see Knowledge Base Q244089
1248 UINT drive_type;
1249 if (is_volume_mount_point(path))
1250 drive_type = get_volume_mount_point_drive_type(path);
1251 else
1252 drive_type = GetDriveTypeW(o3tl::toW(path.getStr()));
1254 if (DRIVE_NO_ROOT_DIR == drive_type)
1255 return oslTranslateFileError(ERROR_INVALID_DRIVE);
1257 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1259 switch (drive_type)
1261 case DRIVE_CDROM:
1262 pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable;
1263 break;
1264 case DRIVE_REMOVABLE:
1265 pInfo->uAttributes |= osl_Volume_Attribute_Removeable;
1266 if (is_floppy_drive(path))
1267 pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk;
1268 break;
1269 case DRIVE_FIXED:
1270 pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk;
1271 break;
1272 case DRIVE_RAMDISK:
1273 pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk;
1274 break;
1275 case DRIVE_REMOTE:
1276 pInfo->uAttributes |= osl_Volume_Attribute_Remote;
1277 break;
1278 case DRIVE_UNKNOWN:
1279 pInfo->uAttributes = 0;
1280 break;
1281 default:
1282 pInfo->uValidFields &= ~osl_VolumeInfo_Mask_Attributes;
1283 pInfo->uAttributes = 0;
1284 break;
1286 return osl_File_E_None;
1289 static inline bool is_volume_space_info_request(sal_uInt32 field_mask)
1291 return (field_mask &
1292 (osl_VolumeInfo_Mask_TotalSpace |
1293 osl_VolumeInfo_Mask_UsedSpace |
1294 osl_VolumeInfo_Mask_FreeSpace));
1297 static void get_volume_space_information(
1298 const OUString& path, oslVolumeInfo *pInfo)
1300 BOOL ret = GetDiskFreeSpaceExW(
1301 o3tl::toW(path.getStr()),
1302 reinterpret_cast<PULARGE_INTEGER>(&pInfo->uFreeSpace),
1303 reinterpret_cast<PULARGE_INTEGER>(&pInfo->uTotalSpace),
1304 nullptr);
1306 if (ret)
1308 pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace;
1309 pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace |
1310 osl_VolumeInfo_Mask_UsedSpace |
1311 osl_VolumeInfo_Mask_FreeSpace;
1315 static inline bool is_filesystem_attributes_request(sal_uInt32 field_mask)
1317 return (field_mask &
1318 (osl_VolumeInfo_Mask_MaxNameLength |
1319 osl_VolumeInfo_Mask_MaxPathLength |
1320 osl_VolumeInfo_Mask_FileSystemName |
1321 osl_VolumeInfo_Mask_FileSystemCaseHandling));
1324 static oslFileError get_filesystem_attributes(
1325 const OUString& path, sal_uInt32 field_mask, oslVolumeInfo* pInfo)
1327 pInfo->uAttributes = 0;
1329 // osl_get_drive_type must be called first because
1330 // this function resets osl_VolumeInfo_Mask_Attributes
1331 // on failure
1332 if (is_drivetype_request(field_mask))
1334 oslFileError osl_error = osl_get_drive_type(path, pInfo);
1335 if (osl_File_E_None != osl_error)
1336 return osl_error;
1338 if (is_filesystem_attributes_request(field_mask))
1340 /* the following two parameters can not be longer than MAX_PATH+1 */
1341 WCHAR vn[MAX_PATH+1];
1342 WCHAR fsn[MAX_PATH+1];
1344 DWORD serial;
1345 DWORD mcl;
1346 DWORD flags;
1348 LPCWSTR pszPath = o3tl::toW(path.getStr());
1349 if (GetVolumeInformationW(pszPath, vn, MAX_PATH+1, &serial, &mcl, &flags, fsn, MAX_PATH+1))
1351 // Currently sal does not use this value, instead MAX_PATH is used
1352 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength;
1353 pInfo->uMaxNameLength = mcl;
1355 // Should the uMaxPathLength be set to 32767, "\\?\" prefix allowes it
1356 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength;
1357 pInfo->uMaxPathLength = MAX_PATH;
1359 pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName;
1360 rtl_uString_newFromStr(&pInfo->ustrFileSystemName, o3tl::toU(fsn));
1362 // volumes (even NTFS) will always be considered case
1363 // insensitive because the Win32 API is not able to
1364 // deal with case sensitive volumes see M$ Knowledge Base
1365 // article 100625 that's why we never set the attribute
1366 // osl_Volume_Attribute_Case_Sensitive
1368 if (flags & FS_CASE_IS_PRESERVED)
1369 pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved;
1371 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1374 return osl_File_E_None;
1377 static bool path_get_parent(OUString& path)
1379 OSL_PRECOND(path.lastIndexOf(SLASH) == -1, "Path must not have slashes");
1381 if (!has_path_parent(path))
1383 sal_Int32 i = path.lastIndexOf(BACKSLASH);
1384 if (-1 < i)
1386 path = OUString(path.getStr(), i);
1387 return true;
1390 return false;
1393 static void path_travel_to_volume_root(const OUString& system_path, OUString& volume_root)
1395 OUString sys_path(system_path);
1397 while(!is_volume_mount_point(sys_path) && path_get_parent(sys_path))
1398 /**/;
1400 volume_root = sys_path;
1401 osl::systemPathEnsureSeparator(volume_root);
1404 oslFileError SAL_CALL osl_getVolumeInformation(
1405 rtl_uString *ustrURL, oslVolumeInfo *pInfo, sal_uInt32 uFieldMask )
1407 if (!pInfo)
1408 return osl_File_E_INVAL;
1410 OUString system_path;
1411 oslFileError error = osl_getSystemPathFromFileURL_(ustrURL, &system_path.pData, false);
1413 if (osl_File_E_None != error)
1414 return error;
1416 OUString volume_root;
1417 path_travel_to_volume_root(system_path, volume_root);
1419 pInfo->uValidFields = 0;
1421 if ((error = get_filesystem_attributes(volume_root, uFieldMask, pInfo)) != osl_File_E_None)
1422 return error;
1424 if (is_volume_space_info_request(uFieldMask))
1425 get_volume_space_information(volume_root, pInfo);
1427 if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle)
1429 error = osl_getFileURLFromSystemPath(volume_root.pData, reinterpret_cast<rtl_uString**>(&pInfo->pDeviceHandle));
1430 if (error != osl_File_E_None)
1431 return error;
1432 pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle;
1435 return osl_File_E_None;
1438 static oslFileError osl_getDriveInfo(
1439 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask)
1441 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1442 WCHAR cDrive[3] = L"A:";
1443 WCHAR cRoot[4] = L"A:\\";
1445 if ( !pItemImpl )
1446 return osl_File_E_INVAL;
1448 pStatus->uValidFields = 0;
1450 cDrive[0] = pItemImpl->cDriveString[0];
1451 cRoot[0] = pItemImpl->cDriveString[0];
1453 if ( uFieldMask & osl_FileStatus_Mask_FileName )
1455 if ( pItemImpl->cDriveString[0] == '\\' && pItemImpl->cDriveString[1] == '\\' )
1457 LPCWSTR lpFirstBkSlash = wcschr( &pItemImpl->cDriveString[2], '\\' );
1459 if ( lpFirstBkSlash && lpFirstBkSlash[1] )
1461 LPCWSTR lpLastBkSlash = wcschr( &lpFirstBkSlash[1], '\\' );
1463 if ( lpLastBkSlash )
1464 rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, o3tl::toU(&lpFirstBkSlash[1]), lpLastBkSlash - lpFirstBkSlash - 1 );
1465 else
1466 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(&lpFirstBkSlash[1]) );
1467 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1470 else switch ( GetDriveTypeW( cRoot ) )
1472 case DRIVE_REMOTE:
1474 WCHAR szBuffer[1024];
1475 DWORD const dwBufsizeConst = SAL_N_ELEMENTS(szBuffer);
1476 DWORD dwBufsize = dwBufsizeConst;
1478 DWORD dwResult = WNetGetConnectionW( cDrive, szBuffer, &dwBufsize );
1479 if ( NO_ERROR == dwResult )
1481 WCHAR szFileName[dwBufsizeConst + 16];
1483 swprintf( szFileName, L"%s [%s]", cDrive, szBuffer );
1484 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(szFileName) );
1486 else
1487 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cDrive) );
1489 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1490 break;
1491 case DRIVE_FIXED:
1493 WCHAR szVolumeNameBuffer[1024];
1494 DWORD const dwBufsizeConst = SAL_N_ELEMENTS(szVolumeNameBuffer);
1496 if ( GetVolumeInformationW( cRoot, szVolumeNameBuffer, dwBufsizeConst, nullptr, nullptr, nullptr, nullptr, 0 ) )
1498 WCHAR szFileName[dwBufsizeConst + 16];
1500 swprintf( szFileName, L"%s [%s]", cDrive, szVolumeNameBuffer );
1501 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(szFileName) );
1503 else
1504 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cDrive) );
1506 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1507 break;
1508 case DRIVE_CDROM:
1509 case DRIVE_REMOVABLE:
1510 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1511 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cRoot) );
1512 break;
1513 case DRIVE_UNKNOWN:
1514 default:
1515 break;
1519 pStatus->eType = osl_File_Type_Volume;
1520 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1522 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1524 rtl_uString *ustrSystemPath = nullptr;
1526 rtl_uString_newFromStr( &ustrSystemPath, o3tl::toU(pItemImpl->cDriveString) );
1527 oslFileError error = osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL );
1528 rtl_uString_release( ustrSystemPath );
1529 if (error != osl_File_E_None)
1530 return error;
1531 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1533 return osl_File_E_None;
1536 static oslFileError osl_getServerInfo(
1537 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask )
1539 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1540 if ( !pItemImpl )
1541 return osl_File_E_INVAL;
1543 pStatus->uValidFields = 0;
1544 pStatus->eType = osl_File_Type_Directory;
1545 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1547 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1549 oslFileError error = osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL );
1550 if (error != osl_File_E_None)
1551 return error;
1552 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1554 return osl_File_E_None;
1557 oslFileError SAL_CALL osl_getFileStatus(
1558 oslDirectoryItem Item,
1559 oslFileStatus *pStatus,
1560 sal_uInt32 uFieldMask )
1562 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1564 if ( !pItemImpl )
1565 return osl_File_E_INVAL;
1567 switch ( pItemImpl->uType )
1569 case DIRECTORYITEM_DRIVE:
1570 return osl_getDriveInfo( Item, pStatus, uFieldMask );
1571 case DIRECTORYITEM_SERVER:
1572 return osl_getServerInfo( Item, pStatus, uFieldMask );
1573 default:
1574 break;
1577 OUString sFullPath(pItemImpl->m_pFullPath);
1579 // Prefix long paths, windows API calls expect this prefix
1580 // (only local paths starting with something like C: or D:)
1581 if (sFullPath.getLength() >= MAX_PATH && isalpha(sFullPath[0]) && sFullPath[1] == ':')
1582 sFullPath = "\\\\?\\" + sFullPath;
1584 if ( uFieldMask & osl_FileStatus_Mask_Validate )
1586 HANDLE hFind = FindFirstFileW( o3tl::toW(sFullPath.getStr() ), &pItemImpl->FindData );
1588 if ( hFind != INVALID_HANDLE_VALUE )
1589 FindClose( hFind );
1590 else
1591 return oslTranslateFileError( GetLastError() );
1593 uFieldMask &= ~ osl_FileStatus_Mask_Validate;
1596 /* If no fields to retrieve left ignore pStatus */
1597 if ( !uFieldMask )
1598 return osl_File_E_None;
1600 /* Otherwise, this must be a valid pointer */
1601 if ( !pStatus )
1602 return osl_File_E_INVAL;
1604 if ( pStatus->uStructSize != sizeof(oslFileStatus) )
1605 return osl_File_E_INVAL;
1607 pStatus->uValidFields = 0;
1609 /* File time stamps */
1611 if ( (uFieldMask & osl_FileStatus_Mask_ModifyTime) &&
1612 FileTimeToTimeValue( &pItemImpl->FindData.ftLastWriteTime, &pStatus->aModifyTime ) )
1613 pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime;
1615 if ( (uFieldMask & osl_FileStatus_Mask_AccessTime) &&
1616 FileTimeToTimeValue( &pItemImpl->FindData.ftLastAccessTime, &pStatus->aAccessTime ) )
1617 pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime;
1619 if ( (uFieldMask & osl_FileStatus_Mask_CreationTime) &&
1620 FileTimeToTimeValue( &pItemImpl->FindData.ftCreationTime, &pStatus->aCreationTime ) )
1621 pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime;
1623 /* Most of the fields are already set, regardless of required fields */
1625 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(pItemImpl->FindData.cFileName) );
1626 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1628 if ((FILE_ATTRIBUTE_REPARSE_POINT & pItemImpl->FindData.dwFileAttributes) &&
1629 (IO_REPARSE_TAG_MOUNT_POINT == pItemImpl->FindData.dwReserved0))
1630 pStatus->eType = osl_File_Type_Volume;
1631 else if (pItemImpl->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1632 pStatus->eType = osl_File_Type_Directory;
1633 else
1634 pStatus->eType = osl_File_Type_Regular;
1636 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1638 pStatus->uAttributes = pItemImpl->FindData.dwFileAttributes;
1639 pStatus->uValidFields |= osl_FileStatus_Mask_Attributes;
1641 pStatus->uFileSize = static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeLow) + (static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeHigh) << 32);
1642 pStatus->uValidFields |= osl_FileStatus_Mask_FileSize;
1644 if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL )
1646 oslFileError error = osl_getFileURLFromSystemPath( sFullPath.pData, &pStatus->ustrLinkTargetURL );
1647 if (error != osl_File_E_None)
1648 return error;
1650 pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
1653 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1655 if ( !pItemImpl->bFullPathNormalized )
1657 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
1658 sal_uInt32 nNewLen = GetCaseCorrectPathName( o3tl::toW( sFullPath.getStr() ),
1659 o3tl::toW( aBuffer ),
1660 aBuffer.getBufSizeInSymbols(),
1661 true );
1663 if ( nNewLen )
1665 rtl_uString_newFromStr( &pItemImpl->m_pFullPath, aBuffer );
1666 sFullPath = OUString( pItemImpl->m_pFullPath );
1667 pItemImpl->bFullPathNormalized = TRUE;
1671 oslFileError error = osl_getFileURLFromSystemPath( sFullPath.pData, &pStatus->ustrFileURL );
1672 if (error != osl_File_E_None)
1673 return error;
1674 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1677 return osl_File_E_None;
1680 oslFileError SAL_CALL osl_setFileAttributes(
1681 rtl_uString *ustrFileURL,
1682 sal_uInt64 uAttributes )
1684 oslFileError error;
1685 rtl_uString *ustrSysPath = nullptr;
1686 DWORD dwFileAttributes;
1687 BOOL fSuccess;
1689 // Converts the normalized path into a systempath
1690 error = osl_getSystemPathFromFileURL_( ustrFileURL, &ustrSysPath, false );
1692 if ( osl_File_E_None != error )
1693 return error;
1695 dwFileAttributes = GetFileAttributesW( o3tl::toW(rtl_uString_getStr(ustrSysPath)) );
1697 if ( DWORD(-1) != dwFileAttributes )
1699 dwFileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
1701 if ( uAttributes & osl_File_Attribute_ReadOnly )
1702 dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1704 if ( uAttributes & osl_File_Attribute_Hidden )
1705 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1707 fSuccess = SetFileAttributesW( o3tl::toW(rtl_uString_getStr(ustrSysPath)), dwFileAttributes );
1709 else
1711 fSuccess = FALSE;
1714 if ( !fSuccess )
1715 error = oslTranslateFileError( GetLastError() );
1717 rtl_uString_release( ustrSysPath );
1719 return error;
1722 oslFileError SAL_CALL osl_setFileTime(
1723 rtl_uString *filePath,
1724 const TimeValue *aCreationTime,
1725 const TimeValue *aLastAccessTime,
1726 const TimeValue *aLastWriteTime)
1728 oslFileError error;
1729 rtl_uString *sysPath=nullptr;
1730 FILETIME *lpCreationTime=nullptr;
1731 FILETIME *lpLastAccessTime=nullptr;
1732 FILETIME *lpLastWriteTime=nullptr;
1733 FILETIME ftCreationTime;
1734 FILETIME ftLastAccessTime;
1735 FILETIME ftLastWriteTime;
1736 HANDLE hFile;
1737 BOOL fSuccess;
1739 error=osl_getSystemPathFromFileURL_(filePath, &sysPath, false);
1741 if (error==osl_File_E_INVAL)
1742 return error;
1744 hFile=CreateFileW(o3tl::toW(rtl_uString_getStr(sysPath)), GENERIC_WRITE, 0, nullptr , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
1745 rtl_uString_release(sysPath);
1747 if (hFile==INVALID_HANDLE_VALUE)
1748 return osl_File_E_NOENT;
1750 if (TimeValueToFileTime(aCreationTime, &ftCreationTime))
1751 lpCreationTime=&ftCreationTime;
1753 if (TimeValueToFileTime(aLastAccessTime, &ftLastAccessTime))
1754 lpLastAccessTime=&ftLastAccessTime;
1756 if (TimeValueToFileTime(aLastWriteTime, &ftLastWriteTime))
1757 lpLastWriteTime=&ftLastWriteTime;
1759 fSuccess=SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
1761 CloseHandle(hFile);
1763 if (!fSuccess)
1764 return osl_File_E_INVAL;
1765 else
1766 return osl_File_E_None;
1769 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */