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