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 static const wchar_t UNC_PREFIX
[] = L
"\\\\";
35 static const wchar_t BACKSLASH
= '\\';
36 static const wchar_t SLASH
= '/';
38 BOOL
TimeValueToFileTime(const TimeValue
*cpTimeVal
, FILETIME
*pFTime
)
40 SYSTEMTIME BaseSysTime
;
41 FILETIME BaseFileTime
;
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 inline bool is_UNC_path(const sal_Unicode
* path
)
124 { return (0 == wcsncmp(UNC_PREFIX
, o3tl::toW(path
), SAL_N_ELEMENTS(UNC_PREFIX
) - 1)); }
126 void parse_UNC_path(const sal_Unicode
* path
, UNCComponents
* puncc
)
128 OSL_PRECOND(is_UNC_path(path
), "Precondition violated: No UNC path");
129 OSL_PRECOND(rtl_ustr_indexOfChar(path
, SLASH
) == -1, "Path must not contain slashes");
131 const sal_Unicode
* pend
= path
+ rtl_ustr_getLength(path
);
132 const sal_Unicode
* ppos
= path
+ 2;
134 puncc
->server_
.begin_
= ppos
;
135 while ((ppos
< pend
) && (*ppos
!= BACKSLASH
))
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(path
);
182 inline 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
224 struct DirectoryItem_Impl
228 WIN32_FIND_DATAW FindData
;
229 WCHAR cDriveString
[MAX_PATH
];
231 rtl_uString
* m_pFullPath
;
232 BOOL bFullPathNormalized
;
236 #define DIRECTORYTYPE_LOCALROOT 0
237 #define DIRECTORYTYPE_NETROOT 1
238 #define DIRECTORYTYPE_FILESYSTEM 3
240 struct Directory_Impl
247 rtl_uString
* m_pDirectoryPath
;
250 typedef struct tagDRIVEENUM
253 WCHAR cBuffer
[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256];
255 } DRIVEENUM
, * PDRIVEENUM
, FAR
* LPDRIVEENUM
;
257 static HANDLE WINAPI
OpenLogicalDrivesEnum()
259 LPDRIVEENUM pEnum
= static_cast<LPDRIVEENUM
>(HeapAlloc( GetProcessHeap(), 0, sizeof(DRIVEENUM
) ));
262 DWORD dwNumCopied
= GetLogicalDriveStringsW( SAL_N_ELEMENTS(pEnum
->cBuffer
) - 1, pEnum
->cBuffer
);
264 if ( dwNumCopied
&& dwNumCopied
< SAL_N_ELEMENTS(pEnum
->cBuffer
) )
266 pEnum
->lpCurrent
= pEnum
->cBuffer
;
267 pEnum
->lpIdent
= L
"tagDRIVEENUM";
271 HeapFree( GetProcessHeap(), 0, pEnum
);
275 return pEnum
? static_cast<HANDLE
>(pEnum
) : INVALID_HANDLE_VALUE
;
278 static BOOL WINAPI
EnumLogicalDrives(HANDLE hEnum
, LPWSTR lpBuffer
)
280 BOOL fSuccess
= FALSE
;
281 LPDRIVEENUM pEnum
= static_cast<LPDRIVEENUM
>(hEnum
);
285 int nLen
= wcslen( pEnum
->lpCurrent
);
289 CopyMemory( lpBuffer
, pEnum
->lpCurrent
, (nLen
+ 1) * sizeof(WCHAR
) );
290 pEnum
->lpCurrent
+= nLen
+ 1;
294 SetLastError( ERROR_NO_MORE_FILES
);
297 SetLastError( ERROR_INVALID_HANDLE
);
302 static BOOL WINAPI
CloseLogicalDrivesEnum(HANDLE hEnum
)
304 BOOL fSuccess
= FALSE
;
305 LPDRIVEENUM pEnum
= static_cast<LPDRIVEENUM
>(hEnum
);
309 HeapFree( GetProcessHeap(), 0, pEnum
);
313 SetLastError( ERROR_INVALID_HANDLE
);
318 typedef struct tagDIRECTORY
321 WIN32_FIND_DATAW aFirstData
;
322 } DIRECTORY
, *PDIRECTORY
, FAR
*LPDIRECTORY
;
324 static HANDLE WINAPI
OpenDirectory( rtl_uString
* pPath
)
326 LPDIRECTORY pDirectory
= nullptr;
330 sal_uInt32 nLen
= rtl_uString_getLength( pPath
);
333 const WCHAR
* pSuffix
= nullptr;
334 sal_uInt32 nSuffLen
= 0;
336 if ( pPath
->buffer
[nLen
- 1] != L
'\\' )
347 WCHAR
* szFileMask
= static_cast< WCHAR
* >( malloc( sizeof( WCHAR
) * ( nLen
+ nSuffLen
+ 1 ) ) );
349 wcscpy( szFileMask
, o3tl::toW(rtl_uString_getStr( pPath
)) );
350 wcscat( szFileMask
, pSuffix
);
352 pDirectory
= static_cast<LPDIRECTORY
>(HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY
)));
353 pDirectory
->hFind
= FindFirstFileW(szFileMask
, &pDirectory
->aFirstData
);
355 if (!IsValidHandle(pDirectory
->hFind
))
357 if ( GetLastError() != ERROR_NO_MORE_FILES
)
359 HeapFree(GetProcessHeap(), 0, pDirectory
);
360 pDirectory
= nullptr;
367 return static_cast<HANDLE
>(pDirectory
);
370 static BOOL WINAPI
EnumDirectory(HANDLE hDirectory
, LPWIN32_FIND_DATAW pFindData
)
372 BOOL fSuccess
= FALSE
;
373 LPDIRECTORY pDirectory
= static_cast<LPDIRECTORY
>(hDirectory
);
381 if ( pDirectory
->aFirstData
.cFileName
[0] )
383 *pFindData
= pDirectory
->aFirstData
;
385 pDirectory
->aFirstData
.cFileName
[0] = 0;
387 else if ( IsValidHandle( pDirectory
->hFind
) )
388 fSuccess
= FindNextFileW( pDirectory
->hFind
, pFindData
);
392 SetLastError( ERROR_NO_MORE_FILES
);
395 fValid
= fSuccess
&& wcscmp( L
".", pFindData
->cFileName
) != 0 && wcscmp( L
"..", pFindData
->cFileName
) != 0;
397 } while( fSuccess
&& !fValid
);
400 SetLastError( ERROR_INVALID_HANDLE
);
405 static BOOL WINAPI
CloseDirectory(HANDLE hDirectory
)
407 BOOL fSuccess
= FALSE
;
408 LPDIRECTORY pDirectory
= static_cast<LPDIRECTORY
>(hDirectory
);
412 if (IsValidHandle(pDirectory
->hFind
))
413 fSuccess
= FindClose(pDirectory
->hFind
);
415 fSuccess
= HeapFree(GetProcessHeap(), 0, pDirectory
) && fSuccess
;
418 SetLastError(ERROR_INVALID_HANDLE
);
423 static oslFileError
osl_openLocalRoot(
424 rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
426 rtl_uString
*strSysPath
= nullptr;
430 return osl_File_E_INVAL
;
432 *pDirectory
= nullptr;
434 error
= osl_getSystemPathFromFileURL_( strDirectoryPath
, &strSysPath
, false );
435 if ( osl_File_E_None
== error
)
437 Directory_Impl
*pDirImpl
;
439 pDirImpl
= static_cast<Directory_Impl
*>(malloc( sizeof(Directory_Impl
)));
440 ZeroMemory( pDirImpl
, sizeof(Directory_Impl
) );
441 rtl_uString_newFromString( &pDirImpl
->m_pDirectoryPath
, strSysPath
);
443 /* Append backslash if necessary */
446 use function ensure backslash
448 sal_uInt32 nLen
= rtl_uString_getLength( pDirImpl
->m_pDirectoryPath
);
449 if ( nLen
&& pDirImpl
->m_pDirectoryPath
->buffer
[nLen
- 1] != L
'\\' )
451 rtl_uString
* pCurDir
= nullptr;
452 rtl_uString
* pBackSlash
= nullptr;
454 rtl_uString_assign( &pCurDir
, pDirImpl
->m_pDirectoryPath
);
455 rtl_uString_newFromAscii( &pBackSlash
, "\\" );
456 rtl_uString_newConcat( &pDirImpl
->m_pDirectoryPath
, pCurDir
, pBackSlash
);
457 rtl_uString_release( pBackSlash
);
458 rtl_uString_release( pCurDir
);
461 pDirImpl
->uType
= DIRECTORYTYPE_LOCALROOT
;
462 pDirImpl
->hEnumDrives
= OpenLogicalDrivesEnum();
465 Use IsValidHandle(...)
467 if ( pDirImpl
->hEnumDrives
!= INVALID_HANDLE_VALUE
)
469 *pDirectory
= static_cast<oslDirectory
>(pDirImpl
);
470 error
= osl_File_E_None
;
476 if ( pDirImpl
->m_pDirectoryPath
)
478 rtl_uString_release( pDirImpl
->m_pDirectoryPath
);
479 pDirImpl
->m_pDirectoryPath
= nullptr;
486 error
= oslTranslateFileError( GetLastError() );
489 rtl_uString_release( strSysPath
);
494 static oslFileError
osl_openFileDirectory(
495 rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
497 oslFileError error
= osl_File_E_None
;
500 return osl_File_E_INVAL
;
501 *pDirectory
= nullptr;
503 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(malloc(sizeof(Directory_Impl
)));
504 ZeroMemory( pDirImpl
, sizeof(Directory_Impl
) );
505 rtl_uString_newFromString( &pDirImpl
->m_pDirectoryPath
, strDirectoryPath
);
507 /* Append backslash if necessary */
510 use function ensure backslash
512 sal_uInt32 nLen
= rtl_uString_getLength( pDirImpl
->m_pDirectoryPath
);
513 if ( nLen
&& pDirImpl
->m_pDirectoryPath
->buffer
[nLen
- 1] != L
'\\' )
515 rtl_uString
* pCurDir
= nullptr;
516 rtl_uString
* pBackSlash
= nullptr;
518 rtl_uString_assign( &pCurDir
, pDirImpl
->m_pDirectoryPath
);
519 rtl_uString_newFromAscii( &pBackSlash
, "\\" );
520 rtl_uString_newConcat( &pDirImpl
->m_pDirectoryPath
, pCurDir
, pBackSlash
);
521 rtl_uString_release( pBackSlash
);
522 rtl_uString_release( pCurDir
);
525 pDirImpl
->uType
= DIRECTORYTYPE_FILESYSTEM
;
526 pDirImpl
->hDirectory
= OpenDirectory( pDirImpl
->m_pDirectoryPath
);
528 if ( !pDirImpl
->hDirectory
)
530 error
= oslTranslateFileError( GetLastError() );
532 if ( pDirImpl
->m_pDirectoryPath
)
534 rtl_uString_release( pDirImpl
->m_pDirectoryPath
);
535 pDirImpl
->m_pDirectoryPath
= nullptr;
542 *pDirectory
= static_cast<oslDirectory
>(pDirImpl
);
546 static oslFileError
osl_openNetworkServer(
547 rtl_uString
*strSysDirPath
, oslDirectory
*pDirectory
)
549 NETRESOURCEW aNetResource
;
553 ZeroMemory( &aNetResource
, sizeof(aNetResource
) );
555 aNetResource
.lpRemoteName
= o3tl::toW(strSysDirPath
->buffer
);
557 dwError
= WNetOpenEnumW(
560 RESOURCEUSAGE_CONNECTABLE
| RESOURCEUSAGE_CONTAINER
,
564 if ( ERROR_SUCCESS
== dwError
)
566 Directory_Impl
*pDirImpl
;
568 pDirImpl
= static_cast<Directory_Impl
*>(malloc(sizeof(Directory_Impl
)));
569 ZeroMemory( pDirImpl
, sizeof(Directory_Impl
) );
570 pDirImpl
->uType
= DIRECTORYTYPE_NETROOT
;
571 pDirImpl
->hDirectory
= hEnum
;
572 *pDirectory
= static_cast<oslDirectory
>(pDirImpl
);
574 return oslTranslateFileError( dwError
);
577 static DWORD
create_dir_with_callback(
578 rtl_uString
* dir_path
,
579 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
582 // Create the specified directory and call the
583 // user specified callback function. On success
584 // the function returns ERROR_SUCCESS else a Win32 error code.
586 BOOL bCreated
= CreateDirectoryW( o3tl::toW(rtl_uString_getStr( dir_path
)), nullptr );
590 if (aDirectoryCreationCallbackFunc
)
593 osl_getFileURLFromSystemPath(dir_path
, &(url
.pData
));
594 aDirectoryCreationCallbackFunc(pData
, url
.pData
);
596 return ERROR_SUCCESS
;
598 return GetLastError();
601 static int path_make_parent(sal_Unicode
* path
)
603 /* Cut off the last part of the given path to
604 get the parent only, e.g. 'c:\dir\subdir' ->
605 'c:\dir' or '\\share\sub\dir' -> '\\share\sub'
606 @return The position where the path has been cut
607 off (this is the position of the last backslash).
608 If there are no more parents 0 will be returned,
609 e.g. 'c:\' or '\\Share' have no more parents */
611 OSL_PRECOND(rtl_ustr_indexOfChar(path
, SLASH
) == -1, "Path must not contain slashes");
612 OSL_PRECOND(has_path_parent(path
), "Path must have a parent");
614 sal_Unicode
* pos_last_backslash
= path
+ rtl_ustr_lastIndexOfChar(path
, BACKSLASH
);
615 *pos_last_backslash
= 0;
616 return (pos_last_backslash
- path
);
619 static DWORD
create_dir_recursively_(
620 rtl_uString
* dir_path
,
621 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
625 rtl_ustr_lastIndexOfChar_WithLength(dir_path
->buffer
, dir_path
->length
, BACKSLASH
) != dir_path
->length
,
626 "Path must not end with a backslash");
628 DWORD w32_error
= create_dir_with_callback(
629 dir_path
, aDirectoryCreationCallbackFunc
, pData
);
630 if (w32_error
== ERROR_SUCCESS
)
631 return ERROR_SUCCESS
;
633 if ((w32_error
!= ERROR_PATH_NOT_FOUND
) || !has_path_parent(dir_path
->buffer
))
636 int pos
= path_make_parent(dir_path
->buffer
); // dir_path->buffer[pos] = 0, restore below
638 w32_error
= create_dir_recursively_(
639 dir_path
, aDirectoryCreationCallbackFunc
, pData
);
641 dir_path
->buffer
[pos
] = BACKSLASH
; // restore
643 if (ERROR_SUCCESS
!= w32_error
&& ERROR_ALREADY_EXISTS
!= w32_error
)
646 return create_dir_recursively_(dir_path
, aDirectoryCreationCallbackFunc
, pData
);
649 oslFileError SAL_CALL
osl_createDirectoryPath(
650 rtl_uString
* aDirectoryUrl
,
651 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc
,
654 if (aDirectoryUrl
== nullptr)
655 return osl_File_E_INVAL
;
658 oslFileError osl_error
=
659 osl_getSystemPathFromFileURL_(aDirectoryUrl
, &sys_path
.pData
, false);
661 if (osl_error
!= osl_File_E_None
)
664 osl::systemPathRemoveSeparator(sys_path
);
666 // const_cast because sys_path is a local copy
667 // which we want to modify inplace instead of
668 // copy it into another buffer on the heap again
669 return oslTranslateFileError(create_dir_recursively_(
670 sys_path
.pData
, aDirectoryCreationCallbackFunc
, pData
));
673 oslFileError SAL_CALL
osl_createDirectory(rtl_uString
* strPath
)
675 return osl_createDirectoryWithFlags(
676 strPath
, osl_File_OpenFlag_Read
| osl_File_OpenFlag_Write
);
679 oslFileError
osl_createDirectoryWithFlags(rtl_uString
* strPath
, sal_uInt32
)
681 rtl_uString
*strSysPath
= nullptr;
682 oslFileError error
= osl_getSystemPathFromFileURL_( strPath
, &strSysPath
, false );
684 if ( osl_File_E_None
== error
)
686 BOOL bCreated
= CreateDirectoryW( o3tl::toW(rtl_uString_getStr( strSysPath
)), nullptr );
691 The following case is a hack because the ucb or the webtop had some
692 problems with the error code that CreateDirectory returns in
693 case the path is only a logical drive, should be removed!
696 const sal_Unicode
*pBuffer
= rtl_uString_getStr( strSysPath
);
697 sal_Int32 nLen
= rtl_uString_getLength( strSysPath
);
700 ( ( pBuffer
[0] >= 'A' && pBuffer
[0] <= 'Z' ) ||
701 ( pBuffer
[0] >= 'a' && pBuffer
[0] <= 'z' ) ) &&
702 pBuffer
[1] == ':' && ( nLen
==2 || ( nLen
== 3 && pBuffer
[2] == '\\' ) )
704 SetLastError( ERROR_ALREADY_EXISTS
);
706 error
= oslTranslateFileError( GetLastError() );
709 rtl_uString_release( strSysPath
);
714 oslFileError SAL_CALL
osl_removeDirectory(rtl_uString
* strPath
)
716 rtl_uString
*strSysPath
= nullptr;
717 oslFileError error
= osl_getSystemPathFromFileURL_( strPath
, &strSysPath
, false );
719 if ( osl_File_E_None
== error
)
721 if ( RemoveDirectoryW( o3tl::toW(rtl_uString_getStr( strSysPath
) )) )
722 error
= osl_File_E_None
;
724 error
= oslTranslateFileError( GetLastError() );
726 rtl_uString_release( strSysPath
);
731 oslFileError SAL_CALL
osl_openDirectory(rtl_uString
*strDirectoryPath
, oslDirectory
*pDirectory
)
735 if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath
->buffer
, "file:///" ) )
736 error
= osl_openLocalRoot( strDirectoryPath
, pDirectory
);
739 rtl_uString
*strSysDirectoryPath
= nullptr;
742 error
= osl_getSystemPathFromFileURL_( strDirectoryPath
, &strSysDirectoryPath
, false );
744 if ( osl_File_E_None
!= error
)
747 dwPathType
= IsValidFilePath( strSysDirectoryPath
, VALIDATEPATH_NORMAL
, nullptr );
749 if ( dwPathType
& PATHTYPE_IS_SERVER
)
751 error
= osl_openNetworkServer( strSysDirectoryPath
, pDirectory
);
754 error
= osl_openFileDirectory( strSysDirectoryPath
, pDirectory
);
756 rtl_uString_release( strSysDirectoryPath
);
761 static oslFileError
osl_getNextNetResource(
762 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32
/*uHint*/ )
764 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
765 DirectoryItem_Impl
*pItemImpl
= nullptr;
767 LPNETRESOURCEW lpNetResource
= reinterpret_cast<LPNETRESOURCEW
>(buffer
);
768 DWORD dwError
, dwCount
, dwBufSize
;
771 return osl_File_E_INVAL
;
775 return osl_File_E_INVAL
;
778 dwBufSize
= sizeof(buffer
);
779 dwError
= WNetEnumResourceW( pDirImpl
->hDirectory
, &dwCount
, lpNetResource
, &dwBufSize
);
784 case ERROR_MORE_DATA
:
786 pItemImpl
= static_cast<DirectoryItem_Impl
*>(malloc(sizeof(DirectoryItem_Impl
)));
788 return osl_File_E_NOMEM
;
790 ZeroMemory( pItemImpl
, sizeof(DirectoryItem_Impl
) );
791 pItemImpl
->uType
= DIRECTORYITEM_DRIVE
;
792 osl_acquireDirectoryItem( static_cast<oslDirectoryItem
>(pItemImpl
) );
794 wcscpy( pItemImpl
->cDriveString
, lpNetResource
->lpRemoteName
);
798 return osl_File_E_None
;
799 case ERROR_NO_MORE_ITEMS
:
800 return osl_File_E_NOENT
;
802 return oslTranslateFileError( dwError
);
806 static oslFileError
osl_getNextDrive(
807 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32
/*uHint*/ )
809 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
810 DirectoryItem_Impl
*pItemImpl
= nullptr;
814 return osl_File_E_INVAL
;
818 return osl_File_E_INVAL
;
820 pItemImpl
= static_cast<DirectoryItem_Impl
*>(malloc(sizeof(DirectoryItem_Impl
)));
822 return osl_File_E_NOMEM
;
824 ZeroMemory( pItemImpl
, sizeof(DirectoryItem_Impl
) );
825 pItemImpl
->uType
= DIRECTORYITEM_DRIVE
;
826 osl_acquireDirectoryItem( static_cast<oslDirectoryItem
>(pItemImpl
) );
827 fSuccess
= EnumLogicalDrives( pDirImpl
->hEnumDrives
, pItemImpl
->cDriveString
);
832 return osl_File_E_None
;
836 if ( pItemImpl
->m_pFullPath
)
838 rtl_uString_release( pItemImpl
->m_pFullPath
);
839 pItemImpl
->m_pFullPath
= nullptr;
843 return oslTranslateFileError( GetLastError() );
847 static oslFileError
osl_getNextFileItem(
848 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32
/*uHint*/)
850 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
851 DirectoryItem_Impl
*pItemImpl
= nullptr;
855 return osl_File_E_INVAL
;
859 return osl_File_E_INVAL
;
861 pItemImpl
= static_cast<DirectoryItem_Impl
*>(malloc(sizeof(DirectoryItem_Impl
)));
863 return osl_File_E_NOMEM
;
865 memset( pItemImpl
, 0, sizeof(DirectoryItem_Impl
) );
866 fFound
= EnumDirectory( pDirImpl
->hDirectory
, &pItemImpl
->FindData
);
870 pItemImpl
->uType
= DIRECTORYITEM_FILE
;
871 pItemImpl
->nRefCount
= 1;
873 rtl_uString
* pTmpFileName
= nullptr;
874 rtl_uString_newFromStr( &pTmpFileName
, o3tl::toU(pItemImpl
->FindData
.cFileName
) );
875 rtl_uString_newConcat( &pItemImpl
->m_pFullPath
, pDirImpl
->m_pDirectoryPath
, pTmpFileName
);
876 rtl_uString_release( pTmpFileName
);
878 pItemImpl
->bFullPathNormalized
= FALSE
;
879 *pItem
= static_cast<oslDirectoryItem
>(pItemImpl
);
880 return osl_File_E_None
;
884 if ( pItemImpl
->m_pFullPath
)
886 rtl_uString_release( pItemImpl
->m_pFullPath
);
887 pItemImpl
->m_pFullPath
= nullptr;
891 return oslTranslateFileError( GetLastError() );
895 oslFileError SAL_CALL
osl_getNextDirectoryItem(
896 oslDirectory Directory
, oslDirectoryItem
*pItem
, sal_uInt32 uHint
)
898 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
903 return osl_File_E_INVAL
;
907 return osl_File_E_INVAL
;
909 switch ( pDirImpl
->uType
)
911 case DIRECTORYTYPE_LOCALROOT
:
912 return osl_getNextDrive( Directory
, pItem
, uHint
);
913 case DIRECTORYTYPE_NETROOT
:
914 return osl_getNextNetResource( Directory
, pItem
, uHint
);
915 case DIRECTORYTYPE_FILESYSTEM
:
916 return osl_getNextFileItem( Directory
, pItem
, uHint
);
918 return osl_File_E_INVAL
;
922 oslFileError SAL_CALL
osl_closeDirectory(oslDirectory Directory
)
924 Directory_Impl
*pDirImpl
= static_cast<Directory_Impl
*>(Directory
);
925 oslFileError eError
= osl_File_E_INVAL
;
929 switch ( pDirImpl
->uType
)
931 case DIRECTORYTYPE_FILESYSTEM
:
932 eError
= CloseDirectory( pDirImpl
->hDirectory
) ? osl_File_E_None
: oslTranslateFileError( GetLastError() );
934 case DIRECTORYTYPE_LOCALROOT
:
935 eError
= CloseLogicalDrivesEnum( pDirImpl
->hEnumDrives
) ? osl_File_E_None
: oslTranslateFileError( GetLastError() );
937 case DIRECTORYTYPE_NETROOT
:
939 DWORD err
= WNetCloseEnum(pDirImpl
->hDirectory
);
940 eError
= (err
== NO_ERROR
) ? osl_File_E_None
: oslTranslateFileError(err
);
944 OSL_FAIL( "Invalid directory type" );
948 if ( pDirImpl
->m_pDirectoryPath
)
950 rtl_uString_release( pDirImpl
->m_pDirectoryPath
);
951 pDirImpl
->m_pDirectoryPath
= nullptr;
959 /* Different types of paths */
962 PATHTYPE_SYNTAXERROR
= 0,
969 oslFileError SAL_CALL
osl_getDirectoryItem(rtl_uString
*strFilePath
, oslDirectoryItem
*pItem
)
971 oslFileError error
= osl_File_E_None
;
972 rtl_uString
* strSysFilePath
= nullptr;
973 PATHTYPE type
= PATHTYPE_FILE
;
979 return osl_File_E_INVAL
;
983 error
= osl_getSystemPathFromFileURL_( strFilePath
, &strSysFilePath
, false );
985 if ( osl_File_E_None
!= error
)
988 dwPathType
= IsValidFilePath( strSysFilePath
, VALIDATEPATH_NORMAL
, nullptr );
990 if ( dwPathType
& PATHTYPE_IS_VOLUME
)
991 type
= PATHTYPE_VOLUME
;
992 else if ( dwPathType
& PATHTYPE_IS_SERVER
)
993 type
= PATHTYPE_NETSERVER
;
995 type
= PATHTYPE_FILE
;
999 case PATHTYPE_NETSERVER
:
1001 DirectoryItem_Impl
* pItemImpl
=
1002 static_cast<DirectoryItem_Impl
*>(malloc(sizeof(DirectoryItem_Impl
)));
1005 error
= osl_File_E_NOMEM
;
1007 if ( osl_File_E_None
== error
)
1009 ZeroMemory( pItemImpl
, sizeof(DirectoryItem_Impl
) );
1010 pItemImpl
->uType
= DIRECTORYITEM_SERVER
;
1012 osl_acquireDirectoryItem( static_cast<oslDirectoryItem
>(pItemImpl
) );
1013 rtl_uString_newFromString( &pItemImpl
->m_pFullPath
, strSysFilePath
);
1015 // Assign a title anyway
1020 while( iSrc
< strSysFilePath
->length
&& strSysFilePath
->buffer
[iSrc
] && strSysFilePath
->buffer
[iSrc
] != '\\' )
1022 pItemImpl
->FindData
.cFileName
[iDst
++] = strSysFilePath
->buffer
[iSrc
++];
1030 case PATHTYPE_VOLUME
:
1032 DirectoryItem_Impl
* pItemImpl
=
1033 static_cast<DirectoryItem_Impl
*>(malloc(sizeof(DirectoryItem_Impl
)));
1036 error
= osl_File_E_NOMEM
;
1038 if ( osl_File_E_None
== error
)
1040 ZeroMemory( pItemImpl
, sizeof(DirectoryItem_Impl
) );
1041 pItemImpl
->uType
= DIRECTORYITEM_DRIVE
;
1043 osl_acquireDirectoryItem( static_cast<oslDirectoryItem
>(pItemImpl
) );
1045 wcscpy( pItemImpl
->cDriveString
, o3tl::toW(strSysFilePath
->buffer
) );
1046 pItemImpl
->cDriveString
[0] = rtl::toAsciiUpperCase( pItemImpl
->cDriveString
[0] );
1048 if ( pItemImpl
->cDriveString
[wcslen(pItemImpl
->cDriveString
) - 1] != '\\' )
1049 wcscat( pItemImpl
->cDriveString
, L
"\\" );
1055 case PATHTYPE_SYNTAXERROR
:
1056 case PATHTYPE_NETROOT
:
1060 WIN32_FIND_DATAW aFindData
;
1062 if ( strSysFilePath
->length
> 0 && strSysFilePath
->buffer
[strSysFilePath
->length
- 1] == '\\' )
1063 rtl_uString_newFromStr_WithLength( &strSysFilePath
, strSysFilePath
->buffer
, strSysFilePath
->length
- 1 );
1065 hFind
= FindFirstFileW( o3tl::toW(rtl_uString_getStr(strSysFilePath
)), &aFindData
);
1067 if ( hFind
!= INVALID_HANDLE_VALUE
)
1069 DirectoryItem_Impl
*pItemImpl
=
1070 static_cast<DirectoryItem_Impl
*>(malloc(sizeof(DirectoryItem_Impl
)));
1072 ZeroMemory( pItemImpl
, sizeof(DirectoryItem_Impl
) );
1073 osl_acquireDirectoryItem( static_cast<oslDirectoryItem
>(pItemImpl
) );
1075 CopyMemory( &pItemImpl
->FindData
, &aFindData
, sizeof(WIN32_FIND_DATAW
) );
1076 rtl_uString_newFromString( &pItemImpl
->m_pFullPath
, strSysFilePath
);
1078 // MT: This costs 600ms startup time on fast v60x!
1079 // GetCaseCorrectPathName( pItemImpl->szFullPath, pItemImpl->szFullPath, sizeof(pItemImpl->szFullPath) );
1081 pItemImpl
->uType
= DIRECTORYITEM_FILE
;
1086 error
= oslTranslateFileError( GetLastError() );
1091 if ( strSysFilePath
)
1092 rtl_uString_release( strSysFilePath
);
1097 oslFileError SAL_CALL
osl_acquireDirectoryItem( oslDirectoryItem Item
)
1099 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1102 return osl_File_E_INVAL
;
1104 pItemImpl
->nRefCount
++;
1105 return osl_File_E_None
;
1108 oslFileError SAL_CALL
osl_releaseDirectoryItem( oslDirectoryItem Item
)
1110 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1113 return osl_File_E_INVAL
;
1115 if ( ! --pItemImpl
->nRefCount
)
1117 if ( pItemImpl
->m_pFullPath
)
1119 rtl_uString_release( pItemImpl
->m_pFullPath
);
1120 pItemImpl
->m_pFullPath
= nullptr;
1126 return osl_File_E_None
;
1130 SAL_CALL
osl_identicalDirectoryItem( oslDirectoryItem a
, oslDirectoryItem b
)
1132 DirectoryItem_Impl
*pA
= static_cast<DirectoryItem_Impl
*>(a
);
1133 DirectoryItem_Impl
*pB
= static_cast<DirectoryItem_Impl
*>(b
);
1136 /* same name => same item, unless renaming / moving madness has occurred */
1137 if (pA
->m_pFullPath
== pB
->m_pFullPath
)
1140 // FIXME: as/when/if this is used in anger on Windows we could
1146 static inline bool is_floppy_A_present()
1147 { return (GetLogicalDrives() & 1); }
1149 static inline bool is_floppy_B_present()
1150 { return (GetLogicalDrives() & 2); }
1152 static bool is_floppy_volume_mount_point(const OUString
& path
)
1154 // determines if a volume mount point shows to a floppy
1155 // disk by comparing the unique volume names
1156 static const LPCWSTR FLOPPY_A
= L
"A:\\";
1157 static const LPCWSTR FLOPPY_B
= L
"B:\\";
1160 osl::systemPathEnsureSeparator(p
);
1163 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p
.getStr()), vn
, SAL_N_ELEMENTS(vn
)))
1166 if (is_floppy_A_present() &&
1167 GetVolumeNameForVolumeMountPointW(FLOPPY_A
, vnfloppy
, SAL_N_ELEMENTS(vnfloppy
)) &&
1168 (0 == wcscmp(vn
, vnfloppy
)))
1171 if (is_floppy_B_present() &&
1172 GetVolumeNameForVolumeMountPointW(FLOPPY_B
, vnfloppy
, SAL_N_ELEMENTS(vnfloppy
)) &&
1173 (0 == wcscmp(vn
, vnfloppy
)))
1179 static bool is_floppy_drive(const OUString
& path
)
1181 static const LPCWSTR FLOPPY_DRV_LETTERS
= L
"AaBb";
1183 // we must take into account that even a floppy
1184 // drive may be mounted to a directory so checking
1185 // for the drive letter alone is not sufficient
1186 // we must compare the unique volume name with
1187 // that of the available floppy disks
1189 const sal_Unicode
* pszPath
= path
.getStr();
1190 return ((wcschr(FLOPPY_DRV_LETTERS
, pszPath
[0]) && (L
':' == pszPath
[1])) || is_floppy_volume_mount_point(path
));
1193 static bool is_volume_mount_point(const OUString
& path
)
1196 osl::systemPathRemoveSeparator(p
);
1198 bool is_volume_root
= false;
1200 if (!is_floppy_drive(p
))
1202 DWORD fattr
= GetFileAttributesW(o3tl::toW(p
.getStr()));
1204 if ((INVALID_FILE_ATTRIBUTES
!= fattr
) &&
1205 (FILE_ATTRIBUTE_REPARSE_POINT
& fattr
))
1207 WIN32_FIND_DATAW find_data
;
1208 HANDLE h_find
= FindFirstFileW(o3tl::toW(p
.getStr()), &find_data
);
1210 if (IsValidHandle(h_find
) &&
1211 (FILE_ATTRIBUTE_REPARSE_POINT
& find_data
.dwFileAttributes
) &&
1212 (IO_REPARSE_TAG_MOUNT_POINT
== find_data
.dwReserved0
))
1214 is_volume_root
= true;
1216 if (IsValidHandle(h_find
))
1220 return is_volume_root
;
1223 static UINT
get_volume_mount_point_drive_type(const OUString
& path
)
1225 if (0 == path
.getLength())
1226 return GetDriveTypeW(nullptr);
1229 osl::systemPathEnsureSeparator(p
);
1232 if (GetVolumeNameForVolumeMountPointW(o3tl::toW(p
.getStr()), vn
, SAL_N_ELEMENTS(vn
)))
1233 return GetDriveTypeW(vn
);
1235 return DRIVE_NO_ROOT_DIR
;
1238 static inline bool is_drivetype_request(sal_uInt32 field_mask
)
1240 return (field_mask
& osl_VolumeInfo_Mask_Attributes
);
1243 static oslFileError
osl_get_drive_type(
1244 const OUString
& path
, oslVolumeInfo
* pInfo
)
1246 // GetDriveType fails on empty volume mount points
1247 // see Knowledge Base Q244089
1249 if (is_volume_mount_point(path
))
1250 drive_type
= get_volume_mount_point_drive_type(path
);
1252 drive_type
= GetDriveTypeW(o3tl::toW(path
.getStr()));
1254 if (DRIVE_NO_ROOT_DIR
== drive_type
)
1255 return oslTranslateFileError(ERROR_INVALID_DRIVE
);
1257 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_Attributes
;
1262 pInfo
->uAttributes
|= osl_Volume_Attribute_CompactDisc
| osl_Volume_Attribute_Removeable
;
1264 case DRIVE_REMOVABLE
:
1265 pInfo
->uAttributes
|= osl_Volume_Attribute_Removeable
;
1266 if (is_floppy_drive(path
))
1267 pInfo
->uAttributes
|= osl_Volume_Attribute_FloppyDisk
;
1270 pInfo
->uAttributes
|= osl_Volume_Attribute_FixedDisk
;
1273 pInfo
->uAttributes
|= osl_Volume_Attribute_RAMDisk
;
1276 pInfo
->uAttributes
|= osl_Volume_Attribute_Remote
;
1279 pInfo
->uAttributes
= 0;
1282 pInfo
->uValidFields
&= ~osl_VolumeInfo_Mask_Attributes
;
1283 pInfo
->uAttributes
= 0;
1286 return osl_File_E_None
;
1289 static inline bool is_volume_space_info_request(sal_uInt32 field_mask
)
1291 return (field_mask
&
1292 (osl_VolumeInfo_Mask_TotalSpace
|
1293 osl_VolumeInfo_Mask_UsedSpace
|
1294 osl_VolumeInfo_Mask_FreeSpace
));
1297 static void get_volume_space_information(
1298 const OUString
& path
, oslVolumeInfo
*pInfo
)
1300 BOOL ret
= GetDiskFreeSpaceExW(
1301 o3tl::toW(path
.getStr()),
1302 reinterpret_cast<PULARGE_INTEGER
>(&pInfo
->uFreeSpace
),
1303 reinterpret_cast<PULARGE_INTEGER
>(&pInfo
->uTotalSpace
),
1308 pInfo
->uUsedSpace
= pInfo
->uTotalSpace
- pInfo
->uFreeSpace
;
1309 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_TotalSpace
|
1310 osl_VolumeInfo_Mask_UsedSpace
|
1311 osl_VolumeInfo_Mask_FreeSpace
;
1315 static inline bool is_filesystem_attributes_request(sal_uInt32 field_mask
)
1317 return (field_mask
&
1318 (osl_VolumeInfo_Mask_MaxNameLength
|
1319 osl_VolumeInfo_Mask_MaxPathLength
|
1320 osl_VolumeInfo_Mask_FileSystemName
|
1321 osl_VolumeInfo_Mask_FileSystemCaseHandling
));
1324 static oslFileError
get_filesystem_attributes(
1325 const OUString
& path
, sal_uInt32 field_mask
, oslVolumeInfo
* pInfo
)
1327 pInfo
->uAttributes
= 0;
1329 // osl_get_drive_type must be called first because
1330 // this function resets osl_VolumeInfo_Mask_Attributes
1332 if (is_drivetype_request(field_mask
))
1334 oslFileError osl_error
= osl_get_drive_type(path
, pInfo
);
1335 if (osl_File_E_None
!= osl_error
)
1338 if (is_filesystem_attributes_request(field_mask
))
1340 /* the following two parameters can not be longer than MAX_PATH+1 */
1341 WCHAR vn
[MAX_PATH
+1];
1342 WCHAR fsn
[MAX_PATH
+1];
1348 LPCWSTR pszPath
= o3tl::toW(path
.getStr());
1349 if (GetVolumeInformationW(pszPath
, vn
, MAX_PATH
+1, &serial
, &mcl
, &flags
, fsn
, MAX_PATH
+1))
1351 // Currently sal does not use this value, instead MAX_PATH is used
1352 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_MaxNameLength
;
1353 pInfo
->uMaxNameLength
= mcl
;
1355 // Should the uMaxPathLength be set to 32767, "\\?\" prefix allowes it
1356 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_MaxPathLength
;
1357 pInfo
->uMaxPathLength
= MAX_PATH
;
1359 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_FileSystemName
;
1360 rtl_uString_newFromStr(&pInfo
->ustrFileSystemName
, o3tl::toU(fsn
));
1362 // volumes (even NTFS) will always be considered case
1363 // insensitive because the Win32 API is not able to
1364 // deal with case sensitive volumes see M$ Knowledge Base
1365 // article 100625 that's why we never set the attribute
1366 // osl_Volume_Attribute_Case_Sensitive
1368 if (flags
& FS_CASE_IS_PRESERVED
)
1369 pInfo
->uAttributes
|= osl_Volume_Attribute_Case_Is_Preserved
;
1371 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_Attributes
;
1374 return osl_File_E_None
;
1377 static bool path_get_parent(OUString
& path
)
1379 OSL_PRECOND(path
.lastIndexOf(SLASH
) == -1, "Path must not have slashes");
1381 if (!has_path_parent(path
))
1383 sal_Int32 i
= path
.lastIndexOf(BACKSLASH
);
1386 path
= OUString(path
.getStr(), i
);
1393 static void path_travel_to_volume_root(const OUString
& system_path
, OUString
& volume_root
)
1395 OUString
sys_path(system_path
);
1397 while(!is_volume_mount_point(sys_path
) && path_get_parent(sys_path
))
1400 volume_root
= sys_path
;
1401 osl::systemPathEnsureSeparator(volume_root
);
1404 oslFileError SAL_CALL
osl_getVolumeInformation(
1405 rtl_uString
*ustrURL
, oslVolumeInfo
*pInfo
, sal_uInt32 uFieldMask
)
1408 return osl_File_E_INVAL
;
1410 OUString system_path
;
1411 oslFileError error
= osl_getSystemPathFromFileURL_(ustrURL
, &system_path
.pData
, false);
1413 if (osl_File_E_None
!= error
)
1416 OUString volume_root
;
1417 path_travel_to_volume_root(system_path
, volume_root
);
1419 pInfo
->uValidFields
= 0;
1421 if ((error
= get_filesystem_attributes(volume_root
, uFieldMask
, pInfo
)) != osl_File_E_None
)
1424 if (is_volume_space_info_request(uFieldMask
))
1425 get_volume_space_information(volume_root
, pInfo
);
1427 if (uFieldMask
& osl_VolumeInfo_Mask_DeviceHandle
)
1429 error
= osl_getFileURLFromSystemPath(volume_root
.pData
, reinterpret_cast<rtl_uString
**>(&pInfo
->pDeviceHandle
));
1430 if (error
!= osl_File_E_None
)
1432 pInfo
->uValidFields
|= osl_VolumeInfo_Mask_DeviceHandle
;
1435 return osl_File_E_None
;
1438 static oslFileError
osl_getDriveInfo(
1439 oslDirectoryItem Item
, oslFileStatus
*pStatus
, sal_uInt32 uFieldMask
)
1441 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1442 WCHAR cDrive
[3] = L
"A:";
1443 WCHAR cRoot
[4] = L
"A:\\";
1446 return osl_File_E_INVAL
;
1448 pStatus
->uValidFields
= 0;
1450 cDrive
[0] = pItemImpl
->cDriveString
[0];
1451 cRoot
[0] = pItemImpl
->cDriveString
[0];
1453 if ( uFieldMask
& osl_FileStatus_Mask_FileName
)
1455 if ( pItemImpl
->cDriveString
[0] == '\\' && pItemImpl
->cDriveString
[1] == '\\' )
1457 LPCWSTR lpFirstBkSlash
= wcschr( &pItemImpl
->cDriveString
[2], '\\' );
1459 if ( lpFirstBkSlash
&& lpFirstBkSlash
[1] )
1461 LPCWSTR lpLastBkSlash
= wcschr( &lpFirstBkSlash
[1], '\\' );
1463 if ( lpLastBkSlash
)
1464 rtl_uString_newFromStr_WithLength( &pStatus
->ustrFileName
, o3tl::toU(&lpFirstBkSlash
[1]), lpLastBkSlash
- lpFirstBkSlash
- 1 );
1466 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(&lpFirstBkSlash
[1]) );
1467 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1470 else switch ( GetDriveTypeW( cRoot
) )
1474 WCHAR szBuffer
[1024];
1475 DWORD
const dwBufsizeConst
= SAL_N_ELEMENTS(szBuffer
);
1476 DWORD dwBufsize
= dwBufsizeConst
;
1478 DWORD dwResult
= WNetGetConnectionW( cDrive
, szBuffer
, &dwBufsize
);
1479 if ( NO_ERROR
== dwResult
)
1481 WCHAR szFileName
[dwBufsizeConst
+ 16];
1483 swprintf( szFileName
, L
"%s [%s]", cDrive
, szBuffer
);
1484 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(szFileName
) );
1487 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cDrive
) );
1489 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1493 WCHAR szVolumeNameBuffer
[1024];
1494 DWORD
const dwBufsizeConst
= SAL_N_ELEMENTS(szVolumeNameBuffer
);
1496 if ( GetVolumeInformationW( cRoot
, szVolumeNameBuffer
, dwBufsizeConst
, nullptr, nullptr, nullptr, nullptr, 0 ) )
1498 WCHAR szFileName
[dwBufsizeConst
+ 16];
1500 swprintf( szFileName
, L
"%s [%s]", cDrive
, szVolumeNameBuffer
);
1501 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(szFileName
) );
1504 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cDrive
) );
1506 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1509 case DRIVE_REMOVABLE
:
1510 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1511 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(cRoot
) );
1519 pStatus
->eType
= osl_File_Type_Volume
;
1520 pStatus
->uValidFields
|= osl_FileStatus_Mask_Type
;
1522 if ( uFieldMask
& osl_FileStatus_Mask_FileURL
)
1524 rtl_uString
*ustrSystemPath
= nullptr;
1526 rtl_uString_newFromStr( &ustrSystemPath
, o3tl::toU(pItemImpl
->cDriveString
) );
1527 oslFileError error
= osl_getFileURLFromSystemPath( ustrSystemPath
, &pStatus
->ustrFileURL
);
1528 rtl_uString_release( ustrSystemPath
);
1529 if (error
!= osl_File_E_None
)
1531 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
1533 return osl_File_E_None
;
1536 static oslFileError
osl_getServerInfo(
1537 oslDirectoryItem Item
, oslFileStatus
*pStatus
, sal_uInt32 uFieldMask
)
1539 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1541 return osl_File_E_INVAL
;
1543 pStatus
->uValidFields
= 0;
1544 pStatus
->eType
= osl_File_Type_Directory
;
1545 pStatus
->uValidFields
|= osl_FileStatus_Mask_Type
;
1547 if ( uFieldMask
& osl_FileStatus_Mask_FileURL
)
1549 oslFileError error
= osl_getFileURLFromSystemPath( pItemImpl
->m_pFullPath
, &pStatus
->ustrFileURL
);
1550 if (error
!= osl_File_E_None
)
1552 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
1554 return osl_File_E_None
;
1557 oslFileError SAL_CALL
osl_getFileStatus(
1558 oslDirectoryItem Item
,
1559 oslFileStatus
*pStatus
,
1560 sal_uInt32 uFieldMask
)
1562 DirectoryItem_Impl
*pItemImpl
= static_cast<DirectoryItem_Impl
*>(Item
);
1565 return osl_File_E_INVAL
;
1567 switch ( pItemImpl
->uType
)
1569 case DIRECTORYITEM_DRIVE
:
1570 return osl_getDriveInfo( Item
, pStatus
, uFieldMask
);
1571 case DIRECTORYITEM_SERVER
:
1572 return osl_getServerInfo( Item
, pStatus
, uFieldMask
);
1577 OUString
sFullPath(pItemImpl
->m_pFullPath
);
1579 // Prefix long paths, windows API calls expect this prefix
1580 // (only local paths starting with something like C: or D:)
1581 if (sFullPath
.getLength() >= MAX_PATH
&& isalpha(sFullPath
[0]) && sFullPath
[1] == ':')
1582 sFullPath
= "\\\\?\\" + sFullPath
;
1584 if ( uFieldMask
& osl_FileStatus_Mask_Validate
)
1586 HANDLE hFind
= FindFirstFileW( o3tl::toW(sFullPath
.getStr() ), &pItemImpl
->FindData
);
1588 if ( hFind
!= INVALID_HANDLE_VALUE
)
1591 return oslTranslateFileError( GetLastError() );
1593 uFieldMask
&= ~ osl_FileStatus_Mask_Validate
;
1596 /* If no fields to retrieve left ignore pStatus */
1598 return osl_File_E_None
;
1600 /* Otherwise, this must be a valid pointer */
1602 return osl_File_E_INVAL
;
1604 if ( pStatus
->uStructSize
!= sizeof(oslFileStatus
) )
1605 return osl_File_E_INVAL
;
1607 pStatus
->uValidFields
= 0;
1609 /* File time stamps */
1611 if ( (uFieldMask
& osl_FileStatus_Mask_ModifyTime
) &&
1612 FileTimeToTimeValue( &pItemImpl
->FindData
.ftLastWriteTime
, &pStatus
->aModifyTime
) )
1613 pStatus
->uValidFields
|= osl_FileStatus_Mask_ModifyTime
;
1615 if ( (uFieldMask
& osl_FileStatus_Mask_AccessTime
) &&
1616 FileTimeToTimeValue( &pItemImpl
->FindData
.ftLastAccessTime
, &pStatus
->aAccessTime
) )
1617 pStatus
->uValidFields
|= osl_FileStatus_Mask_AccessTime
;
1619 if ( (uFieldMask
& osl_FileStatus_Mask_CreationTime
) &&
1620 FileTimeToTimeValue( &pItemImpl
->FindData
.ftCreationTime
, &pStatus
->aCreationTime
) )
1621 pStatus
->uValidFields
|= osl_FileStatus_Mask_CreationTime
;
1623 /* Most of the fields are already set, regardless of required fields */
1625 rtl_uString_newFromStr( &pStatus
->ustrFileName
, o3tl::toU(pItemImpl
->FindData
.cFileName
) );
1626 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileName
;
1628 if ((FILE_ATTRIBUTE_REPARSE_POINT
& pItemImpl
->FindData
.dwFileAttributes
) &&
1629 (IO_REPARSE_TAG_MOUNT_POINT
== pItemImpl
->FindData
.dwReserved0
))
1630 pStatus
->eType
= osl_File_Type_Volume
;
1631 else if (pItemImpl
->FindData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1632 pStatus
->eType
= osl_File_Type_Directory
;
1634 pStatus
->eType
= osl_File_Type_Regular
;
1636 pStatus
->uValidFields
|= osl_FileStatus_Mask_Type
;
1638 pStatus
->uAttributes
= pItemImpl
->FindData
.dwFileAttributes
;
1639 pStatus
->uValidFields
|= osl_FileStatus_Mask_Attributes
;
1641 pStatus
->uFileSize
= static_cast<sal_uInt64
>(pItemImpl
->FindData
.nFileSizeLow
) + (static_cast<sal_uInt64
>(pItemImpl
->FindData
.nFileSizeHigh
) << 32);
1642 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileSize
;
1644 if ( uFieldMask
& osl_FileStatus_Mask_LinkTargetURL
)
1646 oslFileError error
= osl_getFileURLFromSystemPath( sFullPath
.pData
, &pStatus
->ustrLinkTargetURL
);
1647 if (error
!= osl_File_E_None
)
1650 pStatus
->uValidFields
|= osl_FileStatus_Mask_LinkTargetURL
;
1653 if ( uFieldMask
& osl_FileStatus_Mask_FileURL
)
1655 if ( !pItemImpl
->bFullPathNormalized
)
1657 ::osl::LongPathBuffer
< sal_Unicode
> aBuffer( MAX_LONG_PATH
);
1658 sal_uInt32 nNewLen
= GetCaseCorrectPathName( o3tl::toW( sFullPath
.getStr() ),
1659 o3tl::toW( aBuffer
),
1660 aBuffer
.getBufSizeInSymbols(),
1665 rtl_uString_newFromStr( &pItemImpl
->m_pFullPath
, aBuffer
);
1666 sFullPath
= OUString( pItemImpl
->m_pFullPath
);
1667 pItemImpl
->bFullPathNormalized
= TRUE
;
1671 oslFileError error
= osl_getFileURLFromSystemPath( sFullPath
.pData
, &pStatus
->ustrFileURL
);
1672 if (error
!= osl_File_E_None
)
1674 pStatus
->uValidFields
|= osl_FileStatus_Mask_FileURL
;
1677 return osl_File_E_None
;
1680 oslFileError SAL_CALL
osl_setFileAttributes(
1681 rtl_uString
*ustrFileURL
,
1682 sal_uInt64 uAttributes
)
1685 rtl_uString
*ustrSysPath
= nullptr;
1686 DWORD dwFileAttributes
;
1689 // Converts the normalized path into a systempath
1690 error
= osl_getSystemPathFromFileURL_( ustrFileURL
, &ustrSysPath
, false );
1692 if ( osl_File_E_None
!= error
)
1695 dwFileAttributes
= GetFileAttributesW( o3tl::toW(rtl_uString_getStr(ustrSysPath
)) );
1697 if ( DWORD(-1) != dwFileAttributes
)
1699 dwFileAttributes
&= ~(FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
);
1701 if ( uAttributes
& osl_File_Attribute_ReadOnly
)
1702 dwFileAttributes
|= FILE_ATTRIBUTE_READONLY
;
1704 if ( uAttributes
& osl_File_Attribute_Hidden
)
1705 dwFileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
1707 fSuccess
= SetFileAttributesW( o3tl::toW(rtl_uString_getStr(ustrSysPath
)), dwFileAttributes
);
1715 error
= oslTranslateFileError( GetLastError() );
1717 rtl_uString_release( ustrSysPath
);
1722 oslFileError SAL_CALL
osl_setFileTime(
1723 rtl_uString
*filePath
,
1724 const TimeValue
*aCreationTime
,
1725 const TimeValue
*aLastAccessTime
,
1726 const TimeValue
*aLastWriteTime
)
1729 rtl_uString
*sysPath
=nullptr;
1730 FILETIME
*lpCreationTime
=nullptr;
1731 FILETIME
*lpLastAccessTime
=nullptr;
1732 FILETIME
*lpLastWriteTime
=nullptr;
1733 FILETIME ftCreationTime
;
1734 FILETIME ftLastAccessTime
;
1735 FILETIME ftLastWriteTime
;
1739 error
=osl_getSystemPathFromFileURL_(filePath
, &sysPath
, false);
1741 if (error
==osl_File_E_INVAL
)
1744 hFile
=CreateFileW(o3tl::toW(rtl_uString_getStr(sysPath
)), GENERIC_WRITE
, 0, nullptr , OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr);
1745 rtl_uString_release(sysPath
);
1747 if (hFile
==INVALID_HANDLE_VALUE
)
1748 return osl_File_E_NOENT
;
1750 if (TimeValueToFileTime(aCreationTime
, &ftCreationTime
))
1751 lpCreationTime
=&ftCreationTime
;
1753 if (TimeValueToFileTime(aLastAccessTime
, &ftLastAccessTime
))
1754 lpLastAccessTime
=&ftLastAccessTime
;
1756 if (TimeValueToFileTime(aLastWriteTime
, &ftLastWriteTime
))
1757 lpLastWriteTime
=&ftLastWriteTime
;
1759 fSuccess
=SetFileTime(hFile
, lpCreationTime
, lpLastAccessTime
, lpLastWriteTime
);
1764 return osl_File_E_INVAL
;
1766 return osl_File_E_None
;
1769 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */