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