xref: /aoo41x/main/sal/osl/w32/file_dirvol.cxx (revision cdf0e10c)
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