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>
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
;
43 bool fSuccess
= false;
45 BaseSysTime
.wYear
= 1970;
46 BaseSysTime
.wMonth
= 1;
47 BaseSysTime
.wDayOfWeek
= 0;
49 BaseSysTime
.wHour
= 0;
50 BaseSysTime
.wMinute
= 0;
51 BaseSysTime
.wSecond
= 0;
52 BaseSysTime
.wMilliseconds
= 0;
54 if (cpTimeVal
==nullptr)
57 if ( SystemTimeToFileTime(&BaseSysTime
, &BaseFileTime
) )
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
));
65 osl::detail::setFiletime(*pFTime
, timeValue
);
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;
80 BaseSysTime
.wHour
= 0;
81 BaseSysTime
.wMinute
= 0;
82 BaseSysTime
.wSecond
= 0;
83 BaseSysTime
.wMilliseconds
= 0;
85 if ( SystemTimeToFileTime(&BaseSysTime
, &BaseFileTime
) )
89 fSuccess
= 0 <= (Value
= osl::detail::getFiletime(*cpFTime
) - osl::detail::getFiletime(BaseFileTime
));
93 pTimeVal
->Seconds
= static_cast<unsigned long>(Value
/ 10000000L);
94 pTimeVal
->Nanosec
= static_cast<unsigned long>((Value
% 10000000L) * 100);
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_
;
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
))
138 puncc
->server_
.end_
= ppos
;
140 if (BACKSLASH
== *ppos
)
142 puncc
->share_
.begin_
= ++ppos
;
143 while ((ppos
< pend
) && (*ppos
!= BACKSLASH
))
146 puncc
->share_
.end_
= ppos
;
148 if (BACKSLASH
== *ppos
)
150 puncc
->resource_
.begin_
= ++ppos
;
154 puncc
->resource_
.end_
= ppos
;
158 SAL_WARN_IF(!puncc
->server_
.isPresent() || !puncc
->share_
.isPresent(),
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();
177 has_parent
= !osl::systemPathIsLogicalDrivePattern(OUString(path
));
182 bool has_path_parent(const OUString
& path
)
183 { return has_path_parent(path
.getStr()); }
187 oslFileError SAL_CALL
osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle
)
191 rtl_uString_acquire( static_cast<rtl_uString
*>(Handle
) );
192 return osl_File_E_None
;
195 return osl_File_E_INVAL
;
198 oslFileError SAL_CALL
osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle
)
202 rtl_uString_release( static_cast<rtl_uString
*>(Handle
) );
203 return osl_File_E_None
;
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
;
217 return osl_File_E_INVAL
;
220 #define DIRECTORYITEM_DRIVE 0
221 #define DIRECTORYITEM_FILE 1
222 #define DIRECTORYITEM_SERVER 2
226 struct DirectoryItem_Impl
230 WIN32_FIND_DATAW FindData
;
231 WCHAR cDriveString
[MAX_PATH
];
233 OUString m_sFullPath
;
234 bool bFullPathNormalized
= false;
240 #define DIRECTORYTYPE_LOCALROOT 0
241 #define DIRECTORYTYPE_NETROOT 1
242 #define DIRECTORYTYPE_FILESYSTEM 3
246 struct Directory_Impl
250 HANDLE hDirectory
= nullptr;
253 OUString m_sDirectoryPath
;
256 typedef struct tagDRIVEENUM
259 WCHAR cBuffer
[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256];
261 } DRIVEENUM
, *PDRIVEENUM
, *LPDRIVEENUM
;
265 static HANDLE WINAPI
OpenLogicalDrivesEnum()
267 LPDRIVEENUM pEnum
= static_cast<LPDRIVEENUM
>(HeapAlloc( GetProcessHeap(), 0, sizeof(DRIVEENUM
) ));
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";
279 HeapFree( GetProcessHeap(), 0, pEnum
);
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
);
291 SetLastError( ERROR_INVALID_HANDLE
);
295 int nLen
= wcslen( pEnum
->lpCurrent
);
298 SetLastError( ERROR_NO_MORE_FILES
);
302 CopyMemory( lpBuffer
, pEnum
->lpCurrent
, (nLen
+ 1) * sizeof(WCHAR
) );
303 pEnum
->lpCurrent
+= nLen
+ 1;
307 static bool WINAPI
CloseLogicalDrivesEnum(HANDLE hEnum
)
309 bool fSuccess
= false;
310 LPDRIVEENUM pEnum
= static_cast<LPDRIVEENUM
>(hEnum
);
314 HeapFree( GetProcessHeap(), 0, pEnum
);
318 SetLastError( ERROR_INVALID_HANDLE
);
325 typedef struct tagDIRECTORY
328 WIN32_FIND_DATAW aFirstData
;
329 } DIRECTORY
, *PDIRECTORY
, *LPDIRECTORY
;
333 static HANDLE WINAPI
OpenDirectory( rtl_uString
* pPath
)
338 sal_uInt32 nLen
= rtl_uString_getLength( pPath
);
342 const WCHAR
* pSuffix
= nullptr;
343 sal_uInt32 nSuffLen
= 0;
344 if ( pPath
->buffer
[nLen
- 1] != L
'\\' )
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;
374 return static_cast<HANDLE
>(pDirectory
);
377 static bool WINAPI
EnumDirectory(HANDLE hDirectory
, LPWIN32_FIND_DATAW pFindData
)
379 LPDIRECTORY pDirectory
= static_cast<LPDIRECTORY
>(hDirectory
);
382 SetLastError( ERROR_INVALID_HANDLE
);
386 bool fSuccess
= false;
390 if ( pDirectory
->aFirstData
.cFileName
[0] )
392 *pFindData
= pDirectory
->aFirstData
;
394 pDirectory
->aFirstData
.cFileName
[0] = 0;
396 else if ( IsValidHandle( pDirectory
->hFind
) )
397 fSuccess
= FindNextFileW( pDirectory
->hFind
, pFindData
);
401 SetLastError( ERROR_NO_MORE_FILES
);
404 fValid
= fSuccess
&& wcscmp( L
".", pFindData
->cFileName
) != 0 && wcscmp( L
"..", pFindData
->cFileName
) != 0;
406 } while( fSuccess
&& !fValid
);
411 static bool WINAPI
CloseDirectory(HANDLE hDirectory
)
413 bool fSuccess
= false;
414 LPDIRECTORY pDirectory
= static_cast<LPDIRECTORY
>(hDirectory
);
418 if (IsValidHandle(pDirectory
->hFind
))
419 fSuccess
= FindClose(pDirectory
->hFind
);
421 fSuccess
= HeapFree(GetProcessHeap(), 0, pDirectory
) && fSuccess
;
424 SetLastError(ERROR_INVALID_HANDLE
);
429 static oslFileError
osl_openLocalRoot(
430 rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
433 return osl_File_E_INVAL
;
435 *pDirectory
= nullptr;
438 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strDirectoryPath
), &strSysPath
.pData
, false);
439 if ( osl_File_E_None
!= 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 */
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();
461 Use IsValidHandle(...)
463 if ( pDirImpl
->hEnumDrives
!= INVALID_HANDLE_VALUE
)
465 *pDirectory
= static_cast<oslDirectory
>(pDirImpl
);
466 error
= osl_File_E_None
;
476 error
= oslTranslateFileError( GetLastError() );
481 static oslFileError
osl_openFileDirectory(
482 rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
484 oslFileError error
= osl_File_E_None
;
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 */
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() );
514 *pDirectory
= static_cast<oslDirectory
>(pDirImpl
);
518 static oslFileError
osl_openNetworkServer(
519 rtl_uString
*strSysDirPath
, oslDirectory
*pDirectory
)
521 NETRESOURCEW aNetResource
;
525 ZeroMemory( &aNetResource
, sizeof(aNetResource
) );
527 aNetResource
.lpRemoteName
= o3tl::toW(strSysDirPath
->buffer
);
529 dwError
= WNetOpenEnumW(
532 RESOURCEUSAGE_CONNECTABLE
| RESOURCEUSAGE_CONTAINER
,
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
,
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 );
560 if (aDirectoryCreationCallbackFunc
)
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
,
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
))
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
)
616 return create_dir_recursively_(dir_path
, aDirectoryCreationCallbackFunc
, pData
);
619 oslFileError SAL_CALL
osl_createDirectoryPath(
620 rtl_uString
* aDirectoryUrl
,
621 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
624 if (aDirectoryUrl
== nullptr)
625 return osl_File_E_INVAL
;
628 oslFileError osl_error
=
629 osl_getSystemPathFromFileURL_(OUString::unacquired(&aDirectoryUrl
), &sys_path
.pData
, false);
631 if (osl_error
!= osl_File_E_None
)
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
)
652 oslFileError error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strPath
), &strSysPath
.pData
, false);
654 if ( osl_File_E_None
!= error
)
657 bool bCreated
= CreateDirectoryW(o3tl::toW(strSysPath
.getStr()), nullptr);
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() );
676 oslFileError SAL_CALL
osl_removeDirectory(rtl_uString
* strPath
)
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
;
686 error
= oslTranslateFileError( GetLastError() );
691 oslFileError SAL_CALL
osl_openDirectory(rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
695 if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath
->buffer
, "file:///" ) )
696 error
= osl_openLocalRoot( strDirectoryPath
, pDirectory
);
699 OUString strSysDirectoryPath
;
702 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strDirectoryPath
), &strSysDirectoryPath
.pData
, false);
704 if ( osl_File_E_None
!= error
)
707 dwPathType
= IsValidFilePath(strSysDirectoryPath
, VALIDATEPATH_NORMAL
, nullptr);
709 if ( dwPathType
& PATHTYPE_IS_SERVER
)
710 error
= osl_openNetworkServer(strSysDirectoryPath
.pData
, pDirectory
);
712 error
= osl_openFileDirectory(strSysDirectoryPath
.pData
, pDirectory
);
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;
723 LPNETRESOURCEW lpNetResource
= reinterpret_cast<LPNETRESOURCEW
>(buffer
);
724 DWORD dwError
, dwCount
, dwBufSize
;
727 return osl_File_E_INVAL
;
731 return osl_File_E_INVAL
;
734 dwBufSize
= sizeof(buffer
);
735 dwError
= WNetEnumResourceW( pDirImpl
->hDirectory
, &dwCount
, lpNetResource
, &dwBufSize
);
740 case ERROR_MORE_DATA
:
742 pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
744 return osl_File_E_NOMEM
;
746 pItemImpl
->uType
= DIRECTORYITEM_DRIVE
;
747 osl_acquireDirectoryItem( static_cast<oslDirectoryItem
>(pItemImpl
) );
749 wcscpy( pItemImpl
->cDriveString
, lpNetResource
->lpRemoteName
);
753 return osl_File_E_None
;
754 case ERROR_NO_MORE_ITEMS
:
755 return osl_File_E_NOENT
;
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;
769 return osl_File_E_INVAL
;
773 return osl_File_E_INVAL
;
775 pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
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
);
786 return osl_File_E_None
;
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;
803 return osl_File_E_INVAL
;
807 return osl_File_E_INVAL
;
809 pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
811 return osl_File_E_NOMEM
;
813 fFound
= EnumDirectory( pDirImpl
->hDirectory
, &pItemImpl
->FindData
);
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
);
838 return osl_File_E_INVAL
;
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
);
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
;
864 switch ( pDirImpl
->uType
)
866 case DIRECTORYTYPE_FILESYSTEM
:
867 eError
= CloseDirectory( pDirImpl
->hDirectory
) ? osl_File_E_None
: oslTranslateFileError( GetLastError() );
869 case DIRECTORYTYPE_LOCALROOT
:
870 eError
= CloseLogicalDrivesEnum( pDirImpl
->hEnumDrives
) ? osl_File_E_None
: oslTranslateFileError( GetLastError() );
872 case DIRECTORYTYPE_NETROOT
:
874 DWORD err
= WNetCloseEnum(pDirImpl
->hDirectory
);
875 eError
= (err
== NO_ERROR
) ? osl_File_E_None
: oslTranslateFileError(err
);
879 OSL_FAIL( "Invalid directory type" );
890 /* Different types of paths */
893 PATHTYPE_SYNTAXERROR
= 0,
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
;
912 return osl_File_E_INVAL
;
916 error
= osl_getSystemPathFromFileURL_(OUString::unacquired(&strFilePath
), &strSysFilePath
.pData
, false);
918 if ( osl_File_E_None
!= 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
;
928 type
= PATHTYPE_FILE
;
932 case PATHTYPE_NETSERVER
:
934 DirectoryItem_Impl
* pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
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
951 while( iSrc
< strSysFilePath
.getLength() && strSysFilePath
[iSrc
] && strSysFilePath
[iSrc
] != '\\')
953 pItemImpl
->FindData
.cFileName
[iDst
++] = strSysFilePath
[iSrc
++];
961 case PATHTYPE_VOLUME
:
963 DirectoryItem_Impl
* pItemImpl
= new (std::nothrow
) DirectoryItem_Impl
;
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
"\\" );
984 case PATHTYPE_SYNTAXERROR
:
985 case PATHTYPE_NETROOT
:
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
;
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
;
1016 error
= oslTranslateFileError( GetLastError() );
1024 oslFileError SAL_CALL
osl_acquireDirectoryItem( oslDirectoryItem Item
)
1026 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
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
);
1040 return osl_File_E_INVAL
;
1042 if ( ! --pItemImpl
->nRefCount
)
1045 return osl_File_E_None
;
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
);
1055 /* same name => same item, unless renaming / moving madness has occurred */
1056 if (pA
->m_sFullPath
== pB
->m_sFullPath
)
1059 // FIXME: as/when/if this is used in anger on Windows we could
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:\\";
1079 osl::systemPathEnsureSeparator(p
);
1082 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p
.getStr()), vn
, SAL_N_ELEMENTS(vn
)))
1085 if (is_floppy_A_present() &&
1086 GetVolumeNameForVolumeMountPointW(FLOPPY_A
, vnfloppy
, SAL_N_ELEMENTS(vnfloppy
)) &&
1087 (0 == wcscmp(vn
, vnfloppy
)))
1090 if (is_floppy_B_present() &&
1091 GetVolumeNameForVolumeMountPointW(FLOPPY_B
, vnfloppy
, SAL_N_ELEMENTS(vnfloppy
)) &&
1092 (0 == wcscmp(vn
, vnfloppy
)))
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
)
1115 osl::systemPathRemoveSeparator(p
);
1117 if (is_floppy_drive(p
))
1120 DWORD fattr
= GetFileAttributesW(o3tl::toW(p
.getStr()));
1121 if ((INVALID_FILE_ATTRIBUTES
== fattr
) ||
1122 !(FILE_ATTRIBUTE_REPARSE_POINT
& fattr
))
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
))
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);
1146 osl::systemPathEnsureSeparator(p
);
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
1166 if (is_volume_mount_point(path
))
1167 drive_type
= get_volume_mount_point_drive_type(path
);
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
;
1179 pInfo
->uAttributes
|= osl_Volume_Attribute_CompactDisc
| osl_Volume_Attribute_Removeable
;
1181 case DRIVE_REMOVABLE
:
1182 pInfo
->uAttributes
|= osl_Volume_Attribute_Removeable
;
1183 if (is_floppy_drive(path
))
1184 pInfo
->uAttributes
|= osl_Volume_Attribute_FloppyDisk
;
1187 pInfo
->uAttributes
|= osl_Volume_Attribute_FixedDisk
;
1190 pInfo
->uAttributes
|= osl_Volume_Attribute_RAMDisk
;
1193 pInfo
->uAttributes
|= osl_Volume_Attribute_Remote
;
1196 pInfo
->uAttributes
= 0;
1199 pInfo
->uValidFields
&= ~osl_VolumeInfo_Mask_Attributes
;
1200 pInfo
->uAttributes
= 0;
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
),
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
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
)
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];
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
);
1303 path
= OUString(path
.getStr(), i
);
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
))
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
)
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
)
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
)
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
)
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:\\";
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 );
1383 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(&lpFirstBkSlash
[1]) );
1384 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1387 else switch ( GetDriveTypeW( cRoot
) )
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
) );
1404 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cDrive
) );
1406 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
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
) );
1421 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cDrive
) );
1423 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1426 case DRIVE_REMOVABLE
:
1427 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1428 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cRoot
) );
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
)
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
);
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
)
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
);
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
);
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
)
1508 return oslTranslateFileError( GetLastError() );
1510 uFieldMask
&= ~ osl_FileStatus_Mask_Validate
;
1513 /* If no fields to retrieve left ignore pStatus */
1515 return osl_File_E_None
;
1517 /* Otherwise, this must be a valid pointer */
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
;
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
)
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());
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
, ':');
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
)
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
)
1610 OUString ustrSysPath
;
1611 DWORD dwFileAttributes
;
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
)
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
);
1640 error
= oslTranslateFileError( GetLastError() );
1645 oslFileError SAL_CALL
osl_setFileTime(
1646 rtl_uString
*filePath
,
1647 const TimeValue
*aCreationTime
,
1648 const TimeValue
*aLastAccessTime
,
1649 const TimeValue
*aLastWriteTime
)
1653 FILETIME
*lpCreationTime
=nullptr;
1654 FILETIME
*lpLastAccessTime
=nullptr;
1655 FILETIME
*lpLastWriteTime
=nullptr;
1656 FILETIME ftCreationTime
;
1657 FILETIME ftLastAccessTime
;
1658 FILETIME ftLastWriteTime
;
1662 error
=osl_getSystemPathFromFileURL_(OUString::unacquired(&filePath
), &sysPath
.pData
, false);
1664 if (error
==osl_File_E_INVAL
)
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
);
1686 return osl_File_E_INVAL
;
1688 return osl_File_E_None
;
1691 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */