Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sal / osl / w32 / file_dirvol.cxx
blobf9d821605e869be8ca73481ca12af2783771d799
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 const wchar_t UNC_PREFIX[] = L"\\\\";
35 const wchar_t BACKSLASH = '\\';
36 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(OUString(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 namespace {
226 struct DirectoryItem_Impl
228 UINT uType = 0;
229 union {
230 WIN32_FIND_DATAW FindData;
231 WCHAR cDriveString[MAX_PATH];
233 OUString m_sFullPath;
234 bool bFullPathNormalized = false;
235 int nRefCount = 0;
240 #define DIRECTORYTYPE_LOCALROOT 0
241 #define DIRECTORYTYPE_NETROOT 1
242 #define DIRECTORYTYPE_FILESYSTEM 3
244 namespace {
246 struct Directory_Impl
248 UINT uType = 0;
249 union {
250 HANDLE hDirectory = nullptr;
251 HANDLE hEnumDrives;
253 OUString m_sDirectoryPath;
256 typedef struct tagDRIVEENUM
258 LPCWSTR lpIdent;
259 WCHAR cBuffer[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256];
260 LPCWSTR lpCurrent;
261 } DRIVEENUM, *PDRIVEENUM, *LPDRIVEENUM;
265 static HANDLE WINAPI OpenLogicalDrivesEnum()
267 LPDRIVEENUM pEnum = static_cast<LPDRIVEENUM>(HeapAlloc( GetProcessHeap(), 0, sizeof(DRIVEENUM) ));
268 if ( pEnum )
270 DWORD dwNumCopied = GetLogicalDriveStringsW( SAL_N_ELEMENTS(pEnum->cBuffer) - 1, pEnum->cBuffer );
272 if ( dwNumCopied && dwNumCopied < SAL_N_ELEMENTS(pEnum->cBuffer) )
274 pEnum->lpCurrent = pEnum->cBuffer;
275 pEnum->lpIdent = L"tagDRIVEENUM";
277 else
279 HeapFree( GetProcessHeap(), 0, pEnum );
280 pEnum = nullptr;
283 return pEnum ? static_cast<HANDLE>(pEnum) : INVALID_HANDLE_VALUE;
286 static bool WINAPI EnumLogicalDrives(HANDLE hEnum, LPWSTR lpBuffer)
288 LPDRIVEENUM pEnum = static_cast<LPDRIVEENUM>(hEnum);
289 if ( !pEnum )
291 SetLastError( ERROR_INVALID_HANDLE );
292 return false;
295 int nLen = wcslen( pEnum->lpCurrent );
296 if ( !nLen )
298 SetLastError( ERROR_NO_MORE_FILES );
299 return false;
302 CopyMemory( lpBuffer, pEnum->lpCurrent, (nLen + 1) * sizeof(WCHAR) );
303 pEnum->lpCurrent += nLen + 1;
304 return true;
307 static bool WINAPI CloseLogicalDrivesEnum(HANDLE hEnum)
309 bool fSuccess = false;
310 LPDRIVEENUM pEnum = static_cast<LPDRIVEENUM>(hEnum);
312 if ( pEnum )
314 HeapFree( GetProcessHeap(), 0, pEnum );
315 fSuccess = true;
317 else
318 SetLastError( ERROR_INVALID_HANDLE );
320 return fSuccess;
323 namespace {
325 typedef struct tagDIRECTORY
327 HANDLE hFind;
328 WIN32_FIND_DATAW aFirstData;
329 } DIRECTORY, *PDIRECTORY, *LPDIRECTORY;
333 static HANDLE WINAPI OpenDirectory( rtl_uString* pPath)
335 if ( !pPath )
336 return nullptr;
338 sal_uInt32 nLen = rtl_uString_getLength( pPath );
339 if ( !nLen )
340 return nullptr;
342 const WCHAR* pSuffix = nullptr;
343 sal_uInt32 nSuffLen = 0;
344 if ( pPath->buffer[nLen - 1] != L'\\' )
346 pSuffix = L"\\*.*";
347 nSuffLen = 4;
349 else
351 pSuffix = L"*.*";
352 nSuffLen = 3;
355 WCHAR* szFileMask = static_cast< WCHAR* >( malloc( sizeof( WCHAR ) * ( nLen + nSuffLen + 1 ) ) );
356 assert(szFileMask); // Don't handle OOM conditions
357 wcscpy( szFileMask, o3tl::toW(rtl_uString_getStr( pPath )) );
358 wcscat( szFileMask, pSuffix );
360 LPDIRECTORY pDirectory = static_cast<LPDIRECTORY>(HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY)));
361 assert(pDirectory); // Don't handle OOM conditions
362 pDirectory->hFind = FindFirstFileW(szFileMask, &pDirectory->aFirstData);
364 if (!IsValidHandle(pDirectory->hFind))
366 if ( GetLastError() != ERROR_NO_MORE_FILES )
368 HeapFree(GetProcessHeap(), 0, pDirectory);
369 pDirectory = nullptr;
372 free(szFileMask);
374 return static_cast<HANDLE>(pDirectory);
377 static bool WINAPI EnumDirectory(HANDLE hDirectory, LPWIN32_FIND_DATAW pFindData)
379 LPDIRECTORY pDirectory = static_cast<LPDIRECTORY>(hDirectory);
380 if ( !pDirectory )
382 SetLastError( ERROR_INVALID_HANDLE );
383 return false;
386 bool fSuccess = false;
387 bool fValid;
390 if ( pDirectory->aFirstData.cFileName[0] )
392 *pFindData = pDirectory->aFirstData;
393 fSuccess = true;
394 pDirectory->aFirstData.cFileName[0] = 0;
396 else if ( IsValidHandle( pDirectory->hFind ) )
397 fSuccess = FindNextFileW( pDirectory->hFind, pFindData );
398 else
400 fSuccess = false;
401 SetLastError( ERROR_NO_MORE_FILES );
404 fValid = fSuccess && wcscmp( L".", pFindData->cFileName ) != 0 && wcscmp( L"..", pFindData->cFileName ) != 0;
406 } while( fSuccess && !fValid );
408 return fSuccess;
411 static bool WINAPI CloseDirectory(HANDLE hDirectory)
413 bool fSuccess = false;
414 LPDIRECTORY pDirectory = static_cast<LPDIRECTORY>(hDirectory);
416 if (pDirectory)
418 if (IsValidHandle(pDirectory->hFind))
419 fSuccess = FindClose(pDirectory->hFind);
421 fSuccess = HeapFree(GetProcessHeap(), 0, pDirectory) && fSuccess;
423 else
424 SetLastError(ERROR_INVALID_HANDLE);
426 return fSuccess;
429 static oslFileError osl_openLocalRoot(
430 rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
432 if ( !pDirectory )
433 return osl_File_E_INVAL;
435 *pDirectory = nullptr;
437 OUString strSysPath;
438 oslFileError error = osl_getSystemPathFromFileURL_(OUString::unacquired(&strDirectoryPath), &strSysPath.pData, false);
439 if ( osl_File_E_None != error )
440 return error;
442 Directory_Impl* pDirImpl = new (std::nothrow) Directory_Impl;
443 assert(pDirImpl); // Don't handle OOM conditions
444 pDirImpl->m_sDirectoryPath = strSysPath;
446 /* Append backslash if necessary */
448 /* @@@ToDo
449 use function ensure backslash
451 sal_uInt32 nLen = pDirImpl->m_sDirectoryPath.getLength();
452 if ( nLen && pDirImpl->m_sDirectoryPath[nLen - 1] != L'\\' )
454 pDirImpl->m_sDirectoryPath += "\\";
457 pDirImpl->uType = DIRECTORYTYPE_LOCALROOT;
458 pDirImpl->hEnumDrives = OpenLogicalDrivesEnum();
460 /* @@@ToDo
461 Use IsValidHandle(...)
463 if ( pDirImpl->hEnumDrives != INVALID_HANDLE_VALUE )
465 *pDirectory = static_cast<oslDirectory>(pDirImpl);
466 error = osl_File_E_None;
468 else
470 if ( pDirImpl )
472 delete pDirImpl;
473 pDirImpl = nullptr;
476 error = oslTranslateFileError( GetLastError() );
478 return error;
481 static oslFileError osl_openFileDirectory(
482 rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
484 oslFileError error = osl_File_E_None;
486 if ( !pDirectory )
487 return osl_File_E_INVAL;
488 *pDirectory = nullptr;
490 Directory_Impl *pDirImpl = new (std::nothrow) Directory_Impl;
491 assert(pDirImpl); // Don't handle OOM conditions
492 pDirImpl->m_sDirectoryPath = strDirectoryPath;
494 /* Append backslash if necessary */
496 /* @@@ToDo
497 use function ensure backslash
499 sal_uInt32 nLen = pDirImpl->m_sDirectoryPath.getLength();
500 if ( nLen && pDirImpl->m_sDirectoryPath[nLen - 1] != '\\' )
501 pDirImpl->m_sDirectoryPath += "\\";
503 pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM;
504 pDirImpl->hDirectory = OpenDirectory( pDirImpl->m_sDirectoryPath.pData );
506 if ( !pDirImpl->hDirectory )
508 error = oslTranslateFileError( GetLastError() );
510 delete pDirImpl;
511 pDirImpl = nullptr;
514 *pDirectory = static_cast<oslDirectory>(pDirImpl);
515 return error;
518 static oslFileError osl_openNetworkServer(
519 rtl_uString *strSysDirPath, oslDirectory *pDirectory)
521 NETRESOURCEW aNetResource;
522 HANDLE hEnum;
523 DWORD dwError;
525 ZeroMemory( &aNetResource, sizeof(aNetResource) );
527 aNetResource.lpRemoteName = o3tl::toW(strSysDirPath->buffer);
529 dwError = WNetOpenEnumW(
530 RESOURCE_GLOBALNET,
531 RESOURCETYPE_DISK,
532 RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER,
533 &aNetResource,
534 &hEnum );
536 if ( ERROR_SUCCESS == dwError )
538 Directory_Impl *pDirImpl = new (std::nothrow) Directory_Impl;
539 assert(pDirImpl); // Don't handle OOM conditions
540 pDirImpl->uType = DIRECTORYTYPE_NETROOT;
541 pDirImpl->hDirectory = hEnum;
542 *pDirectory = static_cast<oslDirectory>(pDirImpl);
544 return oslTranslateFileError( dwError );
547 static DWORD create_dir_with_callback(
548 rtl_uString * dir_path,
549 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
550 void* pData)
552 // Create the specified directory and call the
553 // user specified callback function. On success
554 // the function returns ERROR_SUCCESS else a Win32 error code.
556 bool bCreated = CreateDirectoryW( o3tl::toW(rtl_uString_getStr( dir_path )), nullptr );
558 if ( bCreated )
560 if (aDirectoryCreationCallbackFunc)
562 OUString url;
563 osl_getFileURLFromSystemPath(dir_path, &(url.pData));
564 aDirectoryCreationCallbackFunc(pData, url.pData);
566 return ERROR_SUCCESS;
568 return GetLastError();
571 static int path_make_parent(sal_Unicode* path)
573 /* Cut off the last part of the given path to
574 get the parent only, e.g. 'c:\dir\subdir' ->
575 'c:\dir' or '\\share\sub\dir' -> '\\share\sub'
576 @return The position where the path has been cut
577 off (this is the position of the last backslash).
578 If there are no more parents 0 will be returned,
579 e.g. 'c:\' or '\\Share' have no more parents */
581 OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) == -1, "Path must not contain slashes");
582 OSL_PRECOND(has_path_parent(path), "Path must have a parent");
584 sal_Unicode* pos_last_backslash = path + rtl_ustr_lastIndexOfChar(path, BACKSLASH);
585 *pos_last_backslash = 0;
586 return (pos_last_backslash - path);
589 static DWORD create_dir_recursively_(
590 rtl_uString * dir_path,
591 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
592 void* pData)
594 OSL_PRECOND(
595 rtl_ustr_lastIndexOfChar_WithLength(dir_path->buffer, dir_path->length, BACKSLASH) != dir_path->length,
596 "Path must not end with a backslash");
598 DWORD w32_error = create_dir_with_callback(
599 dir_path, aDirectoryCreationCallbackFunc, pData);
600 if (w32_error == ERROR_SUCCESS)
601 return ERROR_SUCCESS;
603 if ((w32_error != ERROR_PATH_NOT_FOUND) || !has_path_parent(dir_path->buffer))
604 return w32_error;
606 int pos = path_make_parent(dir_path->buffer); // dir_path->buffer[pos] = 0, restore below
608 w32_error = create_dir_recursively_(
609 dir_path, aDirectoryCreationCallbackFunc, pData);
611 dir_path->buffer[pos] = BACKSLASH; // restore
613 if (ERROR_SUCCESS != w32_error && ERROR_ALREADY_EXISTS != w32_error)
614 return w32_error;
616 return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
619 oslFileError SAL_CALL osl_createDirectoryPath(
620 rtl_uString* aDirectoryUrl,
621 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
622 void* pData)
624 if (aDirectoryUrl == nullptr)
625 return osl_File_E_INVAL;
627 OUString sys_path;
628 oslFileError osl_error =
629 osl_getSystemPathFromFileURL_(OUString::unacquired(&aDirectoryUrl), &sys_path.pData, false);
631 if (osl_error != osl_File_E_None)
632 return osl_error;
634 osl::systemPathRemoveSeparator(sys_path);
636 // const_cast because sys_path is a local copy
637 // which we want to modify inplace instead of
638 // copy it into another buffer on the heap again
639 return oslTranslateFileError(create_dir_recursively_(
640 sys_path.pData, aDirectoryCreationCallbackFunc, pData));
643 oslFileError SAL_CALL osl_createDirectory(rtl_uString* strPath)
645 return osl_createDirectoryWithFlags(
646 strPath, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write);
649 oslFileError osl_createDirectoryWithFlags(rtl_uString * strPath, sal_uInt32)
651 OUString strSysPath;
652 oslFileError error = osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath), &strSysPath.pData, false);
654 if ( osl_File_E_None != error )
655 return error;
657 bool bCreated = CreateDirectoryW(o3tl::toW(strSysPath.getStr()), nullptr);
658 if ( !bCreated )
660 /*@@@ToDo
661 The following case is a hack because the ucb or the webtop had some
662 problems with the error code that CreateDirectory returns in
663 case the path is only a logical drive, should be removed!
666 if ((strSysPath.getLength() == 2 || (strSysPath.getLength() == 3 && strSysPath[2] == '\\'))
667 && rtl::isAsciiAlpha(strSysPath[0]) && strSysPath[1] == ':')
668 SetLastError( ERROR_ALREADY_EXISTS );
670 error = oslTranslateFileError( GetLastError() );
673 return error;
676 oslFileError SAL_CALL osl_removeDirectory(rtl_uString* strPath)
678 OUString strSysPath;
679 oslFileError error = osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath), &strSysPath.pData, false);
681 if ( osl_File_E_None == error )
683 if (RemoveDirectoryW(o3tl::toW(strSysPath.getStr())))
684 error = osl_File_E_None;
685 else
686 error = oslTranslateFileError( GetLastError() );
688 return error;
691 oslFileError SAL_CALL osl_openDirectory(rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
693 oslFileError error;
695 if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath->buffer, "file:///" ) )
696 error = osl_openLocalRoot( strDirectoryPath, pDirectory );
697 else
699 OUString strSysDirectoryPath;
700 DWORD dwPathType;
702 error = osl_getSystemPathFromFileURL_(OUString::unacquired(&strDirectoryPath), &strSysDirectoryPath.pData, false);
704 if ( osl_File_E_None != error )
705 return error;
707 dwPathType = IsValidFilePath(strSysDirectoryPath, VALIDATEPATH_NORMAL, nullptr);
709 if ( dwPathType & PATHTYPE_IS_SERVER )
710 error = osl_openNetworkServer(strSysDirectoryPath.pData, pDirectory);
711 else
712 error = osl_openFileDirectory(strSysDirectoryPath.pData, pDirectory);
714 return error;
717 static oslFileError osl_getNextNetResource(
718 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/ )
720 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
721 DirectoryItem_Impl *pItemImpl = nullptr;
722 BYTE buffer[16384];
723 LPNETRESOURCEW lpNetResource = reinterpret_cast<LPNETRESOURCEW>(buffer);
724 DWORD dwError, dwCount, dwBufSize;
726 if ( !pItem )
727 return osl_File_E_INVAL;
728 *pItem = nullptr;
730 if ( !pDirImpl )
731 return osl_File_E_INVAL;
733 dwCount = 1;
734 dwBufSize = sizeof(buffer);
735 dwError = WNetEnumResourceW( pDirImpl->hDirectory, &dwCount, lpNetResource, &dwBufSize );
737 switch ( dwError )
739 case NO_ERROR:
740 case ERROR_MORE_DATA:
742 pItemImpl = new (std::nothrow) DirectoryItem_Impl;
743 if ( !pItemImpl )
744 return osl_File_E_NOMEM;
746 pItemImpl->uType = DIRECTORYITEM_DRIVE;
747 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
749 wcscpy( pItemImpl->cDriveString, lpNetResource->lpRemoteName );
751 *pItem = pItemImpl;
753 return osl_File_E_None;
754 case ERROR_NO_MORE_ITEMS:
755 return osl_File_E_NOENT;
756 default:
757 return oslTranslateFileError( dwError );
761 static oslFileError osl_getNextDrive(
762 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/ )
764 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
765 DirectoryItem_Impl *pItemImpl = nullptr;
766 bool fSuccess;
768 if ( !pItem )
769 return osl_File_E_INVAL;
770 *pItem = nullptr;
772 if ( !pDirImpl )
773 return osl_File_E_INVAL;
775 pItemImpl = new (std::nothrow) DirectoryItem_Impl;
776 if ( !pItemImpl )
777 return osl_File_E_NOMEM;
779 pItemImpl->uType = DIRECTORYITEM_DRIVE;
780 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
781 fSuccess = EnumLogicalDrives( pDirImpl->hEnumDrives, pItemImpl->cDriveString );
783 if ( fSuccess )
785 *pItem = pItemImpl;
786 return osl_File_E_None;
788 else
790 delete pItemImpl;
791 return oslTranslateFileError( GetLastError() );
795 static oslFileError osl_getNextFileItem(
796 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 /*uHint*/)
798 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
799 DirectoryItem_Impl *pItemImpl = nullptr;
800 bool fFound;
802 if ( !pItem )
803 return osl_File_E_INVAL;
804 *pItem = nullptr;
806 if ( !pDirImpl )
807 return osl_File_E_INVAL;
809 pItemImpl = new (std::nothrow) DirectoryItem_Impl;
810 if ( !pItemImpl )
811 return osl_File_E_NOMEM;
813 fFound = EnumDirectory( pDirImpl->hDirectory, &pItemImpl->FindData );
814 if ( !fFound )
816 delete pItemImpl;
817 return oslTranslateFileError( GetLastError() );
820 pItemImpl->uType = DIRECTORYITEM_FILE;
821 pItemImpl->nRefCount = 1;
823 pItemImpl->m_sFullPath = pDirImpl->m_sDirectoryPath + o3tl::toU(pItemImpl->FindData.cFileName);
825 pItemImpl->bFullPathNormalized = true;
826 *pItem = static_cast<oslDirectoryItem>(pItemImpl);
827 return osl_File_E_None;
830 oslFileError SAL_CALL osl_getNextDirectoryItem(
831 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint)
833 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
835 /* Assume failure */
837 if ( !pItem )
838 return osl_File_E_INVAL;
839 *pItem = nullptr;
841 if ( !pDirImpl )
842 return osl_File_E_INVAL;
844 switch ( pDirImpl->uType )
846 case DIRECTORYTYPE_LOCALROOT:
847 return osl_getNextDrive( Directory, pItem, uHint );
848 case DIRECTORYTYPE_NETROOT:
849 return osl_getNextNetResource( Directory, pItem, uHint );
850 case DIRECTORYTYPE_FILESYSTEM:
851 return osl_getNextFileItem( Directory, pItem, uHint );
852 default:
853 return osl_File_E_INVAL;
857 oslFileError SAL_CALL osl_closeDirectory(oslDirectory Directory)
859 Directory_Impl *pDirImpl = static_cast<Directory_Impl *>(Directory);
860 oslFileError eError = osl_File_E_INVAL;
862 if ( pDirImpl )
864 switch ( pDirImpl->uType )
866 case DIRECTORYTYPE_FILESYSTEM:
867 eError = CloseDirectory( pDirImpl->hDirectory ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
868 break;
869 case DIRECTORYTYPE_LOCALROOT:
870 eError = CloseLogicalDrivesEnum( pDirImpl->hEnumDrives ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
871 break;
872 case DIRECTORYTYPE_NETROOT:
874 DWORD err = WNetCloseEnum(pDirImpl->hDirectory);
875 eError = (err == NO_ERROR) ? osl_File_E_None : oslTranslateFileError(err);
877 break;
878 default:
879 OSL_FAIL( "Invalid directory type" );
880 break;
883 delete pDirImpl;
885 return eError;
888 namespace {
890 /* Different types of paths */
891 enum PATHTYPE
893 PATHTYPE_SYNTAXERROR = 0,
894 PATHTYPE_NETROOT,
895 PATHTYPE_NETSERVER,
896 PATHTYPE_VOLUME,
897 PATHTYPE_FILE
902 oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString *strFilePath, oslDirectoryItem *pItem)
904 oslFileError error = osl_File_E_None;
905 OUString strSysFilePath;
906 PATHTYPE type = PATHTYPE_FILE;
907 DWORD dwPathType;
909 /* Assume failure */
911 if ( !pItem )
912 return osl_File_E_INVAL;
914 *pItem = nullptr;
916 error = osl_getSystemPathFromFileURL_(OUString::unacquired(&strFilePath), &strSysFilePath.pData, false);
918 if ( osl_File_E_None != error )
919 return error;
921 dwPathType = IsValidFilePath( strSysFilePath, VALIDATEPATH_NORMAL, nullptr );
923 if ( dwPathType & PATHTYPE_IS_VOLUME )
924 type = PATHTYPE_VOLUME;
925 else if ( dwPathType & PATHTYPE_IS_SERVER )
926 type = PATHTYPE_NETSERVER;
927 else
928 type = PATHTYPE_FILE;
930 switch ( type )
932 case PATHTYPE_NETSERVER:
934 DirectoryItem_Impl* pItemImpl = new (std::nothrow) DirectoryItem_Impl;
936 if ( !pItemImpl )
937 error = osl_File_E_NOMEM;
939 if ( osl_File_E_None == error )
941 pItemImpl->uType = DIRECTORYITEM_SERVER;
943 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
944 pItemImpl->m_sFullPath = strSysFilePath;
946 // Assign a title anyway
948 int iSrc = 2;
949 int iDst = 0;
951 while( iSrc < strSysFilePath.getLength() && strSysFilePath[iSrc] && strSysFilePath[iSrc] != '\\')
953 pItemImpl->FindData.cFileName[iDst++] = strSysFilePath[iSrc++];
957 *pItem = pItemImpl;
960 break;
961 case PATHTYPE_VOLUME:
963 DirectoryItem_Impl* pItemImpl = new (std::nothrow) DirectoryItem_Impl;
965 if ( !pItemImpl )
966 error = osl_File_E_NOMEM;
968 if ( osl_File_E_None == error )
970 pItemImpl->uType = DIRECTORYITEM_DRIVE;
972 osl_acquireDirectoryItem( static_cast<oslDirectoryItem>(pItemImpl) );
974 wcscpy( pItemImpl->cDriveString, o3tl::toW(strSysFilePath.getStr()) );
975 pItemImpl->cDriveString[0] = rtl::toAsciiUpperCase( pItemImpl->cDriveString[0] );
977 if ( pItemImpl->cDriveString[wcslen(pItemImpl->cDriveString) - 1] != '\\' )
978 wcscat( pItemImpl->cDriveString, L"\\" );
980 *pItem = pItemImpl;
983 break;
984 case PATHTYPE_SYNTAXERROR:
985 case PATHTYPE_NETROOT:
986 case PATHTYPE_FILE:
988 HANDLE hFind;
989 WIN32_FIND_DATAW aFindData;
991 if (!strSysFilePath.isEmpty() && strSysFilePath[strSysFilePath.getLength() - 1] == '\\')
992 strSysFilePath = strSysFilePath.copy(0, strSysFilePath.getLength() - 1);
994 hFind = FindFirstFileW( o3tl::toW(strSysFilePath.getStr()), &aFindData );
996 if ( hFind != INVALID_HANDLE_VALUE )
998 DirectoryItem_Impl *pItemImpl = new (std::nothrow) DirectoryItem_Impl;
999 if (!pItemImpl)
1000 error = osl_File_E_NOMEM;
1002 if (osl_File_E_None == error)
1004 osl_acquireDirectoryItem(static_cast<oslDirectoryItem>(pItemImpl));
1006 CopyMemory(&pItemImpl->FindData, &aFindData, sizeof(WIN32_FIND_DATAW));
1007 pItemImpl->m_sFullPath = strSysFilePath;
1009 pItemImpl->uType = DIRECTORYITEM_FILE;
1010 *pItem = pItemImpl;
1013 FindClose( hFind );
1015 else
1016 error = oslTranslateFileError( GetLastError() );
1018 break;
1021 return error;
1024 oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item )
1026 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1028 if ( !pItemImpl )
1029 return osl_File_E_INVAL;
1031 pItemImpl->nRefCount++;
1032 return osl_File_E_None;
1035 oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
1037 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1039 if ( !pItemImpl )
1040 return osl_File_E_INVAL;
1042 if ( ! --pItemImpl->nRefCount )
1043 delete pItemImpl;
1045 return osl_File_E_None;
1048 sal_Bool
1049 SAL_CALL osl_identicalDirectoryItem( oslDirectoryItem a, oslDirectoryItem b)
1051 DirectoryItem_Impl *pA = static_cast<DirectoryItem_Impl *>(a);
1052 DirectoryItem_Impl *pB = static_cast<DirectoryItem_Impl *>(b);
1053 if (a == b)
1054 return true;
1055 /* same name => same item, unless renaming / moving madness has occurred */
1056 if (pA->m_sFullPath == pB->m_sFullPath)
1057 return true;
1059 // FIXME: as/when/if this is used in anger on Windows we could
1060 // do better here.
1062 return false;
1065 static bool is_floppy_A_present()
1066 { return (GetLogicalDrives() & 1); }
1068 static bool is_floppy_B_present()
1069 { return (GetLogicalDrives() & 2); }
1071 static bool is_floppy_volume_mount_point(const OUString& path)
1073 // determines if a volume mount point shows to a floppy
1074 // disk by comparing the unique volume names
1075 static const LPCWSTR FLOPPY_A = L"A:\\";
1076 static const LPCWSTR FLOPPY_B = L"B:\\";
1078 OUString p(path);
1079 osl::systemPathEnsureSeparator(p);
1081 WCHAR vn[51];
1082 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p.getStr()), vn, SAL_N_ELEMENTS(vn)))
1084 WCHAR vnfloppy[51];
1085 if (is_floppy_A_present() &&
1086 GetVolumeNameForVolumeMountPointW(FLOPPY_A, vnfloppy, SAL_N_ELEMENTS(vnfloppy)) &&
1087 (0 == wcscmp(vn, vnfloppy)))
1088 return true;
1090 if (is_floppy_B_present() &&
1091 GetVolumeNameForVolumeMountPointW(FLOPPY_B, vnfloppy, SAL_N_ELEMENTS(vnfloppy)) &&
1092 (0 == wcscmp(vn, vnfloppy)))
1093 return true;
1095 return false;
1098 static bool is_floppy_drive(const OUString& path)
1100 static const LPCWSTR FLOPPY_DRV_LETTERS = L"AaBb";
1102 // we must take into account that even a floppy
1103 // drive may be mounted to a directory so checking
1104 // for the drive letter alone is not sufficient
1105 // we must compare the unique volume name with
1106 // that of the available floppy disks
1108 const sal_Unicode* pszPath = path.getStr();
1109 return ((wcschr(FLOPPY_DRV_LETTERS, pszPath[0]) && (L':' == pszPath[1])) || is_floppy_volume_mount_point(path));
1112 static bool is_volume_mount_point(const OUString& path)
1114 OUString p(path);
1115 osl::systemPathRemoveSeparator(p);
1117 if (is_floppy_drive(p))
1118 return false;
1120 DWORD fattr = GetFileAttributesW(o3tl::toW(p.getStr()));
1121 if ((INVALID_FILE_ATTRIBUTES == fattr) ||
1122 !(FILE_ATTRIBUTE_REPARSE_POINT & fattr))
1123 return false;
1125 bool is_volume_root = false;
1126 WIN32_FIND_DATAW find_data;
1127 HANDLE h_find = FindFirstFileW(o3tl::toW(p.getStr()), &find_data);
1129 if (IsValidHandle(h_find) &&
1130 (FILE_ATTRIBUTE_REPARSE_POINT & find_data.dwFileAttributes) &&
1131 (IO_REPARSE_TAG_MOUNT_POINT == find_data.dwReserved0))
1133 is_volume_root = true;
1135 if (IsValidHandle(h_find))
1136 FindClose(h_find);
1137 return is_volume_root;
1140 static UINT get_volume_mount_point_drive_type(const OUString& path)
1142 if (0 == path.getLength())
1143 return GetDriveTypeW(nullptr);
1145 OUString p(path);
1146 osl::systemPathEnsureSeparator(p);
1148 WCHAR vn[51];
1149 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p.getStr()), vn, SAL_N_ELEMENTS(vn)))
1150 return GetDriveTypeW(vn);
1152 return DRIVE_NO_ROOT_DIR;
1155 static bool is_drivetype_request(sal_uInt32 field_mask)
1157 return (field_mask & osl_VolumeInfo_Mask_Attributes);
1160 static oslFileError osl_get_drive_type(
1161 const OUString& path, oslVolumeInfo* pInfo)
1163 // GetDriveType fails on empty volume mount points
1164 // see Knowledge Base Q244089
1165 UINT drive_type;
1166 if (is_volume_mount_point(path))
1167 drive_type = get_volume_mount_point_drive_type(path);
1168 else
1169 drive_type = GetDriveTypeW(o3tl::toW(path.getStr()));
1171 if (DRIVE_NO_ROOT_DIR == drive_type)
1172 return oslTranslateFileError(ERROR_INVALID_DRIVE);
1174 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1176 switch (drive_type)
1178 case DRIVE_CDROM:
1179 pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable;
1180 break;
1181 case DRIVE_REMOVABLE:
1182 pInfo->uAttributes |= osl_Volume_Attribute_Removeable;
1183 if (is_floppy_drive(path))
1184 pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk;
1185 break;
1186 case DRIVE_FIXED:
1187 pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk;
1188 break;
1189 case DRIVE_RAMDISK:
1190 pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk;
1191 break;
1192 case DRIVE_REMOTE:
1193 pInfo->uAttributes |= osl_Volume_Attribute_Remote;
1194 break;
1195 case DRIVE_UNKNOWN:
1196 pInfo->uAttributes = 0;
1197 break;
1198 default:
1199 pInfo->uValidFields &= ~osl_VolumeInfo_Mask_Attributes;
1200 pInfo->uAttributes = 0;
1201 break;
1203 return osl_File_E_None;
1206 static bool is_volume_space_info_request(sal_uInt32 field_mask)
1208 return (field_mask &
1209 (osl_VolumeInfo_Mask_TotalSpace |
1210 osl_VolumeInfo_Mask_UsedSpace |
1211 osl_VolumeInfo_Mask_FreeSpace));
1214 static void get_volume_space_information(
1215 const OUString& path, oslVolumeInfo *pInfo)
1217 bool ret = GetDiskFreeSpaceExW(
1218 o3tl::toW(path.getStr()),
1219 reinterpret_cast<PULARGE_INTEGER>(&pInfo->uFreeSpace),
1220 reinterpret_cast<PULARGE_INTEGER>(&pInfo->uTotalSpace),
1221 nullptr);
1223 if (ret)
1225 pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace;
1226 pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace |
1227 osl_VolumeInfo_Mask_UsedSpace |
1228 osl_VolumeInfo_Mask_FreeSpace;
1232 static bool is_filesystem_attributes_request(sal_uInt32 field_mask)
1234 return (field_mask &
1235 (osl_VolumeInfo_Mask_MaxNameLength |
1236 osl_VolumeInfo_Mask_MaxPathLength |
1237 osl_VolumeInfo_Mask_FileSystemName |
1238 osl_VolumeInfo_Mask_FileSystemCaseHandling));
1241 static oslFileError get_filesystem_attributes(
1242 const OUString& path, sal_uInt32 field_mask, oslVolumeInfo* pInfo)
1244 pInfo->uAttributes = 0;
1246 // osl_get_drive_type must be called first because
1247 // this function resets osl_VolumeInfo_Mask_Attributes
1248 // on failure
1249 if (is_drivetype_request(field_mask))
1251 oslFileError osl_error = osl_get_drive_type(path, pInfo);
1252 if (osl_File_E_None != osl_error)
1253 return osl_error;
1255 if (is_filesystem_attributes_request(field_mask))
1257 /* the following two parameters can not be longer than MAX_PATH+1 */
1258 WCHAR vn[MAX_PATH+1];
1259 WCHAR fsn[MAX_PATH+1];
1261 DWORD serial;
1262 DWORD mcl;
1263 DWORD flags;
1265 LPCWSTR pszPath = o3tl::toW(path.getStr());
1266 if (GetVolumeInformationW(pszPath, vn, MAX_PATH+1, &serial, &mcl, &flags, fsn, MAX_PATH+1))
1268 // Currently sal does not use this value, instead MAX_PATH is used
1269 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength;
1270 pInfo->uMaxNameLength = mcl;
1272 // Should the uMaxPathLength be set to 32767, "\\?\" prefix allows it
1273 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength;
1274 pInfo->uMaxPathLength = MAX_PATH;
1276 pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName;
1277 rtl_uString_newFromStr(&pInfo->ustrFileSystemName, o3tl::toU(fsn));
1279 // volumes (even NTFS) will always be considered case
1280 // insensitive because the Win32 API is not able to
1281 // deal with case sensitive volumes see M$ Knowledge Base
1282 // article 100625 that's why we never set the attribute
1283 // osl_Volume_Attribute_Case_Sensitive
1285 if (flags & FS_CASE_IS_PRESERVED)
1286 pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved;
1288 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1291 return osl_File_E_None;
1294 static bool path_get_parent(OUString& path)
1296 OSL_PRECOND(path.lastIndexOf(SLASH) == -1, "Path must not have slashes");
1298 if (!has_path_parent(path))
1300 sal_Int32 i = path.lastIndexOf(BACKSLASH);
1301 if (-1 < i)
1303 path = OUString(path.getStr(), i);
1304 return true;
1307 return false;
1310 static void path_travel_to_volume_root(const OUString& system_path, OUString& volume_root)
1312 OUString sys_path(system_path);
1314 while(!is_volume_mount_point(sys_path) && path_get_parent(sys_path))
1315 /**/;
1317 volume_root = sys_path;
1318 osl::systemPathEnsureSeparator(volume_root);
1321 oslFileError SAL_CALL osl_getVolumeInformation(
1322 rtl_uString *ustrURL, oslVolumeInfo *pInfo, sal_uInt32 uFieldMask )
1324 if (!pInfo)
1325 return osl_File_E_INVAL;
1327 OUString system_path;
1328 oslFileError error = osl_getSystemPathFromFileURL_(OUString::unacquired(&ustrURL), &system_path.pData, false);
1330 if (osl_File_E_None != error)
1331 return error;
1333 OUString volume_root;
1334 path_travel_to_volume_root(system_path, volume_root);
1336 pInfo->uValidFields = 0;
1338 if ((error = get_filesystem_attributes(volume_root, uFieldMask, pInfo)) != osl_File_E_None)
1339 return error;
1341 if (is_volume_space_info_request(uFieldMask))
1342 get_volume_space_information(volume_root, pInfo);
1344 if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle)
1346 error = osl_getFileURLFromSystemPath(volume_root.pData, reinterpret_cast<rtl_uString**>(&pInfo->pDeviceHandle));
1347 if (error != osl_File_E_None)
1348 return error;
1349 pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle;
1352 return osl_File_E_None;
1355 static oslFileError osl_getDriveInfo(
1356 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask)
1358 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1359 WCHAR cDrive[3] = L"A:";
1360 WCHAR cRoot[4] = L"A:\\";
1362 if ( !pItemImpl )
1363 return osl_File_E_INVAL;
1365 pStatus->uValidFields = 0;
1367 cDrive[0] = pItemImpl->cDriveString[0];
1368 cRoot[0] = pItemImpl->cDriveString[0];
1370 if ( uFieldMask & osl_FileStatus_Mask_FileName )
1372 if ( pItemImpl->cDriveString[0] == '\\' && pItemImpl->cDriveString[1] == '\\' )
1374 LPCWSTR lpFirstBkSlash = wcschr( &pItemImpl->cDriveString[2], '\\' );
1376 if ( lpFirstBkSlash && lpFirstBkSlash[1] )
1378 LPCWSTR lpLastBkSlash = wcschr( &lpFirstBkSlash[1], '\\' );
1380 if ( lpLastBkSlash )
1381 rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, o3tl::toU(&lpFirstBkSlash[1]), lpLastBkSlash - lpFirstBkSlash - 1 );
1382 else
1383 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(&lpFirstBkSlash[1]) );
1384 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1387 else switch ( GetDriveTypeW( cRoot ) )
1389 case DRIVE_REMOTE:
1391 WCHAR szBuffer[1024];
1392 DWORD const dwBufsizeConst = SAL_N_ELEMENTS(szBuffer);
1393 DWORD dwBufsize = dwBufsizeConst;
1395 DWORD dwResult = WNetGetConnectionW( cDrive, szBuffer, &dwBufsize );
1396 if ( NO_ERROR == dwResult )
1398 WCHAR szFileName[dwBufsizeConst + 16];
1400 swprintf( szFileName, L"%s [%s]", cDrive, szBuffer );
1401 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(szFileName) );
1403 else
1404 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cDrive) );
1406 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1407 break;
1408 case DRIVE_FIXED:
1410 WCHAR szVolumeNameBuffer[1024];
1411 DWORD const dwBufsizeConst = SAL_N_ELEMENTS(szVolumeNameBuffer);
1413 if ( GetVolumeInformationW( cRoot, szVolumeNameBuffer, dwBufsizeConst, nullptr, nullptr, nullptr, nullptr, 0 ) )
1415 WCHAR szFileName[dwBufsizeConst + 16];
1417 swprintf( szFileName, L"%s [%s]", cDrive, szVolumeNameBuffer );
1418 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(szFileName) );
1420 else
1421 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cDrive) );
1423 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1424 break;
1425 case DRIVE_CDROM:
1426 case DRIVE_REMOVABLE:
1427 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1428 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(cRoot) );
1429 break;
1430 case DRIVE_UNKNOWN:
1431 default:
1432 break;
1436 pStatus->eType = osl_File_Type_Volume;
1437 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1439 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1441 rtl_uString *ustrSystemPath = nullptr;
1443 rtl_uString_newFromStr( &ustrSystemPath, o3tl::toU(pItemImpl->cDriveString) );
1444 oslFileError error = osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL );
1445 rtl_uString_release( ustrSystemPath );
1446 if (error != osl_File_E_None)
1447 return error;
1448 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1450 return osl_File_E_None;
1453 static oslFileError osl_getServerInfo(
1454 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask )
1456 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1457 if ( !pItemImpl )
1458 return osl_File_E_INVAL;
1460 pStatus->uValidFields = 0;
1461 pStatus->eType = osl_File_Type_Directory;
1462 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1464 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1466 oslFileError error = osl_getFileURLFromSystemPath( pItemImpl->m_sFullPath.pData, &pStatus->ustrFileURL );
1467 if (error != osl_File_E_None)
1468 return error;
1469 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1471 return osl_File_E_None;
1474 oslFileError SAL_CALL osl_getFileStatus(
1475 oslDirectoryItem Item,
1476 oslFileStatus *pStatus,
1477 sal_uInt32 uFieldMask )
1479 DirectoryItem_Impl *pItemImpl = static_cast<DirectoryItem_Impl *>(Item);
1481 if ( !pItemImpl )
1482 return osl_File_E_INVAL;
1484 switch ( pItemImpl->uType )
1486 case DIRECTORYITEM_DRIVE:
1487 return osl_getDriveInfo( Item, pStatus, uFieldMask );
1488 case DIRECTORYITEM_SERVER:
1489 return osl_getServerInfo( Item, pStatus, uFieldMask );
1490 default:
1491 break;
1494 OUString sFullPath(pItemImpl->m_sFullPath);
1496 // Prefix long paths, windows API calls expect this prefix
1497 // (only local paths starting with something like C: or D:)
1498 if (sFullPath.getLength() >= MAX_PATH && isalpha(sFullPath[0]) && sFullPath[1] == ':')
1499 sFullPath = "\\\\?\\" + sFullPath;
1501 if ( uFieldMask & osl_FileStatus_Mask_Validate )
1503 HANDLE hFind = FindFirstFileW( o3tl::toW(sFullPath.getStr() ), &pItemImpl->FindData );
1505 if ( hFind != INVALID_HANDLE_VALUE )
1506 FindClose( hFind );
1507 else
1508 return oslTranslateFileError( GetLastError() );
1510 uFieldMask &= ~ osl_FileStatus_Mask_Validate;
1513 /* If no fields to retrieve left ignore pStatus */
1514 if ( !uFieldMask )
1515 return osl_File_E_None;
1517 /* Otherwise, this must be a valid pointer */
1518 if ( !pStatus )
1519 return osl_File_E_INVAL;
1521 if ( pStatus->uStructSize != sizeof(oslFileStatus) )
1522 return osl_File_E_INVAL;
1524 pStatus->uValidFields = 0;
1526 /* File time stamps */
1528 if ( (uFieldMask & osl_FileStatus_Mask_ModifyTime) &&
1529 FileTimeToTimeValue( &pItemImpl->FindData.ftLastWriteTime, &pStatus->aModifyTime ) )
1530 pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime;
1532 if ( (uFieldMask & osl_FileStatus_Mask_AccessTime) &&
1533 FileTimeToTimeValue( &pItemImpl->FindData.ftLastAccessTime, &pStatus->aAccessTime ) )
1534 pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime;
1536 if ( (uFieldMask & osl_FileStatus_Mask_CreationTime) &&
1537 FileTimeToTimeValue( &pItemImpl->FindData.ftCreationTime, &pStatus->aCreationTime ) )
1538 pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime;
1540 /* Most of the fields are already set, regardless of required fields */
1542 rtl_uString_newFromStr( &pStatus->ustrFileName, o3tl::toU(pItemImpl->FindData.cFileName) );
1543 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1545 if ((FILE_ATTRIBUTE_REPARSE_POINT & pItemImpl->FindData.dwFileAttributes) &&
1546 (IO_REPARSE_TAG_MOUNT_POINT == pItemImpl->FindData.dwReserved0))
1547 pStatus->eType = osl_File_Type_Volume;
1548 else if (pItemImpl->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1549 pStatus->eType = osl_File_Type_Directory;
1550 else
1551 pStatus->eType = osl_File_Type_Regular;
1553 pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1555 pStatus->uAttributes = pItemImpl->FindData.dwFileAttributes;
1556 pStatus->uValidFields |= osl_FileStatus_Mask_Attributes;
1558 pStatus->uFileSize = static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeLow) + (static_cast<sal_uInt64>(pItemImpl->FindData.nFileSizeHigh) << 32);
1559 pStatus->uValidFields |= osl_FileStatus_Mask_FileSize;
1561 if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL )
1563 oslFileError error = osl_getFileURLFromSystemPath( sFullPath.pData, &pStatus->ustrLinkTargetURL );
1564 if (error != osl_File_E_None)
1565 return error;
1567 pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
1570 if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1572 if ( !pItemImpl->bFullPathNormalized )
1574 ::osl::LongPathBuffer<sal_Unicode> aBuffer(MAX_LONG_PATH);
1575 sal_uInt32 nNewLen = GetLongPathNameW(o3tl::toW(sFullPath.getStr()), o3tl::toW(aBuffer),
1576 aBuffer.getBufSizeInSymbols());
1578 if ( nNewLen )
1580 /* Capitalizes drive name (single letter). Windows file paths are processed
1581 case-sensitively. While parsing a path, function osl_DirectoryItem has case
1582 PATHTYPE_VOLUME for drives, and capitalizes them. That can be overwritten by
1583 function osl_getFileStatus, in it win32 api GetLongPathNameW does no
1584 capitalization. Thus it needs to be postprocessed.*/
1585 sal_Int32 nIndex = rtl_ustr_indexOfChar(aBuffer, ':');
1586 if (nIndex > 0) {
1587 aBuffer[nIndex - 1] = rtl::toAsciiUpperCase(aBuffer[nIndex - 1]);
1590 pItemImpl->m_sFullPath = OUString(&*aBuffer, nNewLen);
1591 sFullPath = pItemImpl->m_sFullPath;
1592 pItemImpl->bFullPathNormalized = true;
1596 oslFileError error = osl_getFileURLFromSystemPath( sFullPath.pData, &pStatus->ustrFileURL );
1597 if (error != osl_File_E_None)
1598 return error;
1599 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1602 return osl_File_E_None;
1605 oslFileError SAL_CALL osl_setFileAttributes(
1606 rtl_uString *ustrFileURL,
1607 sal_uInt64 uAttributes )
1609 oslFileError error;
1610 OUString ustrSysPath;
1611 DWORD dwFileAttributes;
1612 bool fSuccess;
1614 // Converts the normalized path into a systempath
1615 error = osl_getSystemPathFromFileURL_(OUString::unacquired(&ustrFileURL), &ustrSysPath.pData, false);
1617 if ( osl_File_E_None != error )
1618 return error;
1620 dwFileAttributes = GetFileAttributesW(o3tl::toW(ustrSysPath.getStr()));
1622 if ( DWORD(-1) != dwFileAttributes )
1624 dwFileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
1626 if ( uAttributes & osl_File_Attribute_ReadOnly )
1627 dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1629 if ( uAttributes & osl_File_Attribute_Hidden )
1630 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1632 fSuccess = SetFileAttributesW(o3tl::toW(ustrSysPath.getStr()), dwFileAttributes);
1634 else
1636 fSuccess = false;
1639 if ( !fSuccess )
1640 error = oslTranslateFileError( GetLastError() );
1642 return error;
1645 oslFileError SAL_CALL osl_setFileTime(
1646 rtl_uString *filePath,
1647 const TimeValue *aCreationTime,
1648 const TimeValue *aLastAccessTime,
1649 const TimeValue *aLastWriteTime)
1651 oslFileError error;
1652 OUString sysPath;
1653 FILETIME *lpCreationTime=nullptr;
1654 FILETIME *lpLastAccessTime=nullptr;
1655 FILETIME *lpLastWriteTime=nullptr;
1656 FILETIME ftCreationTime;
1657 FILETIME ftLastAccessTime;
1658 FILETIME ftLastWriteTime;
1659 HANDLE hFile;
1660 bool fSuccess;
1662 error=osl_getSystemPathFromFileURL_(OUString::unacquired(&filePath), &sysPath.pData, false);
1664 if (error==osl_File_E_INVAL)
1665 return error;
1667 hFile=CreateFileW(o3tl::toW(sysPath.getStr()), GENERIC_WRITE, 0, nullptr , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
1669 if (hFile==INVALID_HANDLE_VALUE)
1670 return osl_File_E_NOENT;
1672 if (TimeValueToFileTime(aCreationTime, &ftCreationTime))
1673 lpCreationTime=&ftCreationTime;
1675 if (TimeValueToFileTime(aLastAccessTime, &ftLastAccessTime))
1676 lpLastAccessTime=&ftLastAccessTime;
1678 if (TimeValueToFileTime(aLastWriteTime, &ftLastWriteTime))
1679 lpLastWriteTime=&ftLastWriteTime;
1681 fSuccess=SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
1683 CloseHandle(hFile);
1685 if (!fSuccess)
1686 return osl_File_E_INVAL;
1687 else
1688 return osl_File_E_None;
1691 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */