xref: /trunk/main/sal/osl/w32/file_dirvol.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #define UNICODE
29 #define _UNICODE
30 #define _WIN32_WINNT_0x0500
31 #include "systools/win32/uwinapi.h"
32 
33 #include "osl/file.h"
34 
35 #include "file_url.h"
36 #include "file_error.h"
37 
38 #include "path_helper.hxx"
39 
40 #include "osl/diagnose.h"
41 #include "osl/time.h"
42 #include "rtl/alloc.h"
43 #include "rtl/ustring.hxx"
44 
45 #include <tchar.h>
46 #ifdef __MINGW32__
47 #include <ctype.h>
48 #endif
49 
50 //#####################################################
51 #define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0])))
52 
53 static const wchar_t UNC_PREFIX[] = L"\\\\";
54 static const wchar_t BACKSLASH = '\\';
55 static const wchar_t SLASH = '/';
56 
57 //#####################################################
58 extern "C" BOOL TimeValueToFileTime(const TimeValue *cpTimeVal, FILETIME *pFTime)
59 {
60     SYSTEMTIME  BaseSysTime;
61     FILETIME    BaseFileTime;
62     FILETIME    FTime;
63     __int64     localTime;
64     BOOL        fSuccess = FALSE;
65 
66     BaseSysTime.wYear         = 1970;
67     BaseSysTime.wMonth        = 1;
68     BaseSysTime.wDayOfWeek    = 0;
69     BaseSysTime.wDay          = 1;
70     BaseSysTime.wHour         = 0;
71     BaseSysTime.wMinute       = 0;
72     BaseSysTime.wSecond       = 0;
73     BaseSysTime.wMilliseconds = 0;
74 
75     if (cpTimeVal==NULL)
76         return fSuccess;
77 
78     if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) )
79     {
80         __int64 timeValue;
81         localTime=cpTimeVal->Seconds*(__int64)10000000+cpTimeVal->Nanosec/100;
82         *(__int64 *)&FTime=localTime;
83         fSuccess = 0 <= (timeValue= *((__int64 *)&BaseFileTime) + *((__int64 *) &FTime));
84         if (fSuccess)
85             *(__int64 *)pFTime=timeValue;
86     }
87     return fSuccess;
88 }
89 
90 //#####################################################
91 extern "C" BOOL FileTimeToTimeValue(const FILETIME *cpFTime, TimeValue *pTimeVal)
92 {
93     SYSTEMTIME  BaseSysTime;
94     FILETIME    BaseFileTime;
95     BOOL        fSuccess = FALSE;   /* Assume failure */
96 
97     BaseSysTime.wYear         = 1970;
98     BaseSysTime.wMonth        = 1;
99     BaseSysTime.wDayOfWeek    = 0;
100     BaseSysTime.wDay          = 1;
101     BaseSysTime.wHour         = 0;
102     BaseSysTime.wMinute       = 0;
103     BaseSysTime.wSecond       = 0;
104     BaseSysTime.wMilliseconds = 0;
105 
106     if ( SystemTimeToFileTime(&BaseSysTime, &BaseFileTime) )
107     {
108         __int64     Value;
109 
110         fSuccess = 0 <= (Value = *((__int64 *)cpFTime) - *((__int64 *)&BaseFileTime));
111 
112         if ( fSuccess )
113         {
114             pTimeVal->Seconds  = (unsigned long) (Value / 10000000L);
115             pTimeVal->Nanosec  = (unsigned long)((Value % 10000000L) * 100);
116         }
117     }
118     return fSuccess;
119 }
120 
121 //#####################################################
122 namespace /* private */
123 {
124     //#####################################################
125     struct Component
126     {
127         Component() :
128             begin_(0), end_(0)
129         {}
130 
131         bool isPresent() const
132         { return (static_cast<sal_IntPtr>(end_ - begin_) > 0); }
133 
134         const sal_Unicode* begin_;
135         const sal_Unicode* end_;
136     };
137 
138     //#####################################################
139     struct UNCComponents
140     {
141         Component server_;
142         Component share_;
143         Component resource_;
144     };
145 
146     //#####################################################
147     inline bool is_UNC_path(const sal_Unicode* path)
148     { return (0 == wcsncmp(UNC_PREFIX, reinterpret_cast<LPCWSTR>(path), ELEMENTS_OF_ARRAY(UNC_PREFIX) - 1)); }
149 
150     //#####################################################
151     inline bool is_UNC_path(const rtl::OUString& path)
152     { return is_UNC_path(path.getStr()); }
153 
154     //#####################################################
155     void parse_UNC_path(const sal_Unicode* path, UNCComponents* puncc)
156     {
157         OSL_PRECOND(is_UNC_path(path), "Precondition violated: No UNC path");
158         OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) == -1, "Path must not contain slashes");
159 
160         const sal_Unicode* pend = path + rtl_ustr_getLength(path);
161         const sal_Unicode* ppos = path + 2;
162 
163         puncc->server_.begin_ = ppos;
164         while ((ppos < pend) && (*ppos != BACKSLASH))
165             ppos++;
166 
167         puncc->server_.end_ = ppos;
168 
169         if (BACKSLASH == *ppos)
170         {
171             puncc->share_.begin_ = ++ppos;
172             while ((ppos < pend) && (*ppos != BACKSLASH))
173                 ppos++;
174 
175             puncc->share_.end_ = ppos;
176 
177             if (BACKSLASH == *ppos)
178             {
179                 puncc->resource_.begin_ = ++ppos;
180                 while (ppos < pend)
181                     ppos++;
182 
183                 puncc->resource_.end_ = ppos;
184             }
185         }
186 
187         OSL_POSTCOND(puncc->server_.isPresent() && puncc->share_.isPresent(), \
188         "Postcondition violated: Invalid UNC path detected");
189     }
190 
191     //#####################################################
192     void parse_UNC_path(const rtl::OUString& path, UNCComponents* puncc)
193     { parse_UNC_path(path.getStr(), puncc); }
194 
195 
196     //#####################################################
197     bool has_path_parent(const sal_Unicode* path)
198     {
199         // Has the given path a parent or are we already there,
200         // e.g. 'c:\' or '\\server\share\'?
201 
202         bool has_parent = false;
203         if (is_UNC_path(path))
204         {
205             UNCComponents unc_comp;
206             parse_UNC_path(path, &unc_comp);
207             has_parent = unc_comp.resource_.isPresent();
208         }
209         else
210         {
211             has_parent = !osl::systemPathIsLogicalDrivePattern(path);
212         }
213         return has_parent;
214     }
215 
216     //#####################################################
217     inline bool has_path_parent(const rtl::OUString& path)
218     { return has_path_parent(path.getStr()); }
219 
220 } // end namespace private
221 
222 //#####################################################
223 // volume handling functions
224 //#####################################################
225 
226 //#####################################################
227 oslFileError SAL_CALL osl_unmountVolumeDevice( oslVolumeDeviceHandle Handle )
228 {
229     if ( Handle )
230         return osl_File_E_None;
231     else
232         return osl_File_E_INVAL;
233 }
234 
235 //#####################################################
236 oslFileError SAL_CALL osl_automountVolumeDevice( oslVolumeDeviceHandle Handle )
237 {
238     if ( Handle )
239         return osl_File_E_None;
240     else
241         return osl_File_E_INVAL;
242 }
243 
244 //#####################################################
245 oslFileError SAL_CALL osl_acquireVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
246 {
247     if ( Handle )
248     {
249         rtl_uString_acquire( (rtl_uString *)Handle );
250         return osl_File_E_None;
251     }
252     else
253         return osl_File_E_INVAL;
254 }
255 
256 //#####################################################
257 oslFileError SAL_CALL osl_releaseVolumeDeviceHandle( oslVolumeDeviceHandle Handle )
258 {
259     if ( Handle )
260     {
261         rtl_uString_release( (rtl_uString *)Handle );
262         return osl_File_E_None;
263     }
264     else
265         return osl_File_E_INVAL;
266 }
267 
268 //#####################################################
269 oslFileError SAL_CALL osl_getVolumeDeviceMountPath( oslVolumeDeviceHandle Handle, rtl_uString **pstrPath )
270 {
271     if ( Handle && pstrPath )
272     {
273         rtl_uString_assign( pstrPath, (rtl_uString *)Handle );
274         return osl_File_E_None;
275     }
276     else
277         return osl_File_E_INVAL;
278 }
279 
280 //##################################################################
281 // directory handling functions
282 //##################################################################
283 
284 #define DIRECTORYITEM_DRIVE     0
285 #define DIRECTORYITEM_FILE      1
286 #define DIRECTORYITEM_SERVER    2
287 
288 struct DirectoryItem_Impl
289 {
290     UINT uType;
291     union {
292         WIN32_FIND_DATA FindData;
293         TCHAR           cDriveString[MAX_PATH];
294     };
295     rtl_uString*    m_pFullPath;
296     BOOL            bFullPathNormalized;
297     int             nRefCount;
298 };
299 
300 //#####################################################
301 
302 #define DIRECTORYTYPE_LOCALROOT     0
303 #define DIRECTORYTYPE_NETROOT       1
304 #define DIRECTORYTYPE_NETRESORCE    2
305 #define DIRECTORYTYPE_FILESYSTEM    3
306 
307 struct Directory_Impl
308 {
309     UINT uType;
310     union {
311         HANDLE  hDirectory;
312         HANDLE  hEnumDrives;
313     };
314     rtl_uString*    m_pDirectoryPath;
315 };
316 
317 //#####################################################
318 
319 typedef struct tagDRIVEENUM
320 {
321     LPCTSTR lpIdent;
322     TCHAR   cBuffer[/*('Z' - 'A' + 1) * sizeof("A:\\") + 1*/256];
323     LPCTSTR lpCurrent;
324 } DRIVEENUM, * PDRIVEENUM, FAR * LPDRIVEENUM;
325 
326 //#####################################################
327 
328 static HANDLE WINAPI OpenLogicalDrivesEnum(void)
329 {
330     LPDRIVEENUM pEnum = (LPDRIVEENUM)HeapAlloc( GetProcessHeap(), 0, sizeof(DRIVEENUM) );
331     if ( pEnum )
332     {
333         DWORD dwNumCopied = GetLogicalDriveStrings( (sizeof(pEnum->cBuffer) - 1) / sizeof(TCHAR), pEnum->cBuffer );
334 
335         if ( dwNumCopied && dwNumCopied < sizeof(pEnum->cBuffer) / sizeof(TCHAR) )
336         {
337             pEnum->lpCurrent = pEnum->cBuffer;
338             pEnum->lpIdent = L"tagDRIVEENUM";
339         }
340         else
341         {
342             HeapFree( GetProcessHeap(), 0, pEnum );
343             pEnum = NULL;
344         }
345     }
346     return pEnum ? (HANDLE)pEnum : INVALID_HANDLE_VALUE;
347 }
348 
349 //#####################################################
350 static BOOL WINAPI EnumLogicalDrives(HANDLE hEnum, LPTSTR lpBuffer)
351 {
352     BOOL        fSuccess = FALSE;
353     LPDRIVEENUM pEnum = (LPDRIVEENUM)hEnum;
354 
355     if ( pEnum )
356     {
357         int nLen = _tcslen( pEnum->lpCurrent );
358 
359         if ( nLen )
360         {
361             CopyMemory( lpBuffer, pEnum->lpCurrent, (nLen + 1) * sizeof(TCHAR) );
362             pEnum->lpCurrent += nLen + 1;
363             fSuccess = TRUE;
364         }
365         else
366             SetLastError( ERROR_NO_MORE_FILES );
367     }
368     else
369         SetLastError( ERROR_INVALID_HANDLE );
370 
371     return fSuccess;
372 }
373 
374 //#####################################################
375 static BOOL WINAPI CloseLogicalDrivesEnum(HANDLE hEnum)
376 {
377     BOOL        fSuccess = FALSE;
378     LPDRIVEENUM pEnum = (LPDRIVEENUM)hEnum;
379 
380     if ( pEnum )
381     {
382         HeapFree( GetProcessHeap(), 0, pEnum );
383         fSuccess = TRUE;
384     }
385     else
386         SetLastError( ERROR_INVALID_HANDLE );
387 
388     return fSuccess;
389 }
390 
391 //#####################################################
392 typedef struct tagDIRECTORY
393 {
394     HANDLE          hFind;
395     WIN32_FIND_DATA aFirstData;
396 } DIRECTORY, *PDIRECTORY, FAR *LPDIRECTORY;
397 
398 //#####################################################
399 static HANDLE WINAPI OpenDirectory( rtl_uString* pPath)
400 {
401     LPDIRECTORY pDirectory = NULL;
402 
403     if ( pPath )
404     {
405         sal_uInt32 nLen = rtl_uString_getLength( pPath );
406         if ( nLen )
407         {
408             TCHAR* pSuffix = 0;
409             sal_uInt32 nSuffLen = 0;
410 
411             if ( pPath->buffer[nLen - 1] != L'\\' )
412             {
413                 pSuffix = L"\\*.*";
414                 nSuffLen = 4;
415             }
416             else
417             {
418                 pSuffix = L"*.*";
419                 nSuffLen = 3;
420             }
421 
422             TCHAR* szFileMask = reinterpret_cast< TCHAR* >( rtl_allocateMemory( sizeof( TCHAR ) * ( nLen + nSuffLen + 1 ) ) );
423 
424             _tcscpy( szFileMask, reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pPath ) ) );
425             _tcscat( szFileMask, pSuffix );
426 
427             pDirectory = (LPDIRECTORY)HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY));
428             pDirectory->hFind = FindFirstFile(szFileMask, &pDirectory->aFirstData);
429 
430             if (!IsValidHandle(pDirectory->hFind))
431             {
432                 if ( GetLastError() != ERROR_NO_MORE_FILES )
433                 {
434                     HeapFree(GetProcessHeap(), 0, pDirectory);
435                     pDirectory = NULL;
436                 }
437             }
438         }
439     }
440 
441     return (HANDLE)pDirectory;
442 }
443 
444 //#####################################################
445 BOOL WINAPI EnumDirectory(HANDLE hDirectory, LPWIN32_FIND_DATA pFindData)
446 {
447     BOOL        fSuccess = FALSE;
448     LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory;
449 
450     if ( pDirectory )
451     {
452         BOOL    fValid;
453 
454         do
455         {
456             if ( pDirectory->aFirstData.cFileName[0] )
457             {
458                 *pFindData = pDirectory->aFirstData;
459                 fSuccess = TRUE;
460                 pDirectory->aFirstData.cFileName[0] = 0;
461             }
462             else if ( IsValidHandle( pDirectory->hFind ) )
463                 fSuccess = FindNextFile( pDirectory->hFind, pFindData );
464             else
465             {
466                 fSuccess = FALSE;
467                 SetLastError( ERROR_NO_MORE_FILES );
468             }
469 
470             fValid = fSuccess && _tcscmp( TEXT("."), pFindData->cFileName ) != 0 && _tcscmp( TEXT(".."), pFindData->cFileName ) != 0;
471 
472         } while( fSuccess && !fValid );
473     }
474     else
475         SetLastError( ERROR_INVALID_HANDLE );
476 
477     return fSuccess;
478 }
479 
480 //#####################################################
481 static BOOL WINAPI CloseDirectory(HANDLE hDirectory)
482 {
483     BOOL        fSuccess = FALSE;
484     LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory;
485 
486     if (pDirectory)
487     {
488         if (IsValidHandle(pDirectory->hFind))
489             fSuccess = FindClose(pDirectory->hFind);
490 
491         fSuccess = HeapFree(GetProcessHeap(), 0, pDirectory) && fSuccess;
492     }
493     else
494         SetLastError(ERROR_INVALID_HANDLE);
495 
496     return fSuccess;
497 }
498 
499 //#####################################################
500 static oslFileError osl_openLocalRoot(
501     rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
502 {
503     rtl_uString     *strSysPath = NULL;
504     oslFileError    error;
505 
506     if ( !pDirectory )
507         return osl_File_E_INVAL;
508 
509     *pDirectory = NULL;
510 
511     error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysPath, sal_False );
512     if ( osl_File_E_None == error )
513     {
514         Directory_Impl  *pDirImpl;
515 
516         pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory( sizeof(Directory_Impl)));
517         ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
518         rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strSysPath );
519 
520         /* Append backslash if neccessary */
521 
522         /* @@@ToDo
523            use function ensure backslash
524         */
525         sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
526         if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
527         {
528             rtl_uString* pCurDir = 0;
529             rtl_uString* pBackSlash = 0;
530 
531             rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
532             rtl_uString_newFromAscii( &pBackSlash, "\\" );
533             rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
534             rtl_uString_release( pBackSlash );
535             rtl_uString_release( pCurDir );
536         }
537 
538         pDirImpl->uType = DIRECTORYTYPE_LOCALROOT;
539         pDirImpl->hEnumDrives = OpenLogicalDrivesEnum();
540 
541         /* @@@ToDo
542            Use IsValidHandle(...)
543         */
544         if ( pDirImpl->hEnumDrives != INVALID_HANDLE_VALUE )
545         {
546             *pDirectory = (oslDirectory)pDirImpl;
547             error = osl_File_E_None;
548         }
549         else
550         {
551             if ( pDirImpl )
552             {
553                 if ( pDirImpl->m_pDirectoryPath )
554                 {
555                     rtl_uString_release( pDirImpl->m_pDirectoryPath );
556                     pDirImpl->m_pDirectoryPath = 0;
557                 }
558 
559                 rtl_freeMemory(pDirImpl);
560                 pDirImpl = 0;
561             }
562 
563             error = oslTranslateFileError( GetLastError() );
564         }
565 
566         rtl_uString_release( strSysPath );
567     }
568     return error;
569 }
570 
571 //#####################################################
572 static oslFileError SAL_CALL osl_openFileDirectory(
573     rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
574 {
575     oslFileError error = osl_File_E_None;
576 
577     if ( !pDirectory )
578         return osl_File_E_INVAL;
579     *pDirectory = NULL;
580 
581     Directory_Impl *pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl)));
582     ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
583     rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strDirectoryPath );
584 
585     /* Append backslash if neccessary */
586 
587     /* @@@ToDo
588        use function ensure backslash
589     */
590     sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath );
591     if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' )
592     {
593         rtl_uString* pCurDir = 0;
594         rtl_uString* pBackSlash = 0;
595 
596         rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath );
597         rtl_uString_newFromAscii( &pBackSlash, "\\" );
598         rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash );
599         rtl_uString_release( pBackSlash );
600         rtl_uString_release( pCurDir );
601     }
602 
603 
604     pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM;
605     pDirImpl->hDirectory = OpenDirectory( pDirImpl->m_pDirectoryPath );
606 
607     if ( !pDirImpl->hDirectory )
608     {
609         error = oslTranslateFileError( GetLastError() );
610 
611         if ( pDirImpl->m_pDirectoryPath )
612         {
613             rtl_uString_release( pDirImpl->m_pDirectoryPath );
614             pDirImpl->m_pDirectoryPath = 0;
615         }
616 
617         rtl_freeMemory(pDirImpl), pDirImpl = 0;
618     }
619 
620     *pDirectory = (oslDirectory)(pDirImpl);
621     return error;
622 }
623 
624 //#####################################################
625 static oslFileError SAL_CALL osl_openNetworkServer(
626     rtl_uString *strSysDirPath, oslDirectory *pDirectory)
627 {
628     NETRESOURCEW    aNetResource;
629     HANDLE          hEnum;
630     DWORD           dwError;
631 
632     ZeroMemory( &aNetResource, sizeof(aNetResource) );
633 
634     aNetResource.lpRemoteName = reinterpret_cast<LPWSTR>(strSysDirPath->buffer);
635 
636     dwError = WNetOpenEnumW(
637         RESOURCE_GLOBALNET,
638         RESOURCETYPE_DISK,
639         RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER,
640         &aNetResource,
641         &hEnum );
642 
643     if ( ERROR_SUCCESS == dwError )
644     {
645         Directory_Impl  *pDirImpl;
646 
647         pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl)));
648         ZeroMemory( pDirImpl, sizeof(Directory_Impl) );
649         pDirImpl->uType = DIRECTORYTYPE_NETROOT;
650         pDirImpl->hDirectory = hEnum;
651         *pDirectory = (oslDirectory)pDirImpl;
652     }
653     return oslTranslateFileError( dwError );
654 }
655 
656 //#############################################
657 static DWORD create_dir_with_callback(
658     rtl_uString * dir_path,
659     oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
660     void* pData)
661 {
662     // Create the specified directory and call the
663     // user specified callback function. On success
664     // the function returns ERROR_SUCCESS else a Win32 error code.
665 
666     BOOL bCreated = FALSE;
667 
668     bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( dir_path )), NULL );
669 
670     if ( bCreated )
671     {
672         if (aDirectoryCreationCallbackFunc)
673         {
674             rtl::OUString url;
675             _osl_getFileURLFromSystemPath(dir_path, &(url.pData));
676             aDirectoryCreationCallbackFunc(pData, url.pData);
677         }
678         return ERROR_SUCCESS;
679     }
680     return GetLastError();
681 }
682 
683 //#############################################
684 static int path_make_parent(sal_Unicode* path)
685 {
686     /*  Cut off the last part of the given path to
687     get the parent only, e.g. 'c:\dir\subdir' ->
688     'c:\dir' or '\\share\sub\dir' -> '\\share\sub'
689     @return The position where the path has been cut
690     off (this is the posistion of the last backslash).
691     If there are no more parents 0 will be returned,
692     e.g. 'c:\' or '\\Share' have no more parents */
693 
694     OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) == -1, "Path must not contain slashes");
695     OSL_PRECOND(has_path_parent(path), "Path must have a parent");
696 
697     sal_Unicode* pos_last_backslash = path + rtl_ustr_lastIndexOfChar(path, BACKSLASH);
698     *pos_last_backslash = 0;
699     return (pos_last_backslash - path);
700 }
701 
702 //#############################################
703 static DWORD create_dir_recursively_(
704     rtl_uString * dir_path,
705     oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
706     void* pData)
707 {
708     OSL_PRECOND(
709         rtl_ustr_lastIndexOfChar_WithLength(dir_path->buffer, dir_path->length, BACKSLASH) != dir_path->length,
710         "Path must not end with a backslash");
711 
712     DWORD w32_error = create_dir_with_callback(
713         dir_path, aDirectoryCreationCallbackFunc, pData);
714     if (w32_error == ERROR_SUCCESS)
715         return ERROR_SUCCESS;
716 
717     if ((w32_error != ERROR_PATH_NOT_FOUND) || !has_path_parent(dir_path->buffer))
718         return w32_error;
719 
720     int pos = path_make_parent(dir_path->buffer); // dir_path->buffer[pos] = 0, restore below
721 
722     w32_error = create_dir_recursively_(
723         dir_path, aDirectoryCreationCallbackFunc, pData);
724 
725     dir_path->buffer[pos] = BACKSLASH; // restore
726 
727     if (ERROR_SUCCESS != w32_error)
728         return w32_error;
729 
730     return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData);
731 }
732 
733 //#############################################
734 oslFileError SAL_CALL osl_createDirectoryPath(
735     rtl_uString* aDirectoryUrl,
736     oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc,
737     void* pData)
738 {
739     if (aDirectoryUrl == NULL)
740         return osl_File_E_INVAL;
741 
742     rtl::OUString sys_path;
743     oslFileError osl_error =
744         _osl_getSystemPathFromFileURL(aDirectoryUrl, &sys_path.pData, sal_False);
745 
746     if (osl_error != osl_File_E_None)
747         return osl_error;
748 
749     osl::systemPathRemoveSeparator(sys_path);
750 
751     // const_cast because sys_path is a local copy
752     // which we want to modify inplace instead of
753     // coyp it into another buffer on the heap again
754     return oslTranslateFileError(create_dir_recursively_(
755         sys_path.pData, aDirectoryCreationCallbackFunc, pData));
756 }
757 
758 //#####################################################
759 oslFileError SAL_CALL osl_createDirectory(rtl_uString* strPath)
760 {
761     rtl_uString *strSysPath = NULL;
762     oslFileError    error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
763 
764     if ( osl_File_E_None == error )
765     {
766         BOOL bCreated = FALSE;
767 
768         bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strSysPath )), NULL );
769 
770         if ( !bCreated )
771         {
772             /*@@@ToDo
773               The following case is a hack because the ucb or the webtop had some
774               problems with the error code that CreateDirectory returns in
775               case the path is only a logical drive, should be removed!
776             */
777 
778             const sal_Unicode   *pBuffer = rtl_uString_getStr( strSysPath );
779             sal_Int32           nLen = rtl_uString_getLength( strSysPath );
780 
781             if (
782                 ( ( pBuffer[0] >= 'A' && pBuffer[0] <= 'Z' ) ||
783                   ( pBuffer[0] >= 'a' && pBuffer[0] <= 'z' ) ) &&
784                 pBuffer[1] == ':' && ( nLen ==2 || ( nLen == 3 && pBuffer[2] == '\\' ) )
785                 )
786                 SetLastError( ERROR_ALREADY_EXISTS );
787 
788             error = oslTranslateFileError( GetLastError() );
789         }
790 
791         rtl_uString_release( strSysPath );
792     }
793     return error;
794 }
795 
796 //#####################################################
797 oslFileError SAL_CALL osl_removeDirectory(rtl_uString* strPath)
798 {
799     rtl_uString *strSysPath = NULL;
800     oslFileError    error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False );
801 
802     if ( osl_File_E_None == error )
803     {
804         if ( RemoveDirectory( reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )) ) )
805             error = osl_File_E_None;
806         else
807             error = oslTranslateFileError( GetLastError() );
808 
809         rtl_uString_release( strSysPath );
810     }
811     return error;
812 }
813 
814 //#####################################################
815 oslFileError SAL_CALL osl_openDirectory(rtl_uString *strDirectoryPath, oslDirectory *pDirectory)
816 {
817     oslFileError    error;
818 
819     if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath->buffer, "file:///" ) )
820         error = osl_openLocalRoot( strDirectoryPath, pDirectory );
821     else
822     {
823         rtl_uString *strSysDirectoryPath = NULL;
824         DWORD       dwPathType;
825 
826         error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysDirectoryPath, sal_False );
827 
828         if ( osl_File_E_None != error )
829                 return error;
830 
831         dwPathType = IsValidFilePath( strSysDirectoryPath, NULL, VALIDATEPATH_NORMAL, NULL );
832 
833         if ( dwPathType & PATHTYPE_IS_SERVER )
834         {
835             error = osl_openNetworkServer( strSysDirectoryPath, pDirectory );
836         }
837         else
838             error = osl_openFileDirectory( strSysDirectoryPath, pDirectory );
839 
840         rtl_uString_release( strSysDirectoryPath );
841     }
842     return error;
843 }
844 
845 //#####################################################
846 static oslFileError SAL_CALL osl_getNextNetResource(
847     oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint )
848 {
849     Directory_Impl      *pDirImpl = (Directory_Impl *)Directory;
850     DirectoryItem_Impl  *pItemImpl = NULL;
851     BYTE                buffer[16384];
852     LPNETRESOURCEW      lpNetResource = (LPNETRESOURCEW)buffer;
853     DWORD               dwError, dwCount, dwBufSize;
854 
855     uHint = uHint; /* to get no warning */
856 
857     if ( !pItem )
858         return osl_File_E_INVAL;
859     *pItem = NULL;
860 
861     if ( !pDirImpl )
862         return osl_File_E_INVAL;
863 
864     dwCount = 1;
865     dwBufSize = sizeof(buffer);
866     dwError = WNetEnumResource( pDirImpl->hDirectory, &dwCount, lpNetResource, &dwBufSize );
867 
868     switch ( dwError )
869     {
870         case NO_ERROR:
871         case ERROR_MORE_DATA:
872         {
873             pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
874             if ( !pItemImpl )
875                 return osl_File_E_NOMEM;
876 
877             ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
878             pItemImpl->uType = DIRECTORYITEM_DRIVE;
879             osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
880 
881             wcscpy( pItemImpl->cDriveString, lpNetResource->lpRemoteName );
882 
883             *pItem = pItemImpl;
884         }
885         return osl_File_E_None;
886         case ERROR_NO_MORE_ITEMS:
887             return osl_File_E_NOENT;
888         default:
889             return oslTranslateFileError( dwError );
890     }
891 }
892 
893 //#####################################################
894 static oslFileError SAL_CALL osl_getNextDrive(
895     oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint )
896 {
897     Directory_Impl      *pDirImpl = (Directory_Impl *)Directory;
898     DirectoryItem_Impl  *pItemImpl = NULL;
899     BOOL                fSuccess;
900 
901     uHint = uHint; /* avoid warnings */
902 
903     if ( !pItem )
904         return osl_File_E_INVAL;
905     *pItem = NULL;
906 
907     if ( !pDirImpl )
908         return osl_File_E_INVAL;
909 
910     pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
911     if ( !pItemImpl )
912         return osl_File_E_NOMEM;
913 
914     ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
915     pItemImpl->uType = DIRECTORYITEM_DRIVE;
916     osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
917     fSuccess = EnumLogicalDrives( pDirImpl->hEnumDrives, pItemImpl->cDriveString );
918 
919     if ( fSuccess )
920     {
921         *pItem = pItemImpl;
922         return osl_File_E_None;
923     }
924     else
925     {
926         if ( pItemImpl->m_pFullPath )
927         {
928             rtl_uString_release( pItemImpl->m_pFullPath );
929             pItemImpl->m_pFullPath = 0;
930         }
931 
932         rtl_freeMemory( pItemImpl );
933         return oslTranslateFileError( GetLastError() );
934     }
935 }
936 
937 //#####################################################
938 static oslFileError SAL_CALL osl_getNextFileItem(
939     oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint)
940 {
941     Directory_Impl      *pDirImpl = (Directory_Impl *)Directory;
942     DirectoryItem_Impl  *pItemImpl = NULL;
943     BOOL                fFound;
944 
945     uHint = uHint; /* avoid warnings */
946 
947     if ( !pItem )
948         return osl_File_E_INVAL;
949     *pItem = NULL;
950 
951     if ( !pDirImpl )
952         return osl_File_E_INVAL;
953 
954     pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
955     if ( !pItemImpl )
956         return osl_File_E_NOMEM;
957 
958     memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) );
959     fFound = EnumDirectory( pDirImpl->hDirectory, &pItemImpl->FindData );
960 
961     if ( fFound )
962     {
963         pItemImpl->uType = DIRECTORYITEM_FILE;
964         pItemImpl->nRefCount = 1;
965 
966         rtl_uString* pTmpFileName = 0;
967         rtl_uString_newFromStr( &pTmpFileName,  reinterpret_cast<const sal_Unicode *>(pItemImpl->FindData.cFileName) );
968         rtl_uString_newConcat( &pItemImpl->m_pFullPath, pDirImpl->m_pDirectoryPath, pTmpFileName );
969         rtl_uString_release( pTmpFileName );
970 
971         pItemImpl->bFullPathNormalized = FALSE;
972         *pItem = (oslDirectoryItem)pItemImpl;
973         return osl_File_E_None;
974     }
975     else
976     {
977         if ( pItemImpl->m_pFullPath )
978         {
979             rtl_uString_release( pItemImpl->m_pFullPath );
980             pItemImpl->m_pFullPath = 0;
981         }
982 
983         rtl_freeMemory( pItemImpl );
984         return oslTranslateFileError( GetLastError() );
985     }
986 }
987 
988 //#####################################################
989 oslFileError SAL_CALL osl_getNextDirectoryItem(
990     oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint)
991 {
992     Directory_Impl      *pDirImpl = (Directory_Impl *)Directory;
993 
994     /* Assume failure */
995 
996     if ( !pItem )
997         return osl_File_E_INVAL;
998     *pItem = NULL;
999 
1000     if ( !pDirImpl )
1001         return osl_File_E_INVAL;
1002 
1003     switch ( pDirImpl->uType )
1004     {
1005     case DIRECTORYTYPE_LOCALROOT:
1006         return osl_getNextDrive( Directory, pItem, uHint );
1007     case DIRECTORYTYPE_NETROOT:
1008         return osl_getNextNetResource( Directory, pItem, uHint );
1009     case DIRECTORYTYPE_FILESYSTEM:
1010         return osl_getNextFileItem( Directory, pItem, uHint );
1011     default:
1012         return osl_File_E_INVAL;
1013     }
1014 }
1015 
1016 //#####################################################
1017 oslFileError SAL_CALL osl_closeDirectory(oslDirectory Directory)
1018 {
1019     Directory_Impl  *pDirImpl = (Directory_Impl *)Directory;
1020     oslFileError    eError = osl_File_E_INVAL;
1021 
1022     if ( pDirImpl )
1023     {
1024         switch ( pDirImpl->uType )
1025         {
1026         case DIRECTORYTYPE_FILESYSTEM:
1027             eError = CloseDirectory( pDirImpl->hDirectory ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
1028             break;
1029         case DIRECTORYTYPE_LOCALROOT:
1030             eError = CloseLogicalDrivesEnum( pDirImpl->hEnumDrives ) ? osl_File_E_None : oslTranslateFileError( GetLastError() );
1031             break;
1032         case DIRECTORYTYPE_NETROOT:
1033             {
1034                 DWORD err = WNetCloseEnum(pDirImpl->hDirectory);
1035                 eError = (err == NO_ERROR) ? osl_File_E_None : oslTranslateFileError(err);
1036             }
1037             break;
1038         default:
1039             OSL_ENSURE( 0, "Invalid directory type" );
1040             break;
1041         }
1042 
1043         if ( pDirImpl->m_pDirectoryPath )
1044         {
1045             rtl_uString_release( pDirImpl->m_pDirectoryPath );
1046             pDirImpl->m_pDirectoryPath = 0;
1047         }
1048 
1049         rtl_freeMemory(pDirImpl);
1050     }
1051     return eError;
1052 }
1053 
1054 //#####################################################
1055 /* Different types of paths */
1056 typedef enum _PATHTYPE
1057 {
1058     PATHTYPE_SYNTAXERROR = 0,
1059     PATHTYPE_NETROOT,
1060     PATHTYPE_NETSERVER,
1061     PATHTYPE_VOLUME,
1062     PATHTYPE_FILE
1063 } PATHTYPE;
1064 
1065 oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString *strFilePath, oslDirectoryItem *pItem)
1066 {
1067     oslFileError    error = osl_File_E_None;
1068     rtl_uString*    strSysFilePath = NULL;
1069     PATHTYPE        type = PATHTYPE_FILE;
1070     DWORD           dwPathType;
1071 
1072     /* Assume failure */
1073 
1074     if ( !pItem )
1075         return osl_File_E_INVAL;
1076 
1077     *pItem = NULL;
1078 
1079 
1080     error = _osl_getSystemPathFromFileURL( strFilePath, &strSysFilePath, sal_False );
1081 
1082     if ( osl_File_E_None != error )
1083             return error;
1084 
1085     dwPathType = IsValidFilePath( strSysFilePath, NULL, VALIDATEPATH_NORMAL, NULL );
1086 
1087     if ( dwPathType & PATHTYPE_IS_VOLUME )
1088         type = PATHTYPE_VOLUME;
1089     else if ( dwPathType & PATHTYPE_IS_SERVER )
1090         type = PATHTYPE_NETSERVER;
1091     else
1092         type = PATHTYPE_FILE;
1093 
1094     switch ( type )
1095     {
1096     case PATHTYPE_NETSERVER:
1097         {
1098             DirectoryItem_Impl* pItemImpl =
1099                 reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
1100 
1101             if ( !pItemImpl )
1102                 error = osl_File_E_NOMEM;
1103 
1104             if ( osl_File_E_None == error )
1105             {
1106                 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1107                 pItemImpl->uType = DIRECTORYITEM_SERVER;
1108 
1109                 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
1110                 rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath );
1111 
1112                 // Assign a title anyway
1113                 {
1114                     int iSrc = 2;
1115                     int iDst = 0;
1116 
1117                     while( iSrc < strSysFilePath->length && strSysFilePath->buffer[iSrc] && strSysFilePath->buffer[iSrc] != '\\' )
1118                     {
1119                         pItemImpl->FindData.cFileName[iDst++] = strSysFilePath->buffer[iSrc++];
1120                     }
1121                 }
1122 
1123                 *pItem = pItemImpl;
1124             }
1125         }
1126         break;
1127     case PATHTYPE_VOLUME:
1128         {
1129             DirectoryItem_Impl* pItemImpl =
1130                 reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
1131 
1132             if ( !pItemImpl )
1133                 error = osl_File_E_NOMEM;
1134 
1135             if ( osl_File_E_None == error )
1136             {
1137                 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1138                 pItemImpl->uType = DIRECTORYITEM_DRIVE;
1139 
1140                 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
1141 
1142                 _tcscpy( pItemImpl->cDriveString, reinterpret_cast<LPCTSTR>(strSysFilePath->buffer) );
1143                 pItemImpl->cDriveString[0] = _toupper( pItemImpl->cDriveString[0] );
1144 
1145                 if ( pItemImpl->cDriveString[_tcslen(pItemImpl->cDriveString) - 1] != '\\' )
1146                     _tcscat( pItemImpl->cDriveString, TEXT( "\\" ) );
1147 
1148                 *pItem = pItemImpl;
1149             }
1150         }
1151         break;
1152     case PATHTYPE_SYNTAXERROR:
1153     case PATHTYPE_NETROOT:
1154     case PATHTYPE_FILE:
1155         {
1156             HANDLE              hFind;
1157             WIN32_FIND_DATA     aFindData;
1158 
1159             if ( strSysFilePath->length > 0 && strSysFilePath->buffer[strSysFilePath->length - 1] == '\\' )
1160                 rtl_uString_newFromStr_WithLength( &strSysFilePath, strSysFilePath->buffer, strSysFilePath->length - 1 );
1161 
1162             hFind = FindFirstFile( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(strSysFilePath)), &aFindData );
1163 
1164             if ( hFind != INVALID_HANDLE_VALUE )
1165             {
1166                 DirectoryItem_Impl  *pItemImpl =
1167                     reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl)));
1168 
1169                 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) );
1170                 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl );
1171 
1172                 CopyMemory( &pItemImpl->FindData, &aFindData, sizeof(WIN32_FIND_DATA) );
1173                 rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath );
1174 
1175                 // MT: This costs 600ms startup time on fast v60x!
1176                 // GetCaseCorrectPathName( pItemImpl->szFullPath, pItemImpl->szFullPath, sizeof(pItemImpl->szFullPath) );
1177 
1178                 pItemImpl->uType = DIRECTORYITEM_FILE;
1179                 *pItem = pItemImpl;
1180                 FindClose( hFind );
1181             }
1182             else
1183                 error = oslTranslateFileError( GetLastError() );
1184         }
1185         break;
1186     }
1187 
1188     if ( strSysFilePath )
1189         rtl_uString_release( strSysFilePath );
1190 
1191     return error;
1192 }
1193 
1194 //#####################################################
1195 oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item )
1196 {
1197     DirectoryItem_Impl  *pItemImpl = (DirectoryItem_Impl *)Item;
1198 
1199     if ( !pItemImpl )
1200         return osl_File_E_INVAL;
1201 
1202     pItemImpl->nRefCount++;
1203     return osl_File_E_None;
1204 }
1205 
1206 //#####################################################
1207 oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item )
1208 {
1209     DirectoryItem_Impl  *pItemImpl = (DirectoryItem_Impl *)Item;
1210 
1211     if ( !pItemImpl )
1212         return osl_File_E_INVAL;
1213 
1214     if ( ! --pItemImpl->nRefCount )
1215     {
1216         if ( pItemImpl->m_pFullPath )
1217         {
1218             rtl_uString_release( pItemImpl->m_pFullPath );
1219             pItemImpl->m_pFullPath = 0;
1220         }
1221 
1222         rtl_freeMemory( pItemImpl );
1223     }
1224 
1225     return osl_File_E_None;
1226 }
1227 
1228 //#####################################################
1229 // volume / file info handling functions
1230 //#####################################################
1231 
1232 //#####################################################
1233 static inline bool is_floppy_A_present()
1234 { return (GetLogicalDrives() & 1); }
1235 
1236 //#####################################################
1237 static inline bool is_floppy_B_present()
1238 { return (GetLogicalDrives() & 2); }
1239 
1240 //#####################################################
1241 bool is_floppy_volume_mount_point(const rtl::OUString& path)
1242 {
1243     // determines if a volume mount point shows to a floppy
1244     // disk by comparing the unique volume names
1245     static const LPCWSTR FLOPPY_A = L"A:\\";
1246     static const LPCWSTR FLOPPY_B = L"B:\\";
1247 
1248     rtl::OUString p(path);
1249     osl::systemPathEnsureSeparator(p);
1250 
1251     TCHAR vn[51];
1252     if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn)))
1253     {
1254         TCHAR vnfloppy[51];
1255         if (is_floppy_A_present() &&
1256             GetVolumeNameForVolumeMountPoint(FLOPPY_A, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) &&
1257             (0 == wcscmp(vn, vnfloppy)))
1258             return true;
1259 
1260         if (is_floppy_B_present() &&
1261             GetVolumeNameForVolumeMountPoint(FLOPPY_B, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) &&
1262             (0 == wcscmp(vn, vnfloppy)))
1263             return true;
1264     }
1265     return false;
1266 }
1267 
1268 //################################################
1269 static bool is_floppy_drive(const rtl::OUString& path)
1270 {
1271     static const LPCWSTR FLOPPY_DRV_LETTERS = TEXT("AaBb");
1272 
1273     // we must take into account that even a floppy
1274     // drive may be mounted to a directory so checking
1275     // for the drive letter alone is not sufficient
1276     // we must compare the unique volume name with
1277     // that of the available floppy disks
1278 
1279     const sal_Unicode* pszPath = path.getStr();
1280     return ((wcschr(FLOPPY_DRV_LETTERS, pszPath[0]) && (L':' == pszPath[1])) || is_floppy_volume_mount_point(path));
1281 }
1282 
1283 //#####################################################
1284 static bool is_volume_mount_point(const rtl::OUString& path)
1285 {
1286     rtl::OUString p(path);
1287     osl::systemPathRemoveSeparator(p);
1288 
1289     bool  is_volume_root = false;
1290 
1291     if (!is_floppy_drive(p))
1292     {
1293         DWORD fattr = GetFileAttributes(reinterpret_cast<LPCTSTR>(p.getStr()));
1294 
1295         if ((INVALID_FILE_ATTRIBUTES != fattr) &&
1296             (FILE_ATTRIBUTE_REPARSE_POINT & fattr))
1297         {
1298             WIN32_FIND_DATA find_data;
1299             HANDLE h_find = FindFirstFile(reinterpret_cast<LPCTSTR>(p.getStr()), &find_data);
1300 
1301             if (IsValidHandle(h_find) &&
1302                 (FILE_ATTRIBUTE_REPARSE_POINT & find_data.dwFileAttributes) &&
1303                 (IO_REPARSE_TAG_MOUNT_POINT == find_data.dwReserved0))
1304             {
1305                 is_volume_root = true;
1306             }
1307             if (IsValidHandle(h_find))
1308                 FindClose(h_find);
1309         }
1310     }
1311     return is_volume_root;
1312 }
1313 
1314 //#############################################
1315 static UINT get_volume_mount_point_drive_type(const rtl::OUString& path)
1316 {
1317     if (0 == path.getLength())
1318         return GetDriveType(NULL);
1319 
1320     rtl::OUString p(path);
1321     osl::systemPathEnsureSeparator(p);
1322 
1323     TCHAR vn[51];
1324     if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn)))
1325         return GetDriveType(vn);
1326 
1327     return DRIVE_NO_ROOT_DIR;
1328 }
1329 
1330 //#############################################
1331 static inline bool is_drivetype_request(sal_uInt32 field_mask)
1332 {
1333     return (field_mask & osl_VolumeInfo_Mask_Attributes);
1334 }
1335 
1336 //#############################################
1337 static oslFileError osl_get_drive_type(
1338     const rtl::OUString& path, oslVolumeInfo* pInfo)
1339 {
1340     // GetDriveType fails on empty volume mount points
1341     // see Knowledge Base Q244089
1342     UINT drive_type;
1343     if (is_volume_mount_point(path))
1344         drive_type = get_volume_mount_point_drive_type(path);
1345     else
1346         drive_type = GetDriveType(reinterpret_cast<LPCTSTR>(path.getStr()));
1347 
1348     if (DRIVE_NO_ROOT_DIR == drive_type)
1349         return oslTranslateFileError(ERROR_INVALID_DRIVE);
1350 
1351     pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1352 
1353     switch (drive_type)
1354     {
1355         case DRIVE_CDROM:
1356             pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable;
1357             break;
1358         case DRIVE_REMOVABLE:
1359             pInfo->uAttributes |= osl_Volume_Attribute_Removeable;
1360             if (is_floppy_drive(path))
1361                 pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk;
1362             break;
1363         case DRIVE_FIXED:
1364             pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk;
1365             break;
1366         case DRIVE_RAMDISK:
1367             pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk;
1368             break;
1369         case DRIVE_REMOTE:
1370             pInfo->uAttributes |= osl_Volume_Attribute_Remote;
1371             break;
1372         case DRIVE_UNKNOWN:
1373             pInfo->uAttributes = 0;
1374             break;
1375         default:
1376             pInfo->uValidFields &= ~osl_VolumeInfo_Mask_Attributes;
1377             pInfo->uAttributes = 0;
1378             break;
1379     }
1380     return osl_File_E_None;
1381 }
1382 
1383 //#############################################
1384 static inline bool is_volume_space_info_request(sal_uInt32 field_mask)
1385 {
1386     return (field_mask &
1387             (osl_VolumeInfo_Mask_TotalSpace |
1388              osl_VolumeInfo_Mask_UsedSpace  |
1389              osl_VolumeInfo_Mask_FreeSpace));
1390 }
1391 
1392 //#############################################
1393 static void get_volume_space_information(
1394     const rtl::OUString& path, oslVolumeInfo *pInfo)
1395 {
1396     BOOL ret = GetDiskFreeSpaceEx(
1397         reinterpret_cast<LPCTSTR>(path.getStr()),
1398         (PULARGE_INTEGER)&(pInfo->uFreeSpace),
1399         (PULARGE_INTEGER)&(pInfo->uTotalSpace),
1400         NULL);
1401 
1402     if (ret)
1403     {
1404         pInfo->uUsedSpace    = pInfo->uTotalSpace - pInfo->uFreeSpace;
1405         pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace |
1406             osl_VolumeInfo_Mask_UsedSpace |
1407             osl_VolumeInfo_Mask_FreeSpace;
1408     }
1409 }
1410 
1411 //#############################################
1412 static inline bool is_filesystem_attributes_request(sal_uInt32 field_mask)
1413 {
1414     return (field_mask &
1415             (osl_VolumeInfo_Mask_MaxNameLength |
1416              osl_VolumeInfo_Mask_MaxPathLength |
1417              osl_VolumeInfo_Mask_FileSystemName |
1418              osl_VolumeInfo_Mask_FileSystemCaseHandling));
1419 }
1420 
1421 //#############################################
1422 static oslFileError get_filesystem_attributes(
1423     const rtl::OUString& path, sal_uInt32 field_mask, oslVolumeInfo* pInfo)
1424 {
1425     pInfo->uAttributes = 0;
1426 
1427     // osl_get_drive_type must be called first because
1428     // this function resets osl_VolumeInfo_Mask_Attributes
1429     // on failure
1430     if (is_drivetype_request(field_mask))
1431     {
1432         oslFileError osl_error = osl_get_drive_type(path, pInfo);
1433         if (osl_File_E_None != osl_error)
1434             return osl_error;
1435     }
1436     if (is_filesystem_attributes_request(field_mask))
1437     {
1438         /* the following two parameters can not be longer than MAX_PATH+1 */
1439         WCHAR vn[MAX_PATH+1];
1440         WCHAR fsn[MAX_PATH+1];
1441 
1442         DWORD serial;
1443         DWORD mcl;
1444         DWORD flags;
1445 
1446         LPCTSTR pszPath = reinterpret_cast<LPCTSTR>(path.getStr());
1447         if (GetVolumeInformation(pszPath, vn, MAX_PATH+1, &serial, &mcl, &flags, fsn, MAX_PATH+1))
1448         {
1449             // Currently sal does not use this value, instead MAX_PATH is used
1450             pInfo->uValidFields   |= osl_VolumeInfo_Mask_MaxNameLength;
1451             pInfo->uMaxNameLength  = mcl;
1452 
1453             // Should the uMaxPathLength be set to 32767, "\\?\" prefix allowes it
1454             pInfo->uValidFields   |= osl_VolumeInfo_Mask_MaxPathLength;
1455             pInfo->uMaxPathLength  = MAX_PATH;
1456 
1457             pInfo->uValidFields   |= osl_VolumeInfo_Mask_FileSystemName;
1458             rtl_uString_newFromStr(&pInfo->ustrFileSystemName, reinterpret_cast<const sal_Unicode*>(fsn));
1459 
1460             // volumes (even NTFS) will always be considered case
1461             // insensitive because the Win32 API is not able to
1462             // deal with case sensitive volumes see M$ Knowledge Base
1463             // article 100625 that's why we never set the attribute
1464             // osl_Volume_Attribute_Case_Sensitive
1465 
1466             if (flags & FS_CASE_IS_PRESERVED)
1467                 pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved;
1468 
1469             pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes;
1470         }
1471     }
1472     return osl_File_E_None;
1473 }
1474 
1475 //#####################################################
1476 static bool path_get_parent(rtl::OUString& path)
1477 {
1478     OSL_PRECOND(path.lastIndexOf(SLASH) == -1, "Path must not have slashes");
1479 
1480     if (!has_path_parent(path))
1481     {
1482         sal_Int32 i = path.lastIndexOf(BACKSLASH);
1483         if (-1 < i)
1484         {
1485             path = rtl::OUString(path.getStr(), i);
1486             return true;
1487         }
1488     }
1489     return false;
1490 }
1491 
1492 //#####################################################
1493 static void path_travel_to_volume_root(const rtl::OUString& system_path, rtl::OUString& volume_root)
1494 {
1495     rtl::OUString sys_path(system_path);
1496 
1497     while(!is_volume_mount_point(sys_path) && path_get_parent(sys_path))
1498         /**/;
1499 
1500     volume_root = sys_path;
1501     osl::systemPathEnsureSeparator(volume_root);
1502 }
1503 
1504 //#############################################
1505 oslFileError SAL_CALL osl_getVolumeInformation(
1506     rtl_uString *ustrURL, oslVolumeInfo *pInfo, sal_uInt32 uFieldMask )
1507 {
1508     if (!pInfo)
1509         return osl_File_E_INVAL;
1510 
1511     rtl::OUString system_path;
1512     oslFileError error = _osl_getSystemPathFromFileURL(ustrURL, &system_path.pData, sal_False);
1513 
1514     if (osl_File_E_None != error)
1515         return error;
1516 
1517     rtl::OUString volume_root;
1518     path_travel_to_volume_root(system_path, volume_root);
1519 
1520     pInfo->uValidFields = 0;
1521 
1522     if ((error = get_filesystem_attributes(volume_root, uFieldMask, pInfo)) != osl_File_E_None)
1523         return error;
1524 
1525     if (is_volume_space_info_request(uFieldMask))
1526         get_volume_space_information(volume_root, pInfo);
1527 
1528     if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle)
1529     {
1530         pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle;
1531         osl_getFileURLFromSystemPath(volume_root.pData, (rtl_uString**)&pInfo->pDeviceHandle);
1532     }
1533 
1534     return osl_File_E_None;
1535 }
1536 
1537 //#####################################################
1538 static oslFileError SAL_CALL osl_getDriveInfo(
1539     oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask)
1540 {
1541     DirectoryItem_Impl  *pItemImpl = (DirectoryItem_Impl *)Item;
1542     TCHAR               cDrive[3] = TEXT("A:");
1543     TCHAR               cRoot[4] = TEXT("A:\\");
1544 
1545     if ( !pItemImpl )
1546         return osl_File_E_INVAL;
1547 
1548     pStatus->uValidFields = 0;
1549 
1550     cDrive[0] = pItemImpl->cDriveString[0];
1551     cRoot[0] = pItemImpl->cDriveString[0];
1552 
1553     if ( uFieldMask & osl_FileStatus_Mask_FileName )
1554     {
1555         if ( pItemImpl->cDriveString[0] == '\\' && pItemImpl->cDriveString[1] == '\\' )
1556         {
1557             LPCWSTR lpFirstBkSlash = wcschr( &pItemImpl->cDriveString[2], '\\' );
1558 
1559             if ( lpFirstBkSlash && lpFirstBkSlash[1] )
1560             {
1561                 LPCWSTR lpLastBkSlash = wcschr( &lpFirstBkSlash[1], '\\' );
1562 
1563                 if ( lpLastBkSlash )
1564                     rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]), lpLastBkSlash - lpFirstBkSlash - 1 );
1565                 else
1566                     rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]) );
1567                 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1568             }
1569         }
1570         else switch ( GetDriveType( cRoot ) )
1571         {
1572             case DRIVE_REMOTE:
1573             {
1574                 TCHAR szBuffer[1024];
1575                 DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szBuffer);
1576                 DWORD dwBufsize = dwBufsizeConst;
1577 
1578                 DWORD dwResult = WNetGetConnection( cDrive, szBuffer, &dwBufsize );
1579                 if ( NO_ERROR == dwResult )
1580                 {
1581                     TCHAR szFileName[dwBufsizeConst + 16];
1582 
1583                     swprintf( szFileName, L"%s [%s]", cDrive, szBuffer );
1584                     rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) );
1585                 }
1586                 else
1587                     rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) );
1588             }
1589             pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1590             break;
1591             case DRIVE_FIXED:
1592             {
1593                 TCHAR szVolumeNameBuffer[1024];
1594                 DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szVolumeNameBuffer);
1595 
1596                 if ( GetVolumeInformation( cRoot, szVolumeNameBuffer, dwBufsizeConst, NULL, NULL, NULL, NULL, 0 ) )
1597                 {
1598                     TCHAR   szFileName[dwBufsizeConst + 16];
1599 
1600                     swprintf( szFileName, L"%s [%s]", cDrive, szVolumeNameBuffer );
1601                     rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) );
1602                 }
1603                 else
1604                     rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) );
1605             }
1606             pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1607             break;
1608             case DRIVE_CDROM:
1609             case DRIVE_REMOVABLE:
1610                 pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1611                 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cRoot) );
1612                 break;
1613             case DRIVE_UNKNOWN:
1614             default:
1615                 break;
1616         }
1617     }
1618 
1619     pStatus->eType = osl_File_Type_Volume;
1620     pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1621 
1622     if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1623     {
1624         rtl_uString *ustrSystemPath = NULL;
1625 
1626         rtl_uString_newFromStr( &ustrSystemPath, reinterpret_cast<const sal_Unicode*>(pItemImpl->cDriveString) );
1627         osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL );
1628         rtl_uString_release( ustrSystemPath );
1629         pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1630     }
1631     return osl_File_E_None;
1632 }
1633 
1634 //#####################################################
1635 static oslFileError SAL_CALL osl_getServerInfo(
1636     oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask )
1637 {
1638     DirectoryItem_Impl  *pItemImpl = (DirectoryItem_Impl *)Item;
1639     if ( !pItemImpl )
1640         return osl_File_E_INVAL;
1641 
1642     pStatus->uValidFields = 0;
1643 
1644     //  pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1645 
1646     //  if ( _tcscmp( pItemImpl->FindData.cFileName, TEXT(".") ) == 0 )
1647     //      rtl_uString_newFromAscii( &pStatus->ustrFileName, "/" );
1648     //  else
1649     //      rtl_uString_newFromStr( &pStatus->ustrFileName, pItemImpl->FindData.cFileName );
1650 
1651     pStatus->eType = osl_File_Type_Directory;
1652     pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1653 
1654     if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1655     {
1656         osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL );
1657         pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1658     }
1659     return osl_File_E_None;
1660 }
1661 
1662 //#############################################
1663 oslFileError SAL_CALL osl_getFileStatus(
1664     oslDirectoryItem Item,
1665     oslFileStatus *pStatus,
1666     sal_uInt32 uFieldMask )
1667 {
1668     DirectoryItem_Impl  *pItemImpl = (DirectoryItem_Impl *)Item;
1669 
1670     if ( !pItemImpl )
1671         return osl_File_E_INVAL;
1672 
1673     switch ( pItemImpl->uType  )
1674     {
1675     case DIRECTORYITEM_DRIVE:
1676         return osl_getDriveInfo( Item, pStatus, uFieldMask );
1677     case DIRECTORYITEM_SERVER:
1678         return osl_getServerInfo( Item, pStatus, uFieldMask );
1679     default:
1680         break;
1681     }
1682 
1683     if ( uFieldMask & osl_FileStatus_Mask_Validate )
1684     {
1685         HANDLE  hFind = FindFirstFile( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ), &pItemImpl->FindData );
1686 
1687         if ( hFind != INVALID_HANDLE_VALUE )
1688             FindClose( hFind );
1689         else
1690             return oslTranslateFileError( GetLastError() );
1691 
1692         uFieldMask &= ~ osl_FileStatus_Mask_Validate;
1693     }
1694 
1695     /* If no fields to retrieve left ignore pStatus */
1696     if ( !uFieldMask )
1697         return osl_File_E_None;
1698 
1699     /* Otherwise, this must be a valid pointer */
1700     if ( !pStatus )
1701         return osl_File_E_INVAL;
1702 
1703     if ( pStatus->uStructSize != sizeof(oslFileStatus) )
1704         return osl_File_E_INVAL;
1705 
1706     pStatus->uValidFields = 0;
1707 
1708     /* File time stamps */
1709 
1710     if ( (uFieldMask & osl_FileStatus_Mask_ModifyTime) &&
1711         FileTimeToTimeValue( &pItemImpl->FindData.ftLastWriteTime, &pStatus->aModifyTime ) )
1712         pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime;
1713 
1714     if ( (uFieldMask & osl_FileStatus_Mask_AccessTime) &&
1715         FileTimeToTimeValue( &pItemImpl->FindData.ftLastAccessTime, &pStatus->aAccessTime ) )
1716         pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime;
1717 
1718     if ( (uFieldMask & osl_FileStatus_Mask_CreationTime) &&
1719         FileTimeToTimeValue( &pItemImpl->FindData.ftCreationTime, &pStatus->aCreationTime ) )
1720         pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime;
1721 
1722     /* Most of the fields are already set, regardless of requiered fields */
1723 
1724     rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(pItemImpl->FindData.cFileName) );
1725     pStatus->uValidFields |= osl_FileStatus_Mask_FileName;
1726 
1727     if ((FILE_ATTRIBUTE_REPARSE_POINT & pItemImpl->FindData.dwFileAttributes) &&
1728         (IO_REPARSE_TAG_MOUNT_POINT == pItemImpl->FindData.dwReserved0))
1729         pStatus->eType = osl_File_Type_Volume;
1730     else if (pItemImpl->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1731         pStatus->eType = osl_File_Type_Directory;
1732     else
1733         pStatus->eType = osl_File_Type_Regular;
1734 
1735     pStatus->uValidFields |= osl_FileStatus_Mask_Type;
1736 
1737     pStatus->uAttributes = pItemImpl->FindData.dwFileAttributes;
1738     pStatus->uValidFields |= osl_FileStatus_Mask_Attributes;
1739 
1740     pStatus->uFileSize = (sal_uInt64)pItemImpl->FindData.nFileSizeLow + ((sal_uInt64)pItemImpl->FindData.nFileSizeHigh << 32);
1741     pStatus->uValidFields |= osl_FileStatus_Mask_FileSize;
1742 
1743     if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL )
1744     {
1745         osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrLinkTargetURL );
1746 
1747         pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL;
1748     }
1749 
1750     if ( uFieldMask & osl_FileStatus_Mask_FileURL )
1751     {
1752         if ( !pItemImpl->bFullPathNormalized )
1753         {
1754             sal_uInt32 nLen = rtl_uString_getLength( pItemImpl->m_pFullPath );
1755             ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
1756             sal_uInt32 nNewLen = GetCaseCorrectPathName( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ),
1757                                                       ::osl::mingw_reinterpret_cast<LPTSTR>( aBuffer ),
1758                                                       aBuffer.getBufSizeInSymbols(),
1759                                                       sal_True );
1760 
1761             if ( nNewLen )
1762             {
1763                 rtl_uString_newFromStr( &pItemImpl->m_pFullPath, aBuffer );
1764                 pItemImpl->bFullPathNormalized = TRUE;
1765             }
1766         }
1767 
1768         osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL );
1769         pStatus->uValidFields |= osl_FileStatus_Mask_FileURL;
1770     }
1771 
1772     return osl_File_E_None;
1773 }
1774 
1775 //#####################################################
1776 // file attributes handling functions
1777 //#####################################################
1778 
1779 //#############################################
1780 oslFileError SAL_CALL osl_setFileAttributes(
1781     rtl_uString *ustrFileURL,
1782     sal_uInt64 uAttributes )
1783 {
1784     oslFileError    error;
1785     rtl_uString     *ustrSysPath = NULL;
1786     DWORD           dwFileAttributes;
1787     BOOL            fSuccess;
1788 
1789     // Converts the normalized path into a systempath
1790     error = _osl_getSystemPathFromFileURL( ustrFileURL, &ustrSysPath, sal_False );
1791 
1792     if ( osl_File_E_None != error )
1793         return error;
1794 
1795     dwFileAttributes = GetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)) );
1796 
1797     if ( (DWORD)-1 != dwFileAttributes )
1798     {
1799         dwFileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
1800 
1801         if ( uAttributes & osl_File_Attribute_ReadOnly )
1802             dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1803 
1804         if ( uAttributes & osl_File_Attribute_Hidden )
1805             dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1806 
1807         fSuccess = SetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)), dwFileAttributes );
1808     }
1809     else
1810         fSuccess = FALSE;
1811 
1812     if ( !fSuccess )
1813         error = oslTranslateFileError( GetLastError() );
1814 
1815     rtl_uString_release( ustrSysPath );
1816 
1817     return error;
1818 }
1819 
1820 //#####################################################
1821 oslFileError SAL_CALL osl_setFileTime(
1822     rtl_uString *filePath,
1823     const TimeValue *aCreationTime,
1824     const TimeValue *aLastAccessTime,
1825     const TimeValue *aLastWriteTime)
1826 {
1827     oslFileError error;
1828     rtl_uString *sysPath=NULL;
1829     FILETIME *lpCreationTime=NULL;
1830     FILETIME *lpLastAccessTime=NULL;
1831     FILETIME *lpLastWriteTime=NULL;
1832     FILETIME ftCreationTime;
1833     FILETIME ftLastAccessTime;
1834     FILETIME ftLastWriteTime;
1835     HANDLE hFile;
1836     BOOL fSuccess;
1837 
1838 
1839     error=_osl_getSystemPathFromFileURL(filePath, &sysPath, sal_False);
1840 
1841     if (error==osl_File_E_INVAL)
1842         return error;
1843 
1844     hFile=CreateFileW(reinterpret_cast<LPCWSTR>(rtl_uString_getStr(sysPath)), GENERIC_WRITE, 0, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1845     rtl_uString_release(sysPath);
1846 
1847     if (hFile==INVALID_HANDLE_VALUE)
1848         return osl_File_E_NOENT;
1849 
1850     if (TimeValueToFileTime(aCreationTime, &ftCreationTime))
1851         lpCreationTime=&ftCreationTime;
1852 
1853     if (TimeValueToFileTime(aLastAccessTime, &ftLastAccessTime))
1854         lpLastAccessTime=&ftLastAccessTime;
1855 
1856     if (TimeValueToFileTime(aLastWriteTime, &ftLastWriteTime))
1857         lpLastWriteTime=&ftLastWriteTime;
1858 
1859     fSuccess=SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
1860 
1861     CloseHandle(hFile);
1862 
1863     if (!fSuccess)
1864         return osl_File_E_INVAL;
1865     else
1866         return osl_File_E_None;
1867 }
1868