Branch libreoffice-6-3
[LibreOffice.git] / sal / osl / w32 / file_dirvol.cxx
blob36a4b5d4013db15975b7eb2cc3e2af4c40352c5a
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 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 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 ) ) );
348 assert(szFileMask); // Don't handle OOM conditions
349 wcscpy( szFileMask, o3tl::toW(rtl_uString_getStr( pPath )) );
350 wcscat( szFileMask, pSuffix );
352 pDirectory = static_cast<LPDIRECTORY>(HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY)));
353 assert(pDirectory); // Don't handle OOM conditions
354 pDirectory->hFind = FindFirstFileW(szFileMask, &pDirectory->aFirstData);
356 if (!IsValidHandle(pDirectory->hFind))
358 if ( GetLastError() != ERROR_NO_MORE_FILES )
360 HeapFree(GetProcessHeap(), 0, pDirectory);
361 pDirectory = nullptr;
364 free(szFileMask);
368 return static_cast<HANDLE>(pDirectory);
371 static BOOL WINAPI EnumDirectory(HANDLE hDirectory, LPWIN32_FIND_DATAW pFindData)
373 BOOL fSuccess = FALSE;
374 LPDIRECTORY pDirectory = static_cast<LPDIRECTORY>(hDirectory);
376 if ( pDirectory )
378 BOOL fValid;
382 if ( pDirectory->aFirstData.cFileName[0] )
384 *pFindData = pDirectory->aFirstData;
385 fSuccess = TRUE;
386 pDirectory->aFirstData.cFileName[0] = 0;
388 else if ( IsValidHandle( pDirectory->hFind ) )
389 fSuccess = FindNextFileW( pDirectory->hFind, pFindData );
390 else
392 fSuccess = FALSE;
393 SetLastError( ERROR_NO_MORE_FILES );
396 fValid = fSuccess && wcscmp( L".", pFindData->cFileName ) != 0 && wcscmp( L"..", pFindData->cFileName ) != 0;
398 } while( fSuccess && !fValid );
400 else
401 SetLastError( ERROR_INVALID_HANDLE );
403 return fSuccess;
406 static BOOL WINAPI CloseDirectory(HANDLE hDirectory)
408 BOOL fSuccess = FALSE;
409 LPDIRECTORY pDirectory = static_cast<LPDIRECTORY>(hDirectory);
411 if (pDirectory)
413 if (IsValidHandle(pDirectory->hFind))
414 fSuccess = FindClose(pDirectory->hFind);
416 fSuccess = HeapFree(GetProcessHeap(), 0, pDirectory) && fSuccess;
418 else
419 SetLastError(ERROR_INVALID_HANDLE);
421 return fSuccess;
424 static oslFileError osl_openLocalRoot(
425 rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
427 rtl_uString *strSysPath = nullptr;
428 oslFileError error;
430 if ( !pDirectory )
431 return osl_File_E_INVAL;
433 *pDirectory = nullptr;
435 error = osl_getSystemPathFromFileURL_( strDirectoryPath, &strSysPath, false );
436 if ( osl_File_E_None == error )
438 Directory_Impl *pDirImpl;
440 pDirImpl = static_cast<Directory_Impl*>(malloc( sizeof(Directory_Impl)));
441 assert(pDirImpl); // Don't handle OOM conditions
442 ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
443 rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strSysPath );
445 /* Append backslash if necessary */
447 /* @@@ToDo
448 use function ensure backslash
450 sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
451 if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
453 rtl_uString* pCurDir = nullptr;
454 rtl_uString* pBackSlash = nullptr;
456 rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
457 rtl_uString_newFromAscii( &pBackSlash, "\\" );
458 rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
459 rtl_uString_release( pBackSlash );
460 rtl_uString_release( pCurDir );
463 pDirImpl->uType = DIRECTORYTYPE_LOCALROOT;
464 pDirImpl->hEnumDrives = OpenLogicalDrivesEnum();
466 /* @@@ToDo
467 Use IsValidHandle(...)
469 if ( pDirImpl->hEnumDrives != INVALID_HANDLE_VALUE )
471 *pDirectory = static_cast<oslDirectory>(pDirImpl);
472 error = osl_File_E_None;
474 else
476 if ( pDirImpl )
478 if ( pDirImpl->m_pDirectoryPath )
480 rtl_uString_release( pDirImpl->m_pDirectoryPath );
481 pDirImpl->m_pDirectoryPath = nullptr;
484 free(pDirImpl);
485 pDirImpl = nullptr;
488 error = oslTranslateFileError( GetLastError() );
491 rtl_uString_release( strSysPath );
493 return error;
496 static oslFileError osl_openFileDirectory(
497 rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
499 oslFileError error = osl_File_E_None;
501 if ( !pDirectory )
502 return osl_File_E_INVAL;
503 *pDirectory = nullptr;
505 Directory_Impl *pDirImpl = static_cast<Directory_Impl*>(malloc(sizeof(Directory_Impl)));
506 assert(pDirImpl); // Don't handle OOM conditions
507 ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
508 rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strDirectoryPath );
510 /* Append backslash if necessary */
512 /* @@@ToDo
513 use function ensure backslash
515 sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
516 if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
518 rtl_uString* pCurDir = nullptr;
519 rtl_uString* pBackSlash = nullptr;
521 rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
522 rtl_uString_newFromAscii( &pBackSlash, "\\" );
523 rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
524 rtl_uString_release( pBackSlash );
525 rtl_uString_release( pCurDir );
528 pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM;
529 pDirImpl->hDirectory = OpenDirectory( pDirImpl->m_pDirectoryPath );
531 if ( !pDirImpl->hDirectory )
533 error = oslTranslateFileError( GetLastError() );
535 if ( pDirImpl->m_pDirectoryPath )
537 rtl_uString_release( pDirImpl->m_pDirectoryPath );
538 pDirImpl->m_pDirectoryPath = nullptr;
541 free(pDirImpl);
542 pDirImpl = nullptr;
545 *pDirectory = static_cast<oslDirectory>(pDirImpl);
546 return error;
549 static oslFileError osl_openNetworkServer(
550 rtl_uString *strSysDirPath, oslDirectory *pDirectory)
552 NETRESOURCEW aNetResource;
553 HANDLE hEnum;
554 DWORD dwError;
556 ZeroMemory( &aNetResource, sizeof(aNetResource) );
558 aNetResource.lpRemoteName = o3tl::toW(strSysDirPath->buffer);
560 dwError = WNetOpenEnumW(
561 RESOURCE_GLOBALNET,
562 RESOURCETYPE_DISK,
563 RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER,
564 &aNetResource,
565 &hEnum );
567 if ( ERROR_SUCCESS == dwError )
569 Directory_Impl *pDirImpl;
571 pDirImpl = static_cast<Directory_Impl*>(malloc(sizeof(Directory_Impl)));
572 assert(pDirImpl); // Don't handle OOM conditions
573 ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
574 pDirImpl->uType = DIRECTORYTYPE_NETROOT;
575 pDirImpl->hDirectory = hEnum;
576 *pDirectory = static_cast<oslDirectory>(pDirImpl);
578 return oslTranslateFileError( dwError );
581 static DWORD create_dir_with_callback(
582 rtl_uString * dir_path,
583 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
584 void* pData)
586 // Create the specified directory and call the
587 // user specified callback function. On success
588 // the function returns ERROR_SUCCESS else a Win32 error code.
590 BOOL bCreated = CreateDirectoryW( o3tl::toW(rtl_uString_getStr( dir_path )), nullptr );
592 if ( bCreated )
594 if (aDirectoryCreationCallbackFunc)
596 OUString url;
597 osl_getFileURLFromSystemPath(dir_path, &(url.pData));
598 aDirectoryCreationCallbackFunc(pData, url.pData);
600 return ERROR_SUCCESS;
602 return GetLastError();
605 static int path_make_parent(sal_Unicode* path)
607 /* Cut off the last part of the given path to
608 get the parent only, e.g. 'c:\dir\subdir' ->
609 'c:\dir' or '\\share\sub\dir' -> '\\share\sub'
610 @return The position where the path has been cut
611 off (this is the position of the last backslash).
612 If there are no more parents 0 will be returned,
613 e.g. 'c:\' or '\\Share' have no more parents */
615 OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) == -1, "Path must not contain slashes");
616 OSL_PRECOND(has_path_parent(path), "Path must have a parent");
618 sal_Unicode* pos_last_backslash = path + rtl_ustr_lastIndexOfChar(path, BACKSLASH);
619 *pos_last_backslash = 0;
620 return (pos_last_backslash - path);
623 static DWORD create_dir_recursively_(
624 rtl_uString * dir_path,
625 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
626 void* pData)
628 OSL_PRECOND(
629 rtl_ustr_lastIndexOfChar_WithLength(dir_path->buffer, dir_path->length, BACKSLASH) != dir_path->length,
630 "Path must not end with a backslash");
632 DWORD w32_error = create_dir_with_callback(
633 dir_path, aDirectoryCreationCallbackFunc, pData);
634 if (w32_error == ERROR_SUCCESS)
635 return ERROR_SUCCESS;
637 if ((w32_error != ERROR_PATH_NOT_FOUND) || !has_path_parent(dir_path->buffer))
638 return w32_error;
640 int pos = path_make_parent(dir_path->buffer); // dir_path->buffer[pos] = 0, restore below
642 w32_error = create_dir_recursively_(
643 dir_path, aDirectoryCreationCallbackFunc, pData);
645 dir_path->buffer[pos] = BACKSLASH; // restore
647 if (ERROR_SUCCESS != w32_error && ERROR_ALREADY_EXISTS != w32_error)
648 return w32_error;
650 return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
653 oslFileError SAL_CALL osl_createDirectoryPath(
654 rtl_uString* aDirectoryUrl,
655 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
656 void* pData)
658 if (aDirectoryUrl == nullptr)
659 return osl_File_E_INVAL;
661 OUString sys_path;
662 oslFileError osl_error =
663 osl_getSystemPathFromFileURL_(aDirectoryUrl, &sys_path.pData, false);
665 if (osl_error != osl_File_E_None)
666 return osl_error;
668 osl::systemPathRemoveSeparator(sys_path);
670 // const_cast because sys_path is a local copy
671 // which we want to modify inplace instead of
672 // copy it into another buffer on the heap again
673 return oslTranslateFileError(create_dir_recursively_(
674 sys_path.pData, aDirectoryCreationCallbackFunc, pData));
677 oslFileError SAL_CALL osl_createDirectory(rtl_uString* strPath)
679 return osl_createDirectoryWithFlags(
680 strPath, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write);
683 oslFileError osl_createDirectoryWithFlags(rtl_uString * strPath, sal_uInt32)
685 rtl_uString *strSysPath = nullptr;
686 oslFileError error = osl_getSystemPathFromFileURL_( strPath, &strSysPath, false );
688 if ( osl_File_E_None == error )
690 BOOL bCreated = CreateDirectoryW( o3tl::toW(rtl_uString_getStr( strSysPath )), nullptr );
692 if ( !bCreated )
694 /*@@@ToDo
695 The following case is a hack because the ucb or the webtop had some
696 problems with the error code that CreateDirectory returns in
697 case the path is only a logical drive, should be removed!
700 const sal_Unicode *pBuffer = rtl_uString_getStr( strSysPath );
701 sal_Int32 nLen = rtl_uString_getLength( strSysPath );
703 if (
704 ( ( pBuffer[0] >= 'A' && pBuffer[0] <= 'Z' ) ||
705 ( pBuffer[0] >= 'a' && pBuffer[0] <= 'z' ) ) &&
706 pBuffer[1] == ':' && ( nLen ==2 || ( nLen == 3 && pBuffer[2] == '\\' ) )
708 SetLastError( ERROR_ALREADY_EXISTS );
710 error = oslTranslateFileError( GetLastError() );
713 rtl_uString_release( strSysPath );
715 return error;
718 oslFileError SAL_CALL osl_removeDirectory(rtl_uString* strPath)
720 rtl_uString *strSysPath = nullptr;
721 oslFileError error = osl_getSystemPathFromFileURL_( strPath, &strSysPath, false );
723 if ( osl_File_E_None == error )
725 if ( RemoveDirectoryW( o3tl::toW(rtl_uString_getStr( strSysPath ) )) )
726 error = osl_File_E_None;
727 else
728 error = oslTranslateFileError( GetLastError() );
730 rtl_uString_release( strSysPath );
732 return error;
735 oslFileError SAL_CALL osl_openDirectory(rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
737 oslFileError error;
739 if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath->buffer, "file:///" ) )
740 error = osl_openLocalRoot( strDirectoryPath, pDirectory );
741 else
743 rtl_uString *strSysDirectoryPath = nullptr;
744 DWORD dwPathType;
746 error = osl_getSystemPathFromFileURL_( strDirectoryPath, &strSysDirectoryPath, false );
748 if ( osl_File_E_None != error )
749 return error;
751 dwPathType = IsValidFilePath( strSysDirectoryPath, VALIDATEPATH_NORMAL, nullptr );
753 if ( dwPathType & PATHTYPE_IS_SERVER )
755 error = osl_openNetworkServer( strSysDirectoryPath, pDirectory );
757 else
758 error = osl_openFileDirectory( strSysDirectoryPath, pDirectory );
760 rtl_uString_release( strSysDirectoryPath );
762 return error;
765 static oslFileError osl_getNextNetResource(
766 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/ )
768 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
769 DirectoryItem_Impl *pItemImpl = nullptr;
770 BYTE buffer[16384];
771 LPNETRESOURCEW lpNetResource = reinterpret_cast<LPNETRESOURCEW>(buffer);
772 DWORD dwError, dwCount, dwBufSize;
774 if ( !pItem )
775 return osl_File_E_INVAL;
776 *pItem = nullptr;
778 if ( !pDirImpl )
779 return osl_File_E_INVAL;
781 dwCount = 1;
782 dwBufSize = sizeof(buffer);
783 dwError = WNetEnumResourceW( pDirImpl->hDirectory, &dwCount, lpNetResource, &dwBufSize );
785 switch ( dwError )
787 case NO_ERROR:
788 case ERROR_MORE_DATA:
790 pItemImpl = static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
791 if ( !pItemImpl )
792 return osl_File_E_NOMEM;
794 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
795 pItemImpl->uType = DIRECTORYITEM_DRIVE;
796 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
798 wcscpy( pItemImpl->cDriveString, lpNetResource->lpRemoteName );
800 *pItem = pItemImpl;
802 return osl_File_E_None;
803 case ERROR_NO_MORE_ITEMS:
804 return osl_File_E_NOENT;
805 default:
806 return oslTranslateFileError( dwError );
810 static oslFileError osl_getNextDrive(
811 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/ )
813 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
814 DirectoryItem_Impl *pItemImpl = nullptr;
815 BOOL fSuccess;
817 if ( !pItem )
818 return osl_File_E_INVAL;
819 *pItem = nullptr;
821 if ( !pDirImpl )
822 return osl_File_E_INVAL;
824 pItemImpl = static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
825 if ( !pItemImpl )
826 return osl_File_E_NOMEM;
828 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
829 pItemImpl->uType = DIRECTORYITEM_DRIVE;
830 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
831 fSuccess = EnumLogicalDrives( pDirImpl->hEnumDrives, pItemImpl->cDriveString );
833 if ( fSuccess )
835 *pItem = pItemImpl;
836 return osl_File_E_None;
838 else
840 if ( pItemImpl->m_pFullPath )
842 rtl_uString_release( pItemImpl->m_pFullPath );
843 pItemImpl->m_pFullPath = nullptr;
846 free( pItemImpl );
847 return oslTranslateFileError( GetLastError() );
851 static oslFileError osl_getNextFileItem(
852 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/)
854 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
855 DirectoryItem_Impl *pItemImpl = nullptr;
856 BOOL fFound;
858 if ( !pItem )
859 return osl_File_E_INVAL;
860 *pItem = nullptr;
862 if ( !pDirImpl )
863 return osl_File_E_INVAL;
865 pItemImpl = static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
866 if ( !pItemImpl )
867 return osl_File_E_NOMEM;
869 memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
870 fFound = EnumDirectory( pDirImpl->hDirectory, &pItemImpl->FindData );
872 if ( fFound )
874 pItemImpl->uType = DIRECTORYITEM_FILE;
875 pItemImpl->nRefCount = 1;
877 rtl_uString* pTmpFileName = nullptr;
878 rtl_uString_newFromStr( &pTmpFileName, o3tl::toU(pItemImpl->FindData.cFileName) );
879 rtl_uString_newConcat( &pItemImpl->m_pFullPath, pDirImpl->m_pDirectoryPath, pTmpFileName );
880 rtl_uString_release( pTmpFileName );
882 pItemImpl->bFullPathNormalized = FALSE;
883 *pItem = static_cast<oslDirectoryItem>(pItemImpl);
884 return osl_File_E_None;
886 else
888 if ( pItemImpl->m_pFullPath )
890 rtl_uString_release( pItemImpl->m_pFullPath );
891 pItemImpl->m_pFullPath = nullptr;
894 free( pItemImpl );
895 return oslTranslateFileError( GetLastError() );
899 oslFileError SAL_CALL osl_getNextDirectoryItem(
900 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint)
902 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
904 /* Assume failure */
906 if ( !pItem )
907 return osl_File_E_INVAL;
908 *pItem = nullptr;
910 if ( !pDirImpl )
911 return osl_File_E_INVAL;
913 switch ( pDirImpl->uType )
915 case DIRECTORYTYPE_LOCALROOT:
916 return osl_getNextDrive( Directory, pItem, uHint );
917 case DIRECTORYTYPE_NETROOT:
918 return osl_getNextNetResource( Directory, pItem, uHint );
919 case DIRECTORYTYPE_FILESYSTEM:
920 return osl_getNextFileItem( Directory, pItem, uHint );
921 default:
922 return osl_File_E_INVAL;
926 oslFileError SAL_CALL osl_closeDirectory(oslDirectory Directory)
928 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
929 oslFileError eError = osl_File_E_INVAL;
931 if ( pDirImpl )
933 switch ( pDirImpl->uType )
935 case DIRECTORYTYPE_FILESYSTEM:
936 eError = CloseDirectory( pDirImpl->hDirectory ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
937 break;
938 case DIRECTORYTYPE_LOCALROOT:
939 eError = CloseLogicalDrivesEnum( pDirImpl->hEnumDrives ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
940 break;
941 case DIRECTORYTYPE_NETROOT:
943 DWORD err = WNetCloseEnum(pDirImpl->hDirectory);
944 eError = (err == NO_ERROR) ? osl_File_E_None : oslTranslateFileError(err);
946 break;
947 default:
948 OSL_FAIL( "Invalid directory type" );
949 break;
952 if ( pDirImpl->m_pDirectoryPath )
954 rtl_uString_release( pDirImpl->m_pDirectoryPath );
955 pDirImpl->m_pDirectoryPath = nullptr;
958 free(pDirImpl);
960 return eError;
963 /* Different types of paths */
964 enum PATHTYPE
966 PATHTYPE_SYNTAXERROR = 0,
967 PATHTYPE_NETROOT,
968 PATHTYPE_NETSERVER,
969 PATHTYPE_VOLUME,
970 PATHTYPE_FILE
973 oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString *strFilePath, oslDirectoryItem *pItem)
975 oslFileError error = osl_File_E_None;
976 rtl_uString* strSysFilePath = nullptr;
977 PATHTYPE type = PATHTYPE_FILE;
978 DWORD dwPathType;
980 /* Assume failure */
982 if ( !pItem )
983 return osl_File_E_INVAL;
985 *pItem = nullptr;
987 error = osl_getSystemPathFromFileURL_( strFilePath, &strSysFilePath, false );
989 if ( osl_File_E_None != error )
990 return error;
992 dwPathType = IsValidFilePath( strSysFilePath, VALIDATEPATH_NORMAL, nullptr );
994 if ( dwPathType & PATHTYPE_IS_VOLUME )
995 type = PATHTYPE_VOLUME;
996 else if ( dwPathType & PATHTYPE_IS_SERVER )
997 type = PATHTYPE_NETSERVER;
998 else
999 type = PATHTYPE_FILE;
1001 switch ( type )
1003 case PATHTYPE_NETSERVER:
1005 DirectoryItem_Impl* pItemImpl =
1006 static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
1008 if ( !pItemImpl )
1009 error = osl_File_E_NOMEM;
1011 if ( osl_File_E_None == error )
1013 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1014 pItemImpl->uType = DIRECTORYITEM_SERVER;
1016 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
1017 rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath );
1019 // Assign a title anyway
1021 int iSrc = 2;
1022 int iDst = 0;
1024 while( iSrc < strSysFilePath->length && strSysFilePath->buffer[iSrc] && strSysFilePath->buffer[iSrc] != '\\' )
1026 pItemImpl->FindData.cFileName[iDst++] = strSysFilePath->buffer[iSrc++];
1030 *pItem = pItemImpl;
1033 break;
1034 case PATHTYPE_VOLUME:
1036 DirectoryItem_Impl* pItemImpl =
1037 static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
1039 if ( !pItemImpl )
1040 error = osl_File_E_NOMEM;
1042 if ( osl_File_E_None == error )
1044 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1045 pItemImpl->uType = DIRECTORYITEM_DRIVE;
1047 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
1049 wcscpy( pItemImpl->cDriveString, o3tl::toW(strSysFilePath->buffer) );
1050 pItemImpl->cDriveString[0] = rtl::toAsciiUpperCase( pItemImpl->cDriveString[0] );
1052 if ( pItemImpl->cDriveString[wcslen(pItemImpl->cDriveString) - 1] != '\\' )
1053 wcscat( pItemImpl->cDriveString, L"\\" );
1055 *pItem = pItemImpl;
1058 break;
1059 case PATHTYPE_SYNTAXERROR:
1060 case PATHTYPE_NETROOT:
1061 case PATHTYPE_FILE:
1063 HANDLE hFind;
1064 WIN32_FIND_DATAW aFindData;
1066 if ( strSysFilePath->length > 0 && strSysFilePath->buffer[strSysFilePath->length - 1] == '\\' )
1067 rtl_uString_newFromStr_WithLength( &strSysFilePath, strSysFilePath->buffer, strSysFilePath->length - 1 );
1069 hFind = FindFirstFileW( o3tl::toW(rtl_uString_getStr(strSysFilePath)), &aFindData );
1071 if ( hFind != INVALID_HANDLE_VALUE )
1073 DirectoryItem_Impl *pItemImpl =
1074 static_cast<DirectoryItem_Impl*>(malloc(sizeof(DirectoryItem_Impl)));
1075 if (!pItemImpl)
1076 error = osl_File_E_NOMEM;
1078 if (osl_File_E_None == error)
1080 ZeroMemory(pItemImpl, sizeof(DirectoryItem_Impl));
1081 osl_acquireDirectoryItem(static_cast<oslDirectoryItem>(pItemImpl));
1083 CopyMemory(&pItemImpl->FindData, &aFindData, sizeof(WIN32_FIND_DATAW));
1084 rtl_uString_newFromString(&pItemImpl->m_pFullPath, strSysFilePath);
1086 // MT: This costs 600ms startup time on fast v60x!
1087 // GetCaseCorrectPathName( pItemImpl->szFullPath, pItemImpl->szFullPath, sizeof(pItemImpl->szFullPath) );
1089 pItemImpl->uType = DIRECTORYITEM_FILE;
1090 *pItem = pItemImpl;
1093 FindClose( hFind );
1095 else
1096 error = oslTranslateFileError( GetLastError() );
1098 break;
1101 if ( strSysFilePath )
1102 rtl_uString_release( strSysFilePath );
1104 return error;
1107 oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item )
1109 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1111 if ( !pItemImpl )
1112 return osl_File_E_INVAL;
1114 pItemImpl->nRefCount++;
1115 return osl_File_E_None;
1118 oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
1120 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1122 if ( !pItemImpl )
1123 return osl_File_E_INVAL;
1125 if ( ! --pItemImpl->nRefCount )
1127 if ( pItemImpl->m_pFullPath )
1129 rtl_uString_release( pItemImpl->m_pFullPath );
1130 pItemImpl->m_pFullPath = nullptr;
1133 free( pItemImpl );
1136 return osl_File_E_None;
1139 sal_Bool
1140 SAL_CALL osl_identicalDirectoryItem( oslDirectoryItem a, oslDirectoryItem b)
1142 DirectoryItem_Impl *pA = static_cast<DirectoryItem_Impl *>(a);
1143 DirectoryItem_Impl *pB = static_cast<DirectoryItem_Impl *>(b);
1144 if (a == b)
1145 return true;
1146 /* same name => same item, unless renaming / moving madness has occurred */
1147 if (pA->m_pFullPath == pB->m_pFullPath)
1148 return true;
1150 // FIXME: as/when/if this is used in anger on Windows we could
1151 // do better here.
1153 return false;
1156 static bool is_floppy_A_present()
1157 { return (GetLogicalDrives() & 1); }
1159 static bool is_floppy_B_present()
1160 { return (GetLogicalDrives() & 2); }
1162 static bool is_floppy_volume_mount_point(const OUString& path)
1164 // determines if a volume mount point shows to a floppy
1165 // disk by comparing the unique volume names
1166 static const LPCWSTR FLOPPY_A = L"A:\\";
1167 static const LPCWSTR FLOPPY_B = L"B:\\";
1169 OUString p(path);
1170 osl::systemPathEnsureSeparator(p);
1172 WCHAR vn[51];
1173 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p.getStr()), vn, SAL_N_ELEMENTS(vn)))
1175 WCHAR vnfloppy[51];
1176 if (is_floppy_A_present() &&
1177 GetVolumeNameForVolumeMountPointW(FLOPPY_A, vnfloppy, SAL_N_ELEMENTS(vnfloppy)) &&
1178 (0 == wcscmp(vn, vnfloppy)))
1179 return true;
1181 if (is_floppy_B_present() &&
1182 GetVolumeNameForVolumeMountPointW(FLOPPY_B, vnfloppy, SAL_N_ELEMENTS(vnfloppy)) &&
1183 (0 == wcscmp(vn, vnfloppy)))
1184 return true;
1186 return false;
1189 static bool is_floppy_drive(const OUString& path)
1191 static const LPCWSTR FLOPPY_DRV_LETTERS = L"AaBb";
1193 // we must take into account that even a floppy
1194 // drive may be mounted to a directory so checking
1195 // for the drive letter alone is not sufficient
1196 // we must compare the unique volume name with
1197 // that of the available floppy disks
1199 const sal_Unicode* pszPath = path.getStr();
1200 return ((wcschr(FLOPPY_DRV_LETTERS, pszPath[0]) && (L':' == pszPath[1])) || is_floppy_volume_mount_point(path));
1203 static bool is_volume_mount_point(const OUString& path)
1205 OUString p(path);
1206 osl::systemPathRemoveSeparator(p);
1208 bool is_volume_root = false;
1210 if (!is_floppy_drive(p))
1212 DWORD fattr = GetFileAttributesW(o3tl::toW(p.getStr()));
1214 if ((INVALID_FILE_ATTRIBUTES != fattr) &&
1215 (FILE_ATTRIBUTE_REPARSE_POINT & fattr))
1217 WIN32_FIND_DATAW find_data;
1218 HANDLE h_find = FindFirstFileW(o3tl::toW(p.getStr()), &find_data);
1220 if (IsValidHandle(h_find) &&
1221 (FILE_ATTRIBUTE_REPARSE_POINT & find_data.dwFileAttributes) &&
1222 (IO_REPARSE_TAG_MOUNT_POINT == find_data.dwReserved0))
1224 is_volume_root = true;
1226 if (IsValidHandle(h_find))
1227 FindClose(h_find);
1230 return is_volume_root;
1233 static UINT get_volume_mount_point_drive_type(const OUString& path)
1235 if (0 == path.getLength())
1236 return GetDriveTypeW(nullptr);
1238 OUString p(path);
1239 osl::systemPathEnsureSeparator(p);
1241 WCHAR vn[51];
1242 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p.getStr()), vn, SAL_N_ELEMENTS(vn)))
1243 return GetDriveTypeW(vn);
1245 return DRIVE_NO_ROOT_DIR;
1248 static bool is_drivetype_request(sal_uInt32 field_mask)
1250 return (field_mask & osl_VolumeInfo_Mask_Attributes);
1253 static oslFileError osl_get_drive_type(
1254 const OUString& path, oslVolumeInfo* pInfo)
1256 // GetDriveType fails on empty volume mount points
1257 // see Knowledge Base Q244089
1258 UINT drive_type;
1259 if (is_volume_mount_point(path))
1260 drive_type = get_volume_mount_point_drive_type(path);
1261 else
1262 drive_type = GetDriveTypeW(o3tl::toW(path.getStr()));
1264 if (DRIVE_NO_ROOT_DIR == drive_type)
1265 return oslTranslateFileError(ERROR_INVALID_DRIVE);
1267 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1269 switch (drive_type)
1271 case DRIVE_CDROM:
1272 pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable;
1273 break;
1274 case DRIVE_REMOVABLE:
1275 pInfo->uAttributes |= osl_Volume_Attribute_Removeable;
1276 if (is_floppy_drive(path))
1277 pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk;
1278 break;
1279 case DRIVE_FIXED:
1280 pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk;
1281 break;
1282 case DRIVE_RAMDISK:
1283 pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk;
1284 break;
1285 case DRIVE_REMOTE:
1286 pInfo->uAttributes |= osl_Volume_Attribute_Remote;
1287 break;
1288 case DRIVE_UNKNOWN:
1289 pInfo->uAttributes = 0;
1290 break;
1291 default:
1292 pInfo->uValidFields &= ~osl_VolumeInfo_Mask_Attributes;
1293 pInfo->uAttributes = 0;
1294 break;
1296 return osl_File_E_None;
1299 static bool is_volume_space_info_request(sal_uInt32 field_mask)
1301 return (field_mask &
1302 (osl_VolumeInfo_Mask_TotalSpace |
1303 osl_VolumeInfo_Mask_UsedSpace |
1304 osl_VolumeInfo_Mask_FreeSpace));
1307 static void get_volume_space_information(
1308 const OUString& path, oslVolumeInfo *pInfo)
1310 BOOL ret = GetDiskFreeSpaceExW(
1311 o3tl::toW(path.getStr()),
1312 reinterpret_cast<PULARGE_INTEGER>(&pInfo->uFreeSpace),
1313 reinterpret_cast<PULARGE_INTEGER>(&pInfo->uTotalSpace),
1314 nullptr);
1316 if (ret)
1318 pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace;
1319 pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace |
1320 osl_VolumeInfo_Mask_UsedSpace |
1321 osl_VolumeInfo_Mask_FreeSpace;
1325 static bool is_filesystem_attributes_request(sal_uInt32 field_mask)
1327 return (field_mask &
1328 (osl_VolumeInfo_Mask_MaxNameLength |
1329 osl_VolumeInfo_Mask_MaxPathLength |
1330 osl_VolumeInfo_Mask_FileSystemName |
1331 osl_VolumeInfo_Mask_FileSystemCaseHandling));
1334 static oslFileError get_filesystem_attributes(
1335 const OUString& path, sal_uInt32 field_mask, oslVolumeInfo* pInfo)
1337 pInfo->uAttributes = 0;
1339 // osl_get_drive_type must be called first because
1340 // this function resets osl_VolumeInfo_Mask_Attributes
1341 // on failure
1342 if (is_drivetype_request(field_mask))
1344 oslFileError osl_error = osl_get_drive_type(path, pInfo);
1345 if (osl_File_E_None != osl_error)
1346 return osl_error;
1348 if (is_filesystem_attributes_request(field_mask))
1350 /* the following two parameters can not be longer than MAX_PATH+1 */
1351 WCHAR vn[MAX_PATH+1];
1352 WCHAR fsn[MAX_PATH+1];
1354 DWORD serial;
1355 DWORD mcl;
1356 DWORD flags;
1358 LPCWSTR pszPath = o3tl::toW(path.getStr());
1359 if (GetVolumeInformationW(pszPath, vn, MAX_PATH+1, &serial, &mcl, &flags, fsn, MAX_PATH+1))
1361 // Currently sal does not use this value, instead MAX_PATH is used
1362 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength;
1363 pInfo->uMaxNameLength = mcl;
1365 // Should the uMaxPathLength be set to 32767, "\\?\" prefix allowes it
1366 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength;
1367 pInfo->uMaxPathLength = MAX_PATH;
1369 pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName;
1370 rtl_uString_newFromStr(&pInfo->ustrFileSystemName, o3tl::toU(fsn));
1372 // volumes (even NTFS) will always be considered case
1373 // insensitive because the Win32 API is not able to
1374 // deal with case sensitive volumes see M$ Knowledge Base
1375 // article 100625 that's why we never set the attribute
1376 // osl_Volume_Attribute_Case_Sensitive
1378 if (flags & FS_CASE_IS_PRESERVED)
1379 pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved;
1381 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1384 return osl_File_E_None;
1387 static bool path_get_parent(OUString& path)
1389 OSL_PRECOND(path.lastIndexOf(SLASH) == -1, "Path must not have slashes");
1391 if (!has_path_parent(path))
1393 sal_Int32 i = path.lastIndexOf(BACKSLASH);
1394 if (-1 < i)
1396 path = OUString(path.getStr(), i);
1397 return true;
1400 return false;
1403 static void path_travel_to_volume_root(const OUString& system_path, OUString& volume_root)
1405 OUString sys_path(system_path);
1407 while(!is_volume_mount_point(sys_path) && path_get_parent(sys_path))
1408 /**/;
1410 volume_root = sys_path;
1411 osl::systemPathEnsureSeparator(volume_root);
1414 oslFileError SAL_CALL osl_getVolumeInformation(
1415 rtl_uString *ustrURL, oslVolumeInfo *pInfo, sal_uInt32 uFieldMask )
1417 if (!pInfo)
1418 return osl_File_E_INVAL;
1420 OUString system_path;
1421 oslFileError error = osl_getSystemPathFromFileURL_(ustrURL, &system_path.pData, false);
1423 if (osl_File_E_None != error)
1424 return error;
1426 OUString volume_root;
1427 path_travel_to_volume_root(system_path, volume_root);
1429 pInfo->uValidFields = 0;
1431 if ((error = get_filesystem_attributes(volume_root, uFieldMask, pInfo)) != osl_File_E_None)
1432 return error;
1434 if (is_volume_space_info_request(uFieldMask))
1435 get_volume_space_information(volume_root, pInfo);
1437 if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle)
1439 error = osl_getFileURLFromSystemPath(volume_root.pData, reinterpret_cast<rtl_uString**>(&pInfo->pDeviceHandle));
1440 if (error != osl_File_E_None)
1441 return error;
1442 pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle;
1445 return osl_File_E_None;
1448 static oslFileError osl_getDriveInfo(
1449 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask)
1451 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1452 WCHAR cDrive[3] = L"A:";
1453 WCHAR cRoot[4] = L"A:\\";
1455 if ( !pItemImpl )
1456 return osl_File_E_INVAL;
1458 pStatus->uValidFields = 0;
1460 cDrive[0] = pItemImpl->cDriveString[0];
1461 cRoot[0] = pItemImpl->cDriveString[0];
1463 if ( uFieldMask & osl_FileStatus_Mask_FileName )
1465 if ( pItemImpl->cDriveString[0] == '\\' && pItemImpl->cDriveString[1] == '\\' )
1467 LPCWSTR lpFirstBkSlash = wcschr( &pItemImpl->cDriveString[2], '\\' );
1469 if ( lpFirstBkSlash && lpFirstBkSlash[1] )
1471 LPCWSTR lpLastBkSlash = wcschr( &lpFirstBkSlash[1], '\\' );
1473 if ( lpLastBkSlash )
1474 rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, o3tl::toU(&lpFirstBkSlash[1]), lpLastBkSlash - lpFirstBkSlash - 1 );
1475 else
1476 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(&lpFirstBkSlash[1]) );
1477 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1480 else switch ( GetDriveTypeW( cRoot ) )
1482 case DRIVE_REMOTE:
1484 WCHAR szBuffer[1024];
1485 DWORD const dwBufsizeConst = SAL_N_ELEMENTS(szBuffer);
1486 DWORD dwBufsize = dwBufsizeConst;
1488 DWORD dwResult = WNetGetConnectionW( cDrive, szBuffer, &dwBufsize );
1489 if ( NO_ERROR == dwResult )
1491 WCHAR szFileName[dwBufsizeConst + 16];
1493 swprintf( szFileName, L"%s [%s]", cDrive, szBuffer );
1494 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(szFileName) );
1496 else
1497 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cDrive) );
1499 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1500 break;
1501 case DRIVE_FIXED:
1503 WCHAR szVolumeNameBuffer[1024];
1504 DWORD const dwBufsizeConst = SAL_N_ELEMENTS(szVolumeNameBuffer);
1506 if ( GetVolumeInformationW( cRoot, szVolumeNameBuffer, dwBufsizeConst, nullptr, nullptr, nullptr, nullptr, 0 ) )
1508 WCHAR szFileName[dwBufsizeConst + 16];
1510 swprintf( szFileName, L"%s [%s]", cDrive, szVolumeNameBuffer );
1511 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(szFileName) );
1513 else
1514 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cDrive) );
1516 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1517 break;
1518 case DRIVE_CDROM:
1519 case DRIVE_REMOVABLE:
1520 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1521 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cRoot) );
1522 break;
1523 case DRIVE_UNKNOWN:
1524 default:
1525 break;
1529 pStatus->eType = osl_File_Type_Volume;
1530 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1532 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1534 rtl_uString *ustrSystemPath = nullptr;
1536 rtl_uString_newFromStr( &ustrSystemPath, o3tl::toU(pItemImpl->cDriveString) );
1537 oslFileError error = osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL );
1538 rtl_uString_release( ustrSystemPath );
1539 if (error != osl_File_E_None)
1540 return error;
1541 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1543 return osl_File_E_None;
1546 static oslFileError osl_getServerInfo(
1547 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask )
1549 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1550 if ( !pItemImpl )
1551 return osl_File_E_INVAL;
1553 pStatus->uValidFields = 0;
1554 pStatus->eType = osl_File_Type_Directory;
1555 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1557 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1559 oslFileError error = osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL );
1560 if (error != osl_File_E_None)
1561 return error;
1562 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1564 return osl_File_E_None;
1567 oslFileError SAL_CALL osl_getFileStatus(
1568 oslDirectoryItem Item,
1569 oslFileStatus *pStatus,
1570 sal_uInt32 uFieldMask )
1572 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1574 if ( !pItemImpl )
1575 return osl_File_E_INVAL;
1577 switch ( pItemImpl->uType )
1579 case DIRECTORYITEM_DRIVE:
1580 return osl_getDriveInfo( Item, pStatus, uFieldMask );
1581 case DIRECTORYITEM_SERVER:
1582 return osl_getServerInfo( Item, pStatus, uFieldMask );
1583 default:
1584 break;
1587 OUString sFullPath(pItemImpl->m_pFullPath);
1589 // Prefix long paths, windows API calls expect this prefix
1590 // (only local paths starting with something like C: or D:)
1591 if (sFullPath.getLength() >= MAX_PATH && isalpha(sFullPath[0]) && sFullPath[1] == ':')
1592 sFullPath = "\\\\?\\" + sFullPath;
1594 if ( uFieldMask & osl_FileStatus_Mask_Validate )
1596 HANDLE hFind = FindFirstFileW( o3tl::toW(sFullPath.getStr() ), &pItemImpl->FindData );
1598 if ( hFind != INVALID_HANDLE_VALUE )
1599 FindClose( hFind );
1600 else
1601 return oslTranslateFileError( GetLastError() );
1603 uFieldMask &= ~ osl_FileStatus_Mask_Validate;
1606 /* If no fields to retrieve left ignore pStatus */
1607 if ( !uFieldMask )
1608 return osl_File_E_None;
1610 /* Otherwise, this must be a valid pointer */
1611 if ( !pStatus )
1612 return osl_File_E_INVAL;
1614 if ( pStatus->uStructSize != sizeof(oslFileStatus) )
1615 return osl_File_E_INVAL;
1617 pStatus->uValidFields = 0;
1619 /* File time stamps */
1621 if ( (uFieldMask & osl_FileStatus_Mask_ModifyTime) &&
1622 FileTimeToTimeValue( &pItemImpl->FindData.ftLastWriteTime, &pStatus->aModifyTime ) )
1623 pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime;
1625 if ( (uFieldMask & osl_FileStatus_Mask_AccessTime) &&
1626 FileTimeToTimeValue( &pItemImpl->FindData.ftLastAccessTime, &pStatus->aAccessTime ) )
1627 pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime;
1629 if ( (uFieldMask & osl_FileStatus_Mask_CreationTime) &&
1630 FileTimeToTimeValue( &pItemImpl->FindData.ftCreationTime, &pStatus->aCreationTime ) )
1631 pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime;
1633 /* Most of the fields are already set, regardless of required fields */
1635 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(pItemImpl->FindData.cFileName) );
1636 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1638 if ((FILE_ATTRIBUTE_REPARSE_POINT & pItemImpl->FindData.dwFileAttributes) &&
1639 (IO_REPARSE_TAG_MOUNT_POINT == pItemImpl->FindData.dwReserved0))
1640 pStatus->eType = osl_File_Type_Volume;
1641 else if (pItemImpl->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1642 pStatus->eType = osl_File_Type_Directory;
1643 else
1644 pStatus->eType = osl_File_Type_Regular;
1646 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1648 pStatus->uAttributes = pItemImpl->FindData.dwFileAttributes;
1649 pStatus->uValidFields |= osl_FileStatus_Mask_Attributes;
1651 pStatus->uFileSize = static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeLow) + (static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeHigh) << 32);
1652 pStatus->uValidFields |= osl_FileStatus_Mask_FileSize;
1654 if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL )
1656 oslFileError error = osl_getFileURLFromSystemPath( sFullPath.pData, &pStatus->ustrLinkTargetURL );
1657 if (error != osl_File_E_None)
1658 return error;
1660 pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
1663 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1665 if ( !pItemImpl->bFullPathNormalized )
1667 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
1668 sal_uInt32 nNewLen = GetCaseCorrectPathName( o3tl::toW( sFullPath.getStr() ),
1669 o3tl::toW( aBuffer ),
1670 aBuffer.getBufSizeInSymbols(),
1671 true );
1673 if ( nNewLen )
1675 rtl_uString_newFromStr( &pItemImpl->m_pFullPath, aBuffer );
1676 sFullPath = OUString( pItemImpl->m_pFullPath );
1677 pItemImpl->bFullPathNormalized = TRUE;
1681 oslFileError error = osl_getFileURLFromSystemPath( sFullPath.pData, &pStatus->ustrFileURL );
1682 if (error != osl_File_E_None)
1683 return error;
1684 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1687 return osl_File_E_None;
1690 oslFileError SAL_CALL osl_setFileAttributes(
1691 rtl_uString *ustrFileURL,
1692 sal_uInt64 uAttributes )
1694 oslFileError error;
1695 rtl_uString *ustrSysPath = nullptr;
1696 DWORD dwFileAttributes;
1697 BOOL fSuccess;
1699 // Converts the normalized path into a systempath
1700 error = osl_getSystemPathFromFileURL_( ustrFileURL, &ustrSysPath, false );
1702 if ( osl_File_E_None != error )
1703 return error;
1705 dwFileAttributes = GetFileAttributesW( o3tl::toW(rtl_uString_getStr(ustrSysPath)) );
1707 if ( DWORD(-1) != dwFileAttributes )
1709 dwFileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
1711 if ( uAttributes & osl_File_Attribute_ReadOnly )
1712 dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1714 if ( uAttributes & osl_File_Attribute_Hidden )
1715 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1717 fSuccess = SetFileAttributesW( o3tl::toW(rtl_uString_getStr(ustrSysPath)), dwFileAttributes );
1719 else
1721 fSuccess = FALSE;
1724 if ( !fSuccess )
1725 error = oslTranslateFileError( GetLastError() );
1727 rtl_uString_release( ustrSysPath );
1729 return error;
1732 oslFileError SAL_CALL osl_setFileTime(
1733 rtl_uString *filePath,
1734 const TimeValue *aCreationTime,
1735 const TimeValue *aLastAccessTime,
1736 const TimeValue *aLastWriteTime)
1738 oslFileError error;
1739 rtl_uString *sysPath=nullptr;
1740 FILETIME *lpCreationTime=nullptr;
1741 FILETIME *lpLastAccessTime=nullptr;
1742 FILETIME *lpLastWriteTime=nullptr;
1743 FILETIME ftCreationTime;
1744 FILETIME ftLastAccessTime;
1745 FILETIME ftLastWriteTime;
1746 HANDLE hFile;
1747 BOOL fSuccess;
1749 error=osl_getSystemPathFromFileURL_(filePath, &sysPath, false);
1751 if (error==osl_File_E_INVAL)
1752 return error;
1754 hFile=CreateFileW(o3tl::toW(rtl_uString_getStr(sysPath)), GENERIC_WRITE, 0, nullptr , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
1755 rtl_uString_release(sysPath);
1757 if (hFile==INVALID_HANDLE_VALUE)
1758 return osl_File_E_NOENT;
1760 if (TimeValueToFileTime(aCreationTime, &ftCreationTime))
1761 lpCreationTime=&ftCreationTime;
1763 if (TimeValueToFileTime(aLastAccessTime, &ftLastAccessTime))
1764 lpLastAccessTime=&ftLastAccessTime;
1766 if (TimeValueToFileTime(aLastWriteTime, &ftLastWriteTime))
1767 lpLastWriteTime=&ftLastWriteTime;
1769 fSuccess=SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
1771 CloseHandle(hFile);
1773 if (!fSuccess)
1774 return osl_File_E_INVAL;
1775 else
1776 return osl_File_E_None;
1779 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */