1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
36 BOOL
TimeValueToFileTime(const TimeValue
*cpTimeVal
, FILETIME
*pFTime
)
38 SYSTEMTIME BaseSysTime
;
39 FILETIME BaseFileTime
;
41 bool fSuccess
= false;
43 BaseSysTime
.wYear
= 1970;
44 BaseSysTime
.wMonth
= 1;
45 BaseSysTime
.wDayOfWeek
= 0;
47 BaseSysTime
.wHour
= 0;
48 BaseSysTime
.wMinute
= 0;
49 BaseSysTime
.wSecond
= 0;
50 BaseSysTime
.wMilliseconds
= 0;
52 if (cpTimeVal
==nullptr)
55 if ( SystemTimeToFileTime(&BaseSysTime
, &BaseFileTime
) )
59 __int64 localTime
= cpTimeVal
->Seconds
*__int64(10000000)+cpTimeVal
->Nanosec
/100;
60 osl::detail::setFiletime(FTime
, localTime
);
61 fSuccess
= 0 <= (timeValue
= osl::detail::getFiletime(BaseFileTime
) + osl::detail::getFiletime(FTime
));
63 osl::detail::setFiletime(*pFTime
, timeValue
);
68 BOOL
FileTimeToTimeValue(const FILETIME
*cpFTime
, TimeValue
*pTimeVal
)
70 SYSTEMTIME BaseSysTime
;
71 FILETIME BaseFileTime
;
72 bool fSuccess
= false; /* Assume failure */
74 BaseSysTime
.wYear
= 1970;
75 BaseSysTime
.wMonth
= 1;
76 BaseSysTime
.wDayOfWeek
= 0;
78 BaseSysTime
.wHour
= 0;
79 BaseSysTime
.wMinute
= 0;
80 BaseSysTime
.wSecond
= 0;
81 BaseSysTime
.wMilliseconds
= 0;
83 if ( SystemTimeToFileTime(&BaseSysTime
, &BaseFileTime
) )
87 fSuccess
= 0 <= (Value
= osl::detail::getFiletime(*cpFTime
) - osl::detail::getFiletime(BaseFileTime
));
91 pTimeVal
->Seconds
= static_cast<unsigned long>(Value
/ 10000000L);
92 pTimeVal
->Nanosec
= static_cast<unsigned long>((Value
% 10000000L) * 100);
100 // Returns whether a given path is only a logical drive pattern or not.
101 // A logical drive pattern is something like "a:\", "c:\".
102 // No logical drive pattern is something like "c:\test"
103 bool systemPathIsLogicalDrivePattern(std::u16string_view path
)
105 // is [A-Za-z]:[/|\]\0
106 if (path
.length() < 2 || !rtl::isAsciiAlpha(path
[0]) || path
[1] != ':')
108 auto rest
= path
.substr(2);
109 return rest
.empty() // "c:"
110 || rest
== u
"\\" // "c:\"
111 || rest
== u
"/" // "c:/"
112 || rest
== u
".\\"; // "c:.\"
113 // degenerated case returned by the Windows FileOpen dialog
114 // when someone enters for instance "x:filename", the Win32
115 // API accepts this case
118 // Adds a trailing path separator to the given system path if not
119 // already there and if the path is not the root path or a logical
121 void systemPathEnsureSeparator(/*inout*/ OUString
& path
)
123 if (!path
.endsWith(u
"\\") && !path
.endsWith(u
"/"))
126 SAL_WARN_IF(!path
.endsWith(u
"\\"), "sal.osl",
127 "systemPathEnsureSeparator: Post condition failed");
130 // Removes the last separator from the given system path if any and
131 // if the path is not the root path '\'
132 void systemPathRemoveSeparator(/*inout*/ OUString
& path
)
134 if (!systemPathIsLogicalDrivePattern(path
) && (path
.endsWith(u
"\\") || path
.endsWith(u
"/")))
135 path
= path
.copy(0, path
.getLength() - 1);
140 bool isPresent() const { return begin_
< end_
; }
142 const sal_Unicode
* begin_
= nullptr;
143 const sal_Unicode
* end_
= nullptr;
153 bool is_UNC_path(std::u16string_view path
) { return path
.starts_with(u
"\\\\"); }
155 UNCComponents
parse_UNC_path(std::u16string_view path
)
157 OSL_PRECOND(is_UNC_path(path
), "Precondition violated: No UNC path");
158 OSL_PRECOND(path
.find('/') == std::u16string_view::npos
, "Path must not contain slashes");
160 const sal_Unicode
* pend
= path
.data() + path
.length();
161 const sal_Unicode
* ppos
= path
.data() + 2;
164 uncc
.server_
.begin_
= ppos
;
165 while ((ppos
< pend
) && (*ppos
!= '\\'))
168 uncc
.server_
.end_
= ppos
;
172 uncc
.share_
.begin_
= ++ppos
;
173 while ((ppos
< pend
) && (*ppos
!= '\\'))
176 uncc
.share_
.end_
= ppos
;
180 uncc
.resource_
.begin_
= ppos
+ 1;
181 uncc
.resource_
.end_
= pend
;
185 SAL_WARN_IF(!uncc
.server_
.isPresent() || !uncc
.share_
.isPresent(),
187 "Postcondition violated: Invalid UNC path detected");
191 bool has_path_parent(std::u16string_view path
)
193 // Has the given path a parent or are we already there,
194 // e.g. 'c:\' or '\\server\share\'?
196 bool has_parent
= false;
197 if (is_UNC_path(path
))
199 UNCComponents unc_comp
= parse_UNC_path(path
);
200 has_parent
= unc_comp
.resource_
.isPresent();
204 has_parent
= !systemPathIsLogicalDrivePattern(path
);
210 oslFileError SAL_CALL
osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle
)
214 rtl_uString_acquire( static_cast<rtl_uString
*>(Handle
) );
215 return osl_File_E_None
;
218 return osl_File_E_INVAL
;
221 oslFileError SAL_CALL
osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle
)
225 rtl_uString_release( static_cast<rtl_uString
*>(Handle
) );
226 return osl_File_E_None
;
229 return osl_File_E_INVAL
;
232 oslFileError SAL_CALL
osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle
, rtl_uString
**pstrPath
)
234 if ( Handle
&& pstrPath
)
236 rtl_uString_assign( pstrPath
, static_cast<rtl_uString
*>(Handle
) );
237 return osl_File_E_None
;
240 return osl_File_E_INVAL
;
243 #define DIRECTORYITEM_DRIVE 0
244 #define DIRECTORYITEM_FILE 1
245 #define DIRECTORYITEM_SERVER 2
249 struct DirectoryItem_Impl
253 WIN32_FIND_DATAW FindData
;
254 WCHAR cDriveString
[MAX_PATH
];
256 OUString m_sFullPath
;
257 bool bFullPathNormalized
= false;
263 #define DIRECTORYTYPE_LOCALROOT 0
264 #define DIRECTORYTYPE_NETROOT 1
265 #define DIRECTORYTYPE_FILESYSTEM 3
269 struct Directory_Impl
273 HANDLE hDirectory
= nullptr;
276 OUString m_sDirectoryPath
;
279 typedef struct tagDRIVEENUM
282 WCHAR cBuffer
[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256];
284 } DRIVEENUM
, *PDRIVEENUM
, *LPDRIVEENUM
;
288 static HANDLE
OpenLogicalDrivesEnum()
290 auto xEnum
= std::make_unique
<DRIVEENUM
>();
291 DWORD dwNumCopied
= GetLogicalDriveStringsW( SAL_N_ELEMENTS(xEnum
->cBuffer
) - 1, xEnum
->cBuffer
);
293 if ( dwNumCopied
&& dwNumCopied
< SAL_N_ELEMENTS(xEnum
->cBuffer
) )
295 xEnum
->lpCurrent
= xEnum
->cBuffer
;
296 xEnum
->lpIdent
= L
"tagDRIVEENUM";
302 return xEnum
? static_cast<HANDLE
>(xEnum
.release()) : INVALID_HANDLE_VALUE
;
305 static bool EnumLogicalDrives(HANDLE hEnum
, LPWSTR lpBuffer
)
307 LPDRIVEENUM pEnum
= static_cast<LPDRIVEENUM
>(hEnum
);
310 SetLastError( ERROR_INVALID_HANDLE
);
314 int nLen
= wcslen( pEnum
->lpCurrent
);
317 SetLastError( ERROR_NO_MORE_FILES
);
321 CopyMemory( lpBuffer
, pEnum
->lpCurrent
, (nLen
+ 1) * sizeof(WCHAR
) );
322 pEnum
->lpCurrent
+= nLen
+ 1;
326 static bool CloseLogicalDrivesEnum(HANDLE hEnum
)
328 bool fSuccess
= false;
329 LPDRIVEENUM pEnum
= static_cast<LPDRIVEENUM
>(hEnum
);
337 SetLastError( ERROR_INVALID_HANDLE
);
344 typedef struct tagDIRECTORY
347 WIN32_FIND_DATAW aFirstData
;
348 } DIRECTORY
, *PDIRECTORY
, *LPDIRECTORY
;
352 static HANDLE
OpenDirectory(const OUString
& path
)
357 std::u16string_view suffix
;
358 if (!path
.endsWith(u
"\\"))
363 std::unique_ptr
<WCHAR
[]> szFileMask(new (std::nothrow
) WCHAR
[path
.getLength() + suffix
.length() + 1]);
364 assert(szFileMask
); // Don't handle OOM conditions
365 WCHAR
* pos
= std::copy_n(path
.getStr(), path
.getLength(), szFileMask
.get());
366 pos
= std::copy_n(suffix
.data(), suffix
.length(), pos
);
369 auto xDirectory
= std::make_unique
<DIRECTORY
>();
370 xDirectory
->hFind
= FindFirstFileW(szFileMask
.get(), &xDirectory
->aFirstData
);
372 if (!IsValidHandle(xDirectory
->hFind
))
374 if ( GetLastError() != ERROR_NO_MORE_FILES
)
380 return static_cast<HANDLE
>(xDirectory
.release());
383 static bool EnumDirectory(HANDLE hDirectory
, LPWIN32_FIND_DATAW pFindData
)
385 LPDIRECTORY pDirectory
= static_cast<LPDIRECTORY
>(hDirectory
);
388 SetLastError( ERROR_INVALID_HANDLE
);
392 bool fSuccess
= false;
396 if ( pDirectory
->aFirstData
.cFileName
[0] )
398 *pFindData
= pDirectory
->aFirstData
;
400 pDirectory
->aFirstData
.cFileName
[0] = 0;
402 else if ( IsValidHandle( pDirectory
->hFind
) )
403 fSuccess
= FindNextFileW( pDirectory
->hFind
, pFindData
);
407 SetLastError( ERROR_NO_MORE_FILES
);
410 fValid
= fSuccess
&& wcscmp( L
".", pFindData
->cFileName
) != 0 && wcscmp( L
"..", pFindData
->cFileName
) != 0;
412 } while( fSuccess
&& !fValid
);
417 static bool CloseDirectory(HANDLE hDirectory
)
419 bool fSuccess
= false;
420 LPDIRECTORY pDirectory
= static_cast<LPDIRECTORY
>(hDirectory
);
424 if (IsValidHandle(pDirectory
->hFind
))
425 fSuccess
= FindClose(pDirectory
->hFind
);
430 SetLastError(ERROR_INVALID_HANDLE
);
435 static oslFileError
osl_openLocalRoot(
436 rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
439 return osl_File_E_INVAL
;
441 *pDirectory
= nullptr;
444 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strDirectoryPath
), &strSysPath
.pData
, false);
445 if ( osl_File_E_None
!= error
)
448 std::unique_ptr
<Directory_Impl
> pDirImpl(new (std::nothrow
) Directory_Impl
);
449 assert(pDirImpl
); // Don't handle OOM conditions
450 pDirImpl
->m_sDirectoryPath
= strSysPath
;
452 /* Append backslash if necessary */
455 use function ensure backslash
457 sal_uInt32 nLen
= pDirImpl
->m_sDirectoryPath
.getLength();
458 if ( nLen
&& pDirImpl
->m_sDirectoryPath
[nLen
- 1] != L
'\\' )
460 pDirImpl
->m_sDirectoryPath
+= "\\";
463 pDirImpl
->uType
= DIRECTORYTYPE_LOCALROOT
;
464 pDirImpl
->hEnumDrives
= OpenLogicalDrivesEnum();
467 Use IsValidHandle(...)
469 if (pDirImpl
->hEnumDrives
== INVALID_HANDLE_VALUE
)
470 return oslTranslateFileError(GetLastError());
472 *pDirectory
= pDirImpl
.release();
473 return osl_File_E_None
;
476 static oslFileError
osl_openFileDirectory(
477 rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
480 return osl_File_E_INVAL
;
481 *pDirectory
= nullptr;
483 std::unique_ptr
<Directory_Impl
> pDirImpl(new (std::nothrow
) Directory_Impl
);
484 assert(pDirImpl
); // Don't handle OOM conditions
485 pDirImpl
->m_sDirectoryPath
= strDirectoryPath
;
487 /* Append backslash if necessary */
490 use function ensure backslash
492 sal_uInt32 nLen
= pDirImpl
->m_sDirectoryPath
.getLength();
493 if ( nLen
&& pDirImpl
->m_sDirectoryPath
[nLen
- 1] != '\\' )
494 pDirImpl
->m_sDirectoryPath
+= "\\";
496 pDirImpl
->uType
= DIRECTORYTYPE_FILESYSTEM
;
497 pDirImpl
->hDirectory
= OpenDirectory(pDirImpl
->m_sDirectoryPath
);
499 if ( !pDirImpl
->hDirectory
)
500 return oslTranslateFileError(GetLastError());
502 *pDirectory
= pDirImpl
.release();
503 return osl_File_E_None
;
506 static oslFileError
osl_openNetworkServer(
507 rtl_uString
*strSysDirPath
, oslDirectory
*pDirectory
)
509 NETRESOURCEW aNetResource
;
513 ZeroMemory( &aNetResource
, sizeof(aNetResource
) );
515 aNetResource
.lpRemoteName
= o3tl::toW(strSysDirPath
->buffer
);
517 dwError
= WNetOpenEnumW(
520 RESOURCEUSAGE_CONNECTABLE
| RESOURCEUSAGE_CONTAINER
,
524 if ( ERROR_SUCCESS
== dwError
)
526 Directory_Impl
*pDirImpl
= new (std::nothrow
) Directory_Impl
;
527 assert(pDirImpl
); // Don't handle OOM conditions
528 pDirImpl
->uType
= DIRECTORYTYPE_NETROOT
;
529 pDirImpl
->hDirectory
= hEnum
;
530 *pDirectory
= static_cast<oslDirectory
>(pDirImpl
);
532 return oslTranslateFileError( dwError
);
535 static DWORD
create_dir_with_callback(
536 rtl_uString
* dir_path
,
537 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
540 // Create the specified directory and call the
541 // user specified callback function. On success
542 // the function returns ERROR_SUCCESS else a Win32 error code.
544 bool bCreated
= CreateDirectoryW( o3tl::toW(rtl_uString_getStr( dir_path
)), nullptr );
548 if (aDirectoryCreationCallbackFunc
)
551 osl_getFileURLFromSystemPath(dir_path
, &(url
.pData
));
552 aDirectoryCreationCallbackFunc(pData
, url
.pData
);
554 return ERROR_SUCCESS
;
556 return GetLastError();
559 static sal_Int32
path_make_parent(rtl_uString
* path
)
561 /* Cut off the last part of the given path to
562 get the parent only, e.g. 'c:\dir\subdir' ->
563 'c:\dir' or '\\share\sub\dir' -> '\\share\sub'
564 @return The position where the path has been cut
565 off (this is the position of the last backslash).
566 If there are no more parents 0 will be returned,
567 e.g. 'c:\' or '\\Share' have no more parents */
569 OSL_PRECOND(OUString::unacquired(&path
).indexOf('/') == -1, "Path must not contain slashes");
570 OSL_PRECOND(has_path_parent(OUString::unacquired(&path
)), "Path must have a parent");
572 sal_Int32 pos
= OUString::unacquired(&path
).lastIndexOf('\\');
574 *(path
->buffer
+ pos
) = 0;
578 static DWORD
create_dir_recursively_(
579 rtl_uString
* dir_path
,
580 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
583 OSL_PRECOND(!OUString::unacquired(&dir_path
).endsWith(u
"\\"),
584 "Path must not end with a backslash");
586 DWORD w32_error
= create_dir_with_callback(
587 dir_path
, aDirectoryCreationCallbackFunc
, pData
);
588 if ((w32_error
!= ERROR_PATH_NOT_FOUND
) || !has_path_parent(OUString::unacquired(&dir_path
)))
591 const sal_Int32 oldLen
= dir_path
->length
;
592 dir_path
->length
= path_make_parent(dir_path
); // dir_path->buffer[pos] = 0, restore below
594 w32_error
= create_dir_recursively_(
595 dir_path
, aDirectoryCreationCallbackFunc
, pData
);
597 dir_path
->buffer
[dir_path
->length
] = '\\'; // restore
598 dir_path
->length
= oldLen
;
600 if (ERROR_SUCCESS
!= w32_error
&& ERROR_ALREADY_EXISTS
!= w32_error
)
603 return create_dir_with_callback(dir_path
, aDirectoryCreationCallbackFunc
, pData
);
606 oslFileError SAL_CALL
osl_createDirectoryPath(
607 rtl_uString
* aDirectoryUrl
,
608 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
611 if (aDirectoryUrl
== nullptr)
612 return osl_File_E_INVAL
;
615 oslFileError osl_error
=
616 osl_getSystemPathFromFileURL_(OUString::unacquired(&aDirectoryUrl
), &sys_path
.pData
, false);
618 if (osl_error
!= osl_File_E_None
)
621 systemPathRemoveSeparator(sys_path
);
623 return oslTranslateFileError(create_dir_recursively_(
624 sys_path
.pData
, aDirectoryCreationCallbackFunc
, pData
));
627 oslFileError SAL_CALL
osl_createDirectory(rtl_uString
* strPath
)
629 return osl_createDirectoryWithFlags(
630 strPath
, osl_File_OpenFlag_Read
| osl_File_OpenFlag_Write
);
633 oslFileError
osl_createDirectoryWithFlags(rtl_uString
* strPath
, sal_uInt32
)
636 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
638 if ( osl_File_E_None
!= error
)
641 bool bCreated
= CreateDirectoryW(o3tl::toW(strSysPath
.getStr()), nullptr);
645 The following case is a hack because the ucb or the webtop had some
646 problems with the error code that CreateDirectory returns in
647 case the path is only a logical drive, should be removed!
650 if ((strSysPath
.getLength() == 2 || (strSysPath
.getLength() == 3 && strSysPath
[2] == '\\'))
651 && rtl::isAsciiAlpha(strSysPath
[0]) && strSysPath
[1] == ':')
652 SetLastError( ERROR_ALREADY_EXISTS
);
654 error
= oslTranslateFileError( GetLastError() );
660 oslFileError SAL_CALL
osl_removeDirectory(rtl_uString
* strPath
)
663 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
665 if ( osl_File_E_None
== error
)
667 if (RemoveDirectoryW(o3tl::toW(strSysPath
.getStr())))
668 error
= osl_File_E_None
;
670 error
= oslTranslateFileError( GetLastError() );
675 oslFileError SAL_CALL
osl_openDirectory(rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
679 if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath
->buffer
, "file:///" ) )
680 error
= osl_openLocalRoot( strDirectoryPath
, pDirectory
);
683 OUString strSysDirectoryPath
;
686 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strDirectoryPath
), &strSysDirectoryPath
.pData
, false);
688 if ( osl_File_E_None
!= error
)
691 dwPathType
= IsValidFilePath(strSysDirectoryPath
, VALIDATEPATH_NORMAL
, nullptr);
693 if ( dwPathType
& PATHTYPE_IS_SERVER
)
694 error
= osl_openNetworkServer(strSysDirectoryPath
.pData
, pDirectory
);
696 error
= osl_openFileDirectory(strSysDirectoryPath
.pData
, pDirectory
);
701 static oslFileError
osl_getNextNetResource(
702 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32
/*uHint*/ )
704 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
705 DirectoryItem_Impl
*pItemImpl
= nullptr;
707 LPNETRESOURCEW lpNetResource
= reinterpret_cast<LPNETRESOURCEW
>(buffer
);
708 DWORD dwError
, dwCount
, dwBufSize
;
711 return osl_File_E_INVAL
;
715 return osl_File_E_INVAL
;
718 dwBufSize
= sizeof(buffer
);
719 dwError
= WNetEnumResourceW( pDirImpl
->hDirectory
, &dwCount
, lpNetResource
, &dwBufSize
);
724 case ERROR_MORE_DATA
:
726 pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
728 return osl_File_E_NOMEM
;
730 pItemImpl
->uType
= DIRECTORYITEM_DRIVE
;
731 osl_acquireDirectoryItem( static_cast<oslDirectoryItem
>(pItemImpl
) );
733 wcscpy( pItemImpl
->cDriveString
, lpNetResource
->lpRemoteName
);
737 return osl_File_E_None
;
738 case ERROR_NO_MORE_ITEMS
:
739 return osl_File_E_NOENT
;
741 return oslTranslateFileError( dwError
);
745 static oslFileError
osl_getNextDrive(
746 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32
/*uHint*/ )
748 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
751 return osl_File_E_INVAL
;
755 return osl_File_E_INVAL
;
757 std::unique_ptr
<DirectoryItem_Impl
> pItemImpl(new (std::nothrow
) DirectoryItem_Impl
);
759 return osl_File_E_NOMEM
;
761 pItemImpl
->uType
= DIRECTORYITEM_DRIVE
;
762 osl_acquireDirectoryItem(pItemImpl
.get());
763 if (!EnumLogicalDrives(pDirImpl
->hEnumDrives
, pItemImpl
->cDriveString
))
764 return oslTranslateFileError(GetLastError());
766 *pItem
= pItemImpl
.release();
767 return osl_File_E_None
;
770 static oslFileError
osl_getNextFileItem(
771 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32
/*uHint*/)
773 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
776 return osl_File_E_INVAL
;
780 return osl_File_E_INVAL
;
782 std::unique_ptr
<DirectoryItem_Impl
> pItemImpl(new (std::nothrow
) DirectoryItem_Impl
);
784 return osl_File_E_NOMEM
;
786 if (!EnumDirectory(pDirImpl
->hDirectory
, &pItemImpl
->FindData
))
787 return oslTranslateFileError( GetLastError() );
789 pItemImpl
->uType
= DIRECTORYITEM_FILE
;
790 pItemImpl
->nRefCount
= 1;
792 pItemImpl
->m_sFullPath
= pDirImpl
->m_sDirectoryPath
+ o3tl::toU(pItemImpl
->FindData
.cFileName
);
794 pItemImpl
->bFullPathNormalized
= true;
795 *pItem
= pItemImpl
.release();
796 return osl_File_E_None
;
799 oslFileError SAL_CALL
osl_getNextDirectoryItem(
800 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32 uHint
)
802 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
807 return osl_File_E_INVAL
;
811 return osl_File_E_INVAL
;
813 switch ( pDirImpl
->uType
)
815 case DIRECTORYTYPE_LOCALROOT
:
816 return osl_getNextDrive( Directory
, pItem
, uHint
);
817 case DIRECTORYTYPE_NETROOT
:
818 return osl_getNextNetResource( Directory
, pItem
, uHint
);
819 case DIRECTORYTYPE_FILESYSTEM
:
820 return osl_getNextFileItem( Directory
, pItem
, uHint
);
822 return osl_File_E_INVAL
;
826 oslFileError SAL_CALL
osl_closeDirectory(oslDirectory Directory
)
828 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
829 oslFileError eError
= osl_File_E_INVAL
;
833 switch ( pDirImpl
->uType
)
835 case DIRECTORYTYPE_FILESYSTEM
:
836 eError
= CloseDirectory( pDirImpl
->hDirectory
) ? osl_File_E_None
: oslTranslateFileError( GetLastError() );
838 case DIRECTORYTYPE_LOCALROOT
:
839 eError
= CloseLogicalDrivesEnum( pDirImpl
->hEnumDrives
) ? osl_File_E_None
: oslTranslateFileError( GetLastError() );
841 case DIRECTORYTYPE_NETROOT
:
843 DWORD err
= WNetCloseEnum(pDirImpl
->hDirectory
);
844 eError
= (err
== NO_ERROR
) ? osl_File_E_None
: oslTranslateFileError(err
);
848 OSL_FAIL( "Invalid directory type" );
859 /* Different types of paths */
862 PATHTYPE_SYNTAXERROR
= 0,
871 oslFileError SAL_CALL
osl_getDirectoryItem(rtl_uString
*strFilePath
, oslDirectoryItem
*pItem
)
873 oslFileError error
= osl_File_E_None
;
874 OUString strSysFilePath
;
875 PATHTYPE type
= PATHTYPE_FILE
;
881 return osl_File_E_INVAL
;
885 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strFilePath
), &strSysFilePath
.pData
, false);
887 if ( osl_File_E_None
!= error
)
890 dwPathType
= IsValidFilePath( strSysFilePath
, VALIDATEPATH_NORMAL
, nullptr );
892 if ( dwPathType
& PATHTYPE_IS_VOLUME
)
893 type
= PATHTYPE_VOLUME
;
894 else if ( dwPathType
& PATHTYPE_IS_SERVER
)
895 type
= PATHTYPE_NETSERVER
;
897 type
= PATHTYPE_FILE
;
901 case PATHTYPE_NETSERVER
:
903 DirectoryItem_Impl
* pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
906 return osl_File_E_NOMEM
;
908 pItemImpl
->uType
= DIRECTORYITEM_SERVER
;
910 osl_acquireDirectoryItem(pItemImpl
);
911 pItemImpl
->m_sFullPath
= strSysFilePath
;
913 // Assign a title anyway
918 while( iSrc
< strSysFilePath
.getLength() && strSysFilePath
[iSrc
] && strSysFilePath
[iSrc
] != '\\')
920 pItemImpl
->FindData
.cFileName
[iDst
++] = strSysFilePath
[iSrc
++];
927 case PATHTYPE_VOLUME
:
929 DirectoryItem_Impl
* pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
932 return osl_File_E_NOMEM
;
934 pItemImpl
->uType
= DIRECTORYITEM_DRIVE
;
936 osl_acquireDirectoryItem(pItemImpl
);
938 auto pos
= std::copy_n(strSysFilePath
.getStr(), strSysFilePath
.getLength(), pItemImpl
->cDriveString
);
939 pItemImpl
->cDriveString
[0] = rtl::toAsciiUpperCase( pItemImpl
->cDriveString
[0] );
941 if (!strSysFilePath
.endsWith(u
"\\"))
948 case PATHTYPE_SYNTAXERROR
:
949 case PATHTYPE_NETROOT
:
953 WIN32_FIND_DATAW aFindData
;
955 if (!strSysFilePath
.isEmpty() && strSysFilePath
[strSysFilePath
.getLength() - 1] == '\\')
956 strSysFilePath
= strSysFilePath
.copy(0, strSysFilePath
.getLength() - 1);
958 hFind
= FindFirstFileW( o3tl::toW(strSysFilePath
.getStr()), &aFindData
);
960 if ( hFind
!= INVALID_HANDLE_VALUE
)
962 DirectoryItem_Impl
*pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
964 error
= osl_File_E_NOMEM
;
966 if (osl_File_E_None
== error
)
968 osl_acquireDirectoryItem(static_cast<oslDirectoryItem
>(pItemImpl
));
970 CopyMemory(&pItemImpl
->FindData
, &aFindData
, sizeof(WIN32_FIND_DATAW
));
971 pItemImpl
->m_sFullPath
= strSysFilePath
;
973 pItemImpl
->uType
= DIRECTORYITEM_FILE
;
980 error
= oslTranslateFileError( GetLastError() );
988 oslFileError SAL_CALL
osl_acquireDirectoryItem( oslDirectoryItem Item
)
990 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
993 return osl_File_E_INVAL
;
995 pItemImpl
->nRefCount
++;
996 return osl_File_E_None
;
999 oslFileError SAL_CALL
osl_releaseDirectoryItem( oslDirectoryItem Item
)
1001 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1004 return osl_File_E_INVAL
;
1006 if ( ! --pItemImpl
->nRefCount
)
1009 return osl_File_E_None
;
1013 SAL_CALL
osl_identicalDirectoryItem( oslDirectoryItem a
, oslDirectoryItem b
)
1015 DirectoryItem_Impl
*pA
= static_cast<DirectoryItem_Impl
*>(a
);
1016 DirectoryItem_Impl
*pB
= static_cast<DirectoryItem_Impl
*>(b
);
1019 /* same name => same item, unless renaming / moving madness has occurred */
1020 if (pA
->m_sFullPath
== pB
->m_sFullPath
)
1023 // FIXME: as/when/if this is used in anger on Windows we could
1029 static bool is_floppy_A_present()
1030 { return (GetLogicalDrives() & 1); }
1032 static bool is_floppy_B_present()
1033 { return (GetLogicalDrives() & 2); }
1035 static bool is_floppy_volume_mount_point(const OUString
& path
)
1037 // determines if a volume mount point shows to a floppy
1038 // disk by comparing the unique volume names
1039 static const LPCWSTR FLOPPY_A
= L
"A:\\";
1040 static const LPCWSTR FLOPPY_B
= L
"B:\\";
1043 systemPathEnsureSeparator(p
);
1046 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p
.getStr()), vn
, SAL_N_ELEMENTS(vn
)))
1049 if (is_floppy_A_present() &&
1050 GetVolumeNameForVolumeMountPointW(FLOPPY_A
, vnfloppy
, SAL_N_ELEMENTS(vnfloppy
)) &&
1051 (0 == wcscmp(vn
, vnfloppy
)))
1054 if (is_floppy_B_present() &&
1055 GetVolumeNameForVolumeMountPointW(FLOPPY_B
, vnfloppy
, SAL_N_ELEMENTS(vnfloppy
)) &&
1056 (0 == wcscmp(vn
, vnfloppy
)))
1062 static bool is_floppy_drive(const OUString
& path
)
1064 static const LPCWSTR FLOPPY_DRV_LETTERS
= L
"AaBb";
1066 // we must take into account that even a floppy
1067 // drive may be mounted to a directory so checking
1068 // for the drive letter alone is not sufficient
1069 // we must compare the unique volume name with
1070 // that of the available floppy disks
1072 const sal_Unicode
* pszPath
= path
.getStr();
1073 return ((wcschr(FLOPPY_DRV_LETTERS
, pszPath
[0]) && (L
':' == pszPath
[1])) || is_floppy_volume_mount_point(path
));
1076 static bool is_volume_mount_point(const OUString
& path
)
1079 systemPathRemoveSeparator(p
);
1081 if (is_floppy_drive(p
))
1084 DWORD fattr
= GetFileAttributesW(o3tl::toW(p
.getStr()));
1085 if ((INVALID_FILE_ATTRIBUTES
== fattr
) ||
1086 !(FILE_ATTRIBUTE_REPARSE_POINT
& fattr
))
1089 bool is_volume_root
= false;
1090 WIN32_FIND_DATAW find_data
;
1091 HANDLE h_find
= FindFirstFileW(o3tl::toW(p
.getStr()), &find_data
);
1093 if (IsValidHandle(h_find
) &&
1094 (FILE_ATTRIBUTE_REPARSE_POINT
& find_data
.dwFileAttributes
) &&
1095 (IO_REPARSE_TAG_MOUNT_POINT
== find_data
.dwReserved0
))
1097 is_volume_root
= true;
1099 if (IsValidHandle(h_find
))
1101 return is_volume_root
;
1104 static UINT
get_volume_mount_point_drive_type(const OUString
& path
)
1106 if (0 == path
.getLength())
1107 return GetDriveTypeW(nullptr);
1110 systemPathEnsureSeparator(p
);
1113 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p
.getStr()), vn
, SAL_N_ELEMENTS(vn
)))
1114 return GetDriveTypeW(vn
);
1116 return DRIVE_NO_ROOT_DIR
;
1119 static bool is_drivetype_request(sal_uInt32 field_mask
)
1121 return (field_mask
& osl_VolumeInfo_Mask_Attributes
);
1124 static oslFileError
osl_get_drive_type(
1125 const OUString
& path
, oslVolumeInfo
* pInfo
)
1127 // GetDriveType fails on empty volume mount points
1128 // see Knowledge Base Q244089
1130 if (is_volume_mount_point(path
))
1131 drive_type
= get_volume_mount_point_drive_type(path
);
1133 drive_type
= GetDriveTypeW(o3tl::toW(path
.getStr()));
1135 if (DRIVE_NO_ROOT_DIR
== drive_type
)
1136 return oslTranslateFileError(ERROR_INVALID_DRIVE
);
1138 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_Attributes
;
1143 pInfo
->uAttributes
|= osl_Volume_Attribute_CompactDisc
| osl_Volume_Attribute_Removeable
;
1145 case DRIVE_REMOVABLE
:
1146 pInfo
->uAttributes
|= osl_Volume_Attribute_Removeable
;
1147 if (is_floppy_drive(path
))
1148 pInfo
->uAttributes
|= osl_Volume_Attribute_FloppyDisk
;
1151 pInfo
->uAttributes
|= osl_Volume_Attribute_FixedDisk
;
1154 pInfo
->uAttributes
|= osl_Volume_Attribute_RAMDisk
;
1157 pInfo
->uAttributes
|= osl_Volume_Attribute_Remote
;
1160 pInfo
->uAttributes
= 0;
1163 pInfo
->uValidFields
&= ~osl_VolumeInfo_Mask_Attributes
;
1164 pInfo
->uAttributes
= 0;
1167 return osl_File_E_None
;
1170 static bool is_volume_space_info_request(sal_uInt32 field_mask
)
1172 return (field_mask
&
1173 (osl_VolumeInfo_Mask_TotalSpace
|
1174 osl_VolumeInfo_Mask_UsedSpace
|
1175 osl_VolumeInfo_Mask_FreeSpace
));
1178 static void get_volume_space_information(
1179 const OUString
& path
, oslVolumeInfo
*pInfo
)
1181 bool ret
= GetDiskFreeSpaceExW(
1182 o3tl::toW(path
.getStr()),
1183 reinterpret_cast<PULARGE_INTEGER
>(&pInfo
->uFreeSpace
),
1184 reinterpret_cast<PULARGE_INTEGER
>(&pInfo
->uTotalSpace
),
1189 pInfo
->uUsedSpace
= pInfo
->uTotalSpace
- pInfo
->uFreeSpace
;
1190 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_TotalSpace
|
1191 osl_VolumeInfo_Mask_UsedSpace
|
1192 osl_VolumeInfo_Mask_FreeSpace
;
1196 static bool is_filesystem_attributes_request(sal_uInt32 field_mask
)
1198 return (field_mask
&
1199 (osl_VolumeInfo_Mask_MaxNameLength
|
1200 osl_VolumeInfo_Mask_MaxPathLength
|
1201 osl_VolumeInfo_Mask_FileSystemName
|
1202 osl_VolumeInfo_Mask_FileSystemCaseHandling
));
1205 static oslFileError
get_filesystem_attributes(
1206 const OUString
& path
, sal_uInt32 field_mask
, oslVolumeInfo
* pInfo
)
1208 pInfo
->uAttributes
= 0;
1210 // osl_get_drive_type must be called first because
1211 // this function resets osl_VolumeInfo_Mask_Attributes
1213 if (is_drivetype_request(field_mask
))
1215 oslFileError osl_error
= osl_get_drive_type(path
, pInfo
);
1216 if (osl_File_E_None
!= osl_error
)
1219 if (is_filesystem_attributes_request(field_mask
))
1221 /* the following two parameters can not be longer than MAX_PATH+1 */
1222 WCHAR vn
[MAX_PATH
+1];
1223 WCHAR fsn
[MAX_PATH
+1];
1229 LPCWSTR pszPath
= o3tl::toW(path
.getStr());
1230 if (GetVolumeInformationW(pszPath
, vn
, MAX_PATH
+1, &serial
, &mcl
, &flags
, fsn
, MAX_PATH
+1))
1232 // Currently sal does not use this value, instead MAX_PATH is used
1233 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_MaxNameLength
;
1234 pInfo
->uMaxNameLength
= mcl
;
1236 // Should the uMaxPathLength be set to 32767, "\\?\" prefix allows it
1237 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_MaxPathLength
;
1238 pInfo
->uMaxPathLength
= MAX_PATH
;
1240 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_FileSystemName
;
1241 rtl_uString_newFromStr(&pInfo
->ustrFileSystemName
, o3tl::toU(fsn
));
1243 // volumes (even NTFS) will always be considered case
1244 // insensitive because the Win32 API is not able to
1245 // deal with case sensitive volumes see M$ Knowledge Base
1246 // article 100625 that's why we never set the attribute
1247 // osl_Volume_Attribute_Case_Sensitive
1249 if (flags
& FS_CASE_IS_PRESERVED
)
1250 pInfo
->uAttributes
|= osl_Volume_Attribute_Case_Is_Preserved
;
1252 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_Attributes
;
1255 return osl_File_E_None
;
1258 static bool path_get_parent(OUString
& path
)
1260 OSL_PRECOND(path
.lastIndexOf('/') == -1, "Path must not have slashes");
1262 if (!has_path_parent(path
))
1264 sal_Int32 i
= path
.lastIndexOf('\\');
1267 path
= path
.copy(0, i
);
1274 static void path_travel_to_volume_root(const OUString
& system_path
, OUString
& volume_root
)
1276 OUString
sys_path(system_path
);
1278 while(!is_volume_mount_point(sys_path
) && path_get_parent(sys_path
))
1281 volume_root
= sys_path
;
1282 systemPathEnsureSeparator(volume_root
);
1285 oslFileError SAL_CALL
osl_getVolumeInformation(
1286 rtl_uString
*ustrURL
, oslVolumeInfo
*pInfo
, sal_uInt32 uFieldMask
)
1289 return osl_File_E_INVAL
;
1291 OUString system_path
;
1292 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&ustrURL
), &system_path
.pData
, false);
1294 if (osl_File_E_None
!= error
)
1297 OUString volume_root
;
1298 path_travel_to_volume_root(system_path
, volume_root
);
1300 pInfo
->uValidFields
= 0;
1302 if ((error
= get_filesystem_attributes(volume_root
, uFieldMask
, pInfo
)) != osl_File_E_None
)
1305 if (is_volume_space_info_request(uFieldMask
))
1306 get_volume_space_information(volume_root
, pInfo
);
1308 if (uFieldMask
& osl_VolumeInfo_Mask_DeviceHandle
)
1310 error
= osl_getFileURLFromSystemPath(volume_root
.pData
, reinterpret_cast<rtl_uString
**>(&pInfo
->pDeviceHandle
));
1311 if (error
!= osl_File_E_None
)
1313 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_DeviceHandle
;
1316 return osl_File_E_None
;
1319 static oslFileError
osl_getDriveInfo(
1320 oslDirectoryItem Item
, oslFileStatus
*pStatus
, sal_uInt32 uFieldMask
)
1322 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1323 WCHAR cDrive
[3] = L
"A:";
1324 WCHAR cRoot
[4] = L
"A:\\";
1327 return osl_File_E_INVAL
;
1329 pStatus
->uValidFields
= 0;
1331 cDrive
[0] = pItemImpl
->cDriveString
[0];
1332 cRoot
[0] = pItemImpl
->cDriveString
[0];
1334 if ( uFieldMask
& osl_FileStatus_Mask_FileName
)
1336 if ( pItemImpl
->cDriveString
[0] == '\\' && pItemImpl
->cDriveString
[1] == '\\' )
1338 LPCWSTR lpFirstBkSlash
= wcschr( &pItemImpl
->cDriveString
[2], '\\' );
1340 if ( lpFirstBkSlash
&& lpFirstBkSlash
[1] )
1342 LPCWSTR lpLastBkSlash
= wcschr( &lpFirstBkSlash
[1], '\\' );
1344 if ( lpLastBkSlash
)
1345 rtl_uString_newFromStr_WithLength( &pStatus
->ustrFileName
, o3tl::toU(&lpFirstBkSlash
[1]), lpLastBkSlash
- lpFirstBkSlash
- 1 );
1347 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(&lpFirstBkSlash
[1]) );
1348 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1351 else switch ( GetDriveTypeW( cRoot
) )
1355 WCHAR szBuffer
[1024];
1356 DWORD
const dwBufsizeConst
= SAL_N_ELEMENTS(szBuffer
);
1357 DWORD dwBufsize
= dwBufsizeConst
;
1359 DWORD dwResult
= WNetGetConnectionW( cDrive
, szBuffer
, &dwBufsize
);
1360 if ( NO_ERROR
== dwResult
)
1362 WCHAR szFileName
[dwBufsizeConst
+ 16];
1364 swprintf( szFileName
, L
"%s [%s]", cDrive
, szBuffer
);
1365 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(szFileName
) );
1368 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cDrive
) );
1370 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1374 WCHAR szVolumeNameBuffer
[1024];
1375 DWORD
const dwBufsizeConst
= SAL_N_ELEMENTS(szVolumeNameBuffer
);
1377 if ( GetVolumeInformationW( cRoot
, szVolumeNameBuffer
, dwBufsizeConst
, nullptr, nullptr, nullptr, nullptr, 0 ) )
1379 WCHAR szFileName
[dwBufsizeConst
+ 16];
1381 swprintf( szFileName
, L
"%s [%s]", cDrive
, szVolumeNameBuffer
);
1382 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(szFileName
) );
1385 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cDrive
) );
1387 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1390 case DRIVE_REMOVABLE
:
1391 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1392 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cRoot
) );
1400 pStatus
->eType
= osl_File_Type_Volume
;
1401 pStatus
->uValidFields
|= osl_FileStatus_Mask_Type
;
1403 if ( uFieldMask
& osl_FileStatus_Mask_FileURL
)
1405 rtl_uString
*ustrSystemPath
= nullptr;
1407 rtl_uString_newFromStr( &ustrSystemPath
, o3tl::toU(pItemImpl
->cDriveString
) );
1408 oslFileError error
= osl_getFileURLFromSystemPath( ustrSystemPath
, &pStatus
->ustrFileURL
);
1409 rtl_uString_release( ustrSystemPath
);
1410 if (error
!= osl_File_E_None
)
1412 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
1414 return osl_File_E_None
;
1417 static oslFileError
osl_getServerInfo(
1418 oslDirectoryItem Item
, oslFileStatus
*pStatus
, sal_uInt32 uFieldMask
)
1420 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1422 return osl_File_E_INVAL
;
1424 pStatus
->uValidFields
= 0;
1425 pStatus
->eType
= osl_File_Type_Directory
;
1426 pStatus
->uValidFields
|= osl_FileStatus_Mask_Type
;
1428 if ( uFieldMask
& osl_FileStatus_Mask_FileURL
)
1430 oslFileError error
= osl_getFileURLFromSystemPath( pItemImpl
->m_sFullPath
.pData
, &pStatus
->ustrFileURL
);
1431 if (error
!= osl_File_E_None
)
1433 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
1435 return osl_File_E_None
;
1438 oslFileError SAL_CALL
osl_getFileStatus(
1439 oslDirectoryItem Item
,
1440 oslFileStatus
*pStatus
,
1441 sal_uInt32 uFieldMask
)
1443 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1446 return osl_File_E_INVAL
;
1448 switch ( pItemImpl
->uType
)
1450 case DIRECTORYITEM_DRIVE
:
1451 return osl_getDriveInfo( Item
, pStatus
, uFieldMask
);
1452 case DIRECTORYITEM_SERVER
:
1453 return osl_getServerInfo( Item
, pStatus
, uFieldMask
);
1458 OUString
sFullPath(pItemImpl
->m_sFullPath
);
1460 // Prefix long paths, windows API calls expect this prefix
1461 // (only local paths starting with something like C: or D:)
1462 if (sFullPath
.getLength() >= MAX_PATH
&& isalpha(sFullPath
[0]) && sFullPath
[1] == ':')
1463 sFullPath
= "\\\\?\\" + sFullPath
;
1465 if ( uFieldMask
& osl_FileStatus_Mask_Validate
)
1467 HANDLE hFind
= FindFirstFileW( o3tl::toW(sFullPath
.getStr() ), &pItemImpl
->FindData
);
1469 if ( hFind
!= INVALID_HANDLE_VALUE
)
1472 return oslTranslateFileError( GetLastError() );
1474 uFieldMask
&= ~ osl_FileStatus_Mask_Validate
;
1477 /* If no fields to retrieve left ignore pStatus */
1479 return osl_File_E_None
;
1481 /* Otherwise, this must be a valid pointer */
1483 return osl_File_E_INVAL
;
1485 if ( pStatus
->uStructSize
!= sizeof(oslFileStatus
) )
1486 return osl_File_E_INVAL
;
1488 pStatus
->uValidFields
= 0;
1490 /* File time stamps */
1492 if ( (uFieldMask
& osl_FileStatus_Mask_ModifyTime
) &&
1493 FileTimeToTimeValue( &pItemImpl
->FindData
.ftLastWriteTime
, &pStatus
->aModifyTime
) )
1494 pStatus
->uValidFields
|= osl_FileStatus_Mask_ModifyTime
;
1496 if ( (uFieldMask
& osl_FileStatus_Mask_AccessTime
) &&
1497 FileTimeToTimeValue( &pItemImpl
->FindData
.ftLastAccessTime
, &pStatus
->aAccessTime
) )
1498 pStatus
->uValidFields
|= osl_FileStatus_Mask_AccessTime
;
1500 if ( (uFieldMask
& osl_FileStatus_Mask_CreationTime
) &&
1501 FileTimeToTimeValue( &pItemImpl
->FindData
.ftCreationTime
, &pStatus
->aCreationTime
) )
1502 pStatus
->uValidFields
|= osl_FileStatus_Mask_CreationTime
;
1504 /* Most of the fields are already set, regardless of required fields */
1506 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(pItemImpl
->FindData
.cFileName
) );
1507 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1509 if ((FILE_ATTRIBUTE_REPARSE_POINT
& pItemImpl
->FindData
.dwFileAttributes
) &&
1510 (IO_REPARSE_TAG_MOUNT_POINT
== pItemImpl
->FindData
.dwReserved0
))
1511 pStatus
->eType
= osl_File_Type_Volume
;
1512 else if (pItemImpl
->FindData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1513 pStatus
->eType
= osl_File_Type_Directory
;
1515 pStatus
->eType
= osl_File_Type_Regular
;
1517 pStatus
->uValidFields
|= osl_FileStatus_Mask_Type
;
1519 pStatus
->uAttributes
= pItemImpl
->FindData
.dwFileAttributes
;
1520 // tdf#157448: RO attribute is ignored for directories on Windows:
1521 // https://learn.microsoft.com/en-us/windows/desktop/FileIO/file-attribute-constants
1522 if (pStatus
->uAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1523 pStatus
->uAttributes
&= ~sal_uInt64(FILE_ATTRIBUTE_READONLY
);
1524 pStatus
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
1526 pStatus
->uFileSize
= static_cast<sal_uInt64
>(pItemImpl
->FindData
.nFileSizeLow
) + (static_cast<sal_uInt64
>(pItemImpl
->FindData
.nFileSizeHigh
) << 32);
1527 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileSize
;
1529 if ( uFieldMask
& osl_FileStatus_Mask_LinkTargetURL
)
1531 oslFileError error
= osl_getFileURLFromSystemPath( sFullPath
.pData
, &pStatus
->ustrLinkTargetURL
);
1532 if (error
!= osl_File_E_None
)
1535 pStatus
->uValidFields
|= osl_FileStatus_Mask_LinkTargetURL
;
1538 if ( uFieldMask
& osl_FileStatus_Mask_FileURL
)
1540 if ( !pItemImpl
->bFullPathNormalized
)
1542 ::osl::LongPathBuffer
<sal_Unicode
> aBuffer(MAX_LONG_PATH
);
1543 sal_uInt32 nNewLen
= GetLongPathNameW(o3tl::toW(sFullPath
.getStr()), o3tl::toW(aBuffer
),
1544 aBuffer
.getBufSizeInSymbols());
1548 /* Capitalizes drive name (single letter). Windows file paths are processed
1549 case-sensitively. While parsing a path, function osl_DirectoryItem has case
1550 PATHTYPE_VOLUME for drives, and capitalizes them. That can be overwritten by
1551 function osl_getFileStatus, in it win32 api GetLongPathNameW does no
1552 capitalization. Thus it needs to be postprocessed.*/
1553 sal_Int32 nIndex
= rtl_ustr_indexOfChar(aBuffer
, ':');
1555 aBuffer
[nIndex
- 1] = rtl::toAsciiUpperCase(aBuffer
[nIndex
- 1]);
1558 pItemImpl
->m_sFullPath
= OUString(&*aBuffer
, nNewLen
);
1559 sFullPath
= pItemImpl
->m_sFullPath
;
1560 pItemImpl
->bFullPathNormalized
= true;
1564 oslFileError error
= osl_getFileURLFromSystemPath( sFullPath
.pData
, &pStatus
->ustrFileURL
);
1565 if (error
!= osl_File_E_None
)
1567 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
1570 return osl_File_E_None
;
1573 oslFileError SAL_CALL
osl_setFileAttributes(
1574 rtl_uString
*ustrFileURL
,
1575 sal_uInt64 uAttributes
)
1578 OUString ustrSysPath
;
1579 DWORD dwFileAttributes
;
1582 // Converts the normalized path into a systempath
1583 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&ustrFileURL
), &ustrSysPath
.pData
, false);
1585 if ( osl_File_E_None
!= error
)
1588 dwFileAttributes
= GetFileAttributesW(o3tl::toW(ustrSysPath
.getStr()));
1590 if ( DWORD(-1) != dwFileAttributes
)
1592 dwFileAttributes
&= ~(FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
);
1594 if ( uAttributes
& osl_File_Attribute_ReadOnly
)
1595 dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
1597 if ( uAttributes
& osl_File_Attribute_Hidden
)
1598 dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
1600 fSuccess
= SetFileAttributesW(o3tl::toW(ustrSysPath
.getStr()), dwFileAttributes
);
1608 error
= oslTranslateFileError( GetLastError() );
1613 oslFileError SAL_CALL
osl_setFileTime(
1614 rtl_uString
*filePath
,
1615 const TimeValue
*aCreationTime
,
1616 const TimeValue
*aLastAccessTime
,
1617 const TimeValue
*aLastWriteTime
)
1621 FILETIME
*lpCreationTime
=nullptr;
1622 FILETIME
*lpLastAccessTime
=nullptr;
1623 FILETIME
*lpLastWriteTime
=nullptr;
1624 FILETIME ftCreationTime
;
1625 FILETIME ftLastAccessTime
;
1626 FILETIME ftLastWriteTime
;
1630 error
=osl_getSystemPathFromFileURL_(OUString::unacquired(&filePath
), &sysPath
.pData
, false);
1632 if (error
==osl_File_E_INVAL
)
1635 hFile
=CreateFileW(o3tl::toW(sysPath
.getStr()), GENERIC_WRITE
, 0, nullptr , OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr);
1637 if (hFile
==INVALID_HANDLE_VALUE
)
1638 return osl_File_E_NOENT
;
1640 if (TimeValueToFileTime(aCreationTime
, &ftCreationTime
))
1641 lpCreationTime
=&ftCreationTime
;
1643 if (TimeValueToFileTime(aLastAccessTime
, &ftLastAccessTime
))
1644 lpLastAccessTime
=&ftLastAccessTime
;
1646 if (TimeValueToFileTime(aLastWriteTime
, &ftLastWriteTime
))
1647 lpLastWriteTime
=&ftLastWriteTime
;
1649 fSuccess
=SetFileTime(hFile
, lpCreationTime
, lpLastAccessTime
, lpLastWriteTime
);
1654 return osl_File_E_INVAL
;
1656 return osl_File_E_None
;
1659 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */