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 rtl_freeMemory(szFileMask); // #119939#, memory leak 436 } 437 } 438 439 return (HANDLE)pDirectory; 440 } 441 442 //##################################################### 443 BOOL WINAPI EnumDirectory(HANDLE hDirectory, LPWIN32_FIND_DATA pFindData) 444 { 445 BOOL fSuccess = FALSE; 446 LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory; 447 448 if ( pDirectory ) 449 { 450 BOOL fValid; 451 452 do 453 { 454 if ( pDirectory->aFirstData.cFileName[0] ) 455 { 456 *pFindData = pDirectory->aFirstData; 457 fSuccess = TRUE; 458 pDirectory->aFirstData.cFileName[0] = 0; 459 } 460 else if ( IsValidHandle( pDirectory->hFind ) ) 461 fSuccess = FindNextFile( pDirectory->hFind, pFindData ); 462 else 463 { 464 fSuccess = FALSE; 465 SetLastError( ERROR_NO_MORE_FILES ); 466 } 467 468 fValid = fSuccess && _tcscmp( TEXT("."), pFindData->cFileName ) != 0 && _tcscmp( TEXT(".."), pFindData->cFileName ) != 0; 469 470 } while( fSuccess && !fValid ); 471 } 472 else 473 SetLastError( ERROR_INVALID_HANDLE ); 474 475 return fSuccess; 476 } 477 478 //##################################################### 479 static BOOL WINAPI CloseDirectory(HANDLE hDirectory) 480 { 481 BOOL fSuccess = FALSE; 482 LPDIRECTORY pDirectory = (LPDIRECTORY)hDirectory; 483 484 if (pDirectory) 485 { 486 if (IsValidHandle(pDirectory->hFind)) 487 fSuccess = FindClose(pDirectory->hFind); 488 489 fSuccess = HeapFree(GetProcessHeap(), 0, pDirectory) && fSuccess; 490 } 491 else 492 SetLastError(ERROR_INVALID_HANDLE); 493 494 return fSuccess; 495 } 496 497 //##################################################### 498 static oslFileError osl_openLocalRoot( 499 rtl_uString *strDirectoryPath, oslDirectory *pDirectory) 500 { 501 rtl_uString *strSysPath = NULL; 502 oslFileError error; 503 504 if ( !pDirectory ) 505 return osl_File_E_INVAL; 506 507 *pDirectory = NULL; 508 509 error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysPath, sal_False ); 510 if ( osl_File_E_None == error ) 511 { 512 Directory_Impl *pDirImpl; 513 514 pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory( sizeof(Directory_Impl))); 515 ZeroMemory( pDirImpl, sizeof(Directory_Impl) ); 516 rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strSysPath ); 517 518 /* Append backslash if neccessary */ 519 520 /* @@@ToDo 521 use function ensure backslash 522 */ 523 sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath ); 524 if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' ) 525 { 526 rtl_uString* pCurDir = 0; 527 rtl_uString* pBackSlash = 0; 528 529 rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath ); 530 rtl_uString_newFromAscii( &pBackSlash, "\\" ); 531 rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash ); 532 rtl_uString_release( pBackSlash ); 533 rtl_uString_release( pCurDir ); 534 } 535 536 pDirImpl->uType = DIRECTORYTYPE_LOCALROOT; 537 pDirImpl->hEnumDrives = OpenLogicalDrivesEnum(); 538 539 /* @@@ToDo 540 Use IsValidHandle(...) 541 */ 542 if ( pDirImpl->hEnumDrives != INVALID_HANDLE_VALUE ) 543 { 544 *pDirectory = (oslDirectory)pDirImpl; 545 error = osl_File_E_None; 546 } 547 else 548 { 549 if ( pDirImpl ) 550 { 551 if ( pDirImpl->m_pDirectoryPath ) 552 { 553 rtl_uString_release( pDirImpl->m_pDirectoryPath ); 554 pDirImpl->m_pDirectoryPath = 0; 555 } 556 557 rtl_freeMemory(pDirImpl); 558 pDirImpl = 0; 559 } 560 561 error = oslTranslateFileError( GetLastError() ); 562 } 563 564 rtl_uString_release( strSysPath ); 565 } 566 return error; 567 } 568 569 //##################################################### 570 static oslFileError SAL_CALL osl_openFileDirectory( 571 rtl_uString *strDirectoryPath, oslDirectory *pDirectory) 572 { 573 oslFileError error = osl_File_E_None; 574 575 if ( !pDirectory ) 576 return osl_File_E_INVAL; 577 *pDirectory = NULL; 578 579 Directory_Impl *pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl))); 580 ZeroMemory( pDirImpl, sizeof(Directory_Impl) ); 581 rtl_uString_newFromString( &pDirImpl->m_pDirectoryPath, strDirectoryPath ); 582 583 /* Append backslash if neccessary */ 584 585 /* @@@ToDo 586 use function ensure backslash 587 */ 588 sal_uInt32 nLen = rtl_uString_getLength( pDirImpl->m_pDirectoryPath ); 589 if ( nLen && pDirImpl->m_pDirectoryPath->buffer[nLen - 1] != L'\\' ) 590 { 591 rtl_uString* pCurDir = 0; 592 rtl_uString* pBackSlash = 0; 593 594 rtl_uString_assign( &pCurDir, pDirImpl->m_pDirectoryPath ); 595 rtl_uString_newFromAscii( &pBackSlash, "\\" ); 596 rtl_uString_newConcat( &pDirImpl->m_pDirectoryPath, pCurDir, pBackSlash ); 597 rtl_uString_release( pBackSlash ); 598 rtl_uString_release( pCurDir ); 599 } 600 601 602 pDirImpl->uType = DIRECTORYTYPE_FILESYSTEM; 603 pDirImpl->hDirectory = OpenDirectory( pDirImpl->m_pDirectoryPath ); 604 605 if ( !pDirImpl->hDirectory ) 606 { 607 error = oslTranslateFileError( GetLastError() ); 608 609 if ( pDirImpl->m_pDirectoryPath ) 610 { 611 rtl_uString_release( pDirImpl->m_pDirectoryPath ); 612 pDirImpl->m_pDirectoryPath = 0; 613 } 614 615 rtl_freeMemory(pDirImpl), pDirImpl = 0; 616 } 617 618 *pDirectory = (oslDirectory)(pDirImpl); 619 return error; 620 } 621 622 //##################################################### 623 static oslFileError SAL_CALL osl_openNetworkServer( 624 rtl_uString *strSysDirPath, oslDirectory *pDirectory) 625 { 626 NETRESOURCEW aNetResource; 627 HANDLE hEnum; 628 DWORD dwError; 629 630 ZeroMemory( &aNetResource, sizeof(aNetResource) ); 631 632 aNetResource.lpRemoteName = reinterpret_cast<LPWSTR>(strSysDirPath->buffer); 633 634 dwError = WNetOpenEnumW( 635 RESOURCE_GLOBALNET, 636 RESOURCETYPE_DISK, 637 RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER, 638 &aNetResource, 639 &hEnum ); 640 641 if ( ERROR_SUCCESS == dwError ) 642 { 643 Directory_Impl *pDirImpl; 644 645 pDirImpl = reinterpret_cast<Directory_Impl*>(rtl_allocateMemory(sizeof(Directory_Impl))); 646 ZeroMemory( pDirImpl, sizeof(Directory_Impl) ); 647 pDirImpl->uType = DIRECTORYTYPE_NETROOT; 648 pDirImpl->hDirectory = hEnum; 649 *pDirectory = (oslDirectory)pDirImpl; 650 } 651 return oslTranslateFileError( dwError ); 652 } 653 654 //############################################# 655 static DWORD create_dir_with_callback( 656 rtl_uString * dir_path, 657 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, 658 void* pData) 659 { 660 // Create the specified directory and call the 661 // user specified callback function. On success 662 // the function returns ERROR_SUCCESS else a Win32 error code. 663 664 BOOL bCreated = FALSE; 665 666 bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( dir_path )), NULL ); 667 668 if ( bCreated ) 669 { 670 if (aDirectoryCreationCallbackFunc) 671 { 672 rtl::OUString url; 673 _osl_getFileURLFromSystemPath(dir_path, &(url.pData)); 674 aDirectoryCreationCallbackFunc(pData, url.pData); 675 } 676 return ERROR_SUCCESS; 677 } 678 return GetLastError(); 679 } 680 681 //############################################# 682 static int path_make_parent(sal_Unicode* path) 683 { 684 /* Cut off the last part of the given path to 685 get the parent only, e.g. 'c:\dir\subdir' -> 686 'c:\dir' or '\\share\sub\dir' -> '\\share\sub' 687 @return The position where the path has been cut 688 off (this is the posistion of the last backslash). 689 If there are no more parents 0 will be returned, 690 e.g. 'c:\' or '\\Share' have no more parents */ 691 692 OSL_PRECOND(rtl_ustr_indexOfChar(path, SLASH) == -1, "Path must not contain slashes"); 693 OSL_PRECOND(has_path_parent(path), "Path must have a parent"); 694 695 sal_Unicode* pos_last_backslash = path + rtl_ustr_lastIndexOfChar(path, BACKSLASH); 696 *pos_last_backslash = 0; 697 return (pos_last_backslash - path); 698 } 699 700 //############################################# 701 static DWORD create_dir_recursively_( 702 rtl_uString * dir_path, 703 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, 704 void* pData) 705 { 706 OSL_PRECOND( 707 rtl_ustr_lastIndexOfChar_WithLength(dir_path->buffer, dir_path->length, BACKSLASH) != dir_path->length, 708 "Path must not end with a backslash"); 709 710 DWORD w32_error = create_dir_with_callback( 711 dir_path, aDirectoryCreationCallbackFunc, pData); 712 if (w32_error == ERROR_SUCCESS) 713 return ERROR_SUCCESS; 714 715 if ((w32_error != ERROR_PATH_NOT_FOUND) || !has_path_parent(dir_path->buffer)) 716 return w32_error; 717 718 int pos = path_make_parent(dir_path->buffer); // dir_path->buffer[pos] = 0, restore below 719 720 w32_error = create_dir_recursively_( 721 dir_path, aDirectoryCreationCallbackFunc, pData); 722 723 dir_path->buffer[pos] = BACKSLASH; // restore 724 725 if (ERROR_SUCCESS != w32_error) 726 return w32_error; 727 728 return create_dir_recursively_(dir_path, aDirectoryCreationCallbackFunc, pData); 729 } 730 731 //############################################# 732 oslFileError SAL_CALL osl_createDirectoryPath( 733 rtl_uString* aDirectoryUrl, 734 oslDirectoryCreationCallbackFunc aDirectoryCreationCallbackFunc, 735 void* pData) 736 { 737 if (aDirectoryUrl == NULL) 738 return osl_File_E_INVAL; 739 740 rtl::OUString sys_path; 741 oslFileError osl_error = 742 _osl_getSystemPathFromFileURL(aDirectoryUrl, &sys_path.pData, sal_False); 743 744 if (osl_error != osl_File_E_None) 745 return osl_error; 746 747 osl::systemPathRemoveSeparator(sys_path); 748 749 // const_cast because sys_path is a local copy 750 // which we want to modify inplace instead of 751 // coyp it into another buffer on the heap again 752 return oslTranslateFileError(create_dir_recursively_( 753 sys_path.pData, aDirectoryCreationCallbackFunc, pData)); 754 } 755 756 //##################################################### 757 oslFileError SAL_CALL osl_createDirectory(rtl_uString* strPath) 758 { 759 rtl_uString *strSysPath = NULL; 760 oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); 761 762 if ( osl_File_E_None == error ) 763 { 764 BOOL bCreated = FALSE; 765 766 bCreated = CreateDirectoryW( reinterpret_cast<LPCWSTR>(rtl_uString_getStr( strSysPath )), NULL ); 767 768 if ( !bCreated ) 769 { 770 /*@@@ToDo 771 The following case is a hack because the ucb or the webtop had some 772 problems with the error code that CreateDirectory returns in 773 case the path is only a logical drive, should be removed! 774 */ 775 776 const sal_Unicode *pBuffer = rtl_uString_getStr( strSysPath ); 777 sal_Int32 nLen = rtl_uString_getLength( strSysPath ); 778 779 if ( 780 ( ( pBuffer[0] >= 'A' && pBuffer[0] <= 'Z' ) || 781 ( pBuffer[0] >= 'a' && pBuffer[0] <= 'z' ) ) && 782 pBuffer[1] == ':' && ( nLen ==2 || ( nLen == 3 && pBuffer[2] == '\\' ) ) 783 ) 784 SetLastError( ERROR_ALREADY_EXISTS ); 785 786 error = oslTranslateFileError( GetLastError() ); 787 } 788 789 rtl_uString_release( strSysPath ); 790 } 791 return error; 792 } 793 794 //##################################################### 795 oslFileError SAL_CALL osl_removeDirectory(rtl_uString* strPath) 796 { 797 rtl_uString *strSysPath = NULL; 798 oslFileError error = _osl_getSystemPathFromFileURL( strPath, &strSysPath, sal_False ); 799 800 if ( osl_File_E_None == error ) 801 { 802 if ( RemoveDirectory( reinterpret_cast<LPCTSTR>(rtl_uString_getStr( strSysPath )) ) ) 803 error = osl_File_E_None; 804 else 805 error = oslTranslateFileError( GetLastError() ); 806 807 rtl_uString_release( strSysPath ); 808 } 809 return error; 810 } 811 812 //##################################################### 813 oslFileError SAL_CALL osl_openDirectory(rtl_uString *strDirectoryPath, oslDirectory *pDirectory) 814 { 815 oslFileError error; 816 817 if ( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase( strDirectoryPath->buffer, "file:///" ) ) 818 error = osl_openLocalRoot( strDirectoryPath, pDirectory ); 819 else 820 { 821 rtl_uString *strSysDirectoryPath = NULL; 822 DWORD dwPathType; 823 824 error = _osl_getSystemPathFromFileURL( strDirectoryPath, &strSysDirectoryPath, sal_False ); 825 826 if ( osl_File_E_None != error ) 827 return error; 828 829 dwPathType = IsValidFilePath( strSysDirectoryPath, NULL, VALIDATEPATH_NORMAL, NULL ); 830 831 if ( dwPathType & PATHTYPE_IS_SERVER ) 832 { 833 error = osl_openNetworkServer( strSysDirectoryPath, pDirectory ); 834 } 835 else 836 error = osl_openFileDirectory( strSysDirectoryPath, pDirectory ); 837 838 rtl_uString_release( strSysDirectoryPath ); 839 } 840 return error; 841 } 842 843 //##################################################### 844 static oslFileError SAL_CALL osl_getNextNetResource( 845 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint ) 846 { 847 Directory_Impl *pDirImpl = (Directory_Impl *)Directory; 848 DirectoryItem_Impl *pItemImpl = NULL; 849 BYTE buffer[16384]; 850 LPNETRESOURCEW lpNetResource = (LPNETRESOURCEW)buffer; 851 DWORD dwError, dwCount, dwBufSize; 852 853 uHint = uHint; /* to get no warning */ 854 855 if ( !pItem ) 856 return osl_File_E_INVAL; 857 *pItem = NULL; 858 859 if ( !pDirImpl ) 860 return osl_File_E_INVAL; 861 862 dwCount = 1; 863 dwBufSize = sizeof(buffer); 864 dwError = WNetEnumResource( pDirImpl->hDirectory, &dwCount, lpNetResource, &dwBufSize ); 865 866 switch ( dwError ) 867 { 868 case NO_ERROR: 869 case ERROR_MORE_DATA: 870 { 871 pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); 872 if ( !pItemImpl ) 873 return osl_File_E_NOMEM; 874 875 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); 876 pItemImpl->uType = DIRECTORYITEM_DRIVE; 877 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); 878 879 wcscpy( pItemImpl->cDriveString, lpNetResource->lpRemoteName ); 880 881 *pItem = pItemImpl; 882 } 883 return osl_File_E_None; 884 case ERROR_NO_MORE_ITEMS: 885 return osl_File_E_NOENT; 886 default: 887 return oslTranslateFileError( dwError ); 888 } 889 } 890 891 //##################################################### 892 static oslFileError SAL_CALL osl_getNextDrive( 893 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint ) 894 { 895 Directory_Impl *pDirImpl = (Directory_Impl *)Directory; 896 DirectoryItem_Impl *pItemImpl = NULL; 897 BOOL fSuccess; 898 899 uHint = uHint; /* avoid warnings */ 900 901 if ( !pItem ) 902 return osl_File_E_INVAL; 903 *pItem = NULL; 904 905 if ( !pDirImpl ) 906 return osl_File_E_INVAL; 907 908 pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); 909 if ( !pItemImpl ) 910 return osl_File_E_NOMEM; 911 912 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); 913 pItemImpl->uType = DIRECTORYITEM_DRIVE; 914 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); 915 fSuccess = EnumLogicalDrives( pDirImpl->hEnumDrives, pItemImpl->cDriveString ); 916 917 if ( fSuccess ) 918 { 919 *pItem = pItemImpl; 920 return osl_File_E_None; 921 } 922 else 923 { 924 if ( pItemImpl->m_pFullPath ) 925 { 926 rtl_uString_release( pItemImpl->m_pFullPath ); 927 pItemImpl->m_pFullPath = 0; 928 } 929 930 rtl_freeMemory( pItemImpl ); 931 return oslTranslateFileError( GetLastError() ); 932 } 933 } 934 935 //##################################################### 936 static oslFileError SAL_CALL osl_getNextFileItem( 937 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint) 938 { 939 Directory_Impl *pDirImpl = (Directory_Impl *)Directory; 940 DirectoryItem_Impl *pItemImpl = NULL; 941 BOOL fFound; 942 943 uHint = uHint; /* avoid warnings */ 944 945 if ( !pItem ) 946 return osl_File_E_INVAL; 947 *pItem = NULL; 948 949 if ( !pDirImpl ) 950 return osl_File_E_INVAL; 951 952 pItemImpl = reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); 953 if ( !pItemImpl ) 954 return osl_File_E_NOMEM; 955 956 memset( pItemImpl, 0, sizeof(DirectoryItem_Impl) ); 957 fFound = EnumDirectory( pDirImpl->hDirectory, &pItemImpl->FindData ); 958 959 if ( fFound ) 960 { 961 pItemImpl->uType = DIRECTORYITEM_FILE; 962 pItemImpl->nRefCount = 1; 963 964 rtl_uString* pTmpFileName = 0; 965 rtl_uString_newFromStr( &pTmpFileName, reinterpret_cast<const sal_Unicode *>(pItemImpl->FindData.cFileName) ); 966 rtl_uString_newConcat( &pItemImpl->m_pFullPath, pDirImpl->m_pDirectoryPath, pTmpFileName ); 967 rtl_uString_release( pTmpFileName ); 968 969 pItemImpl->bFullPathNormalized = FALSE; 970 *pItem = (oslDirectoryItem)pItemImpl; 971 return osl_File_E_None; 972 } 973 else 974 { 975 if ( pItemImpl->m_pFullPath ) 976 { 977 rtl_uString_release( pItemImpl->m_pFullPath ); 978 pItemImpl->m_pFullPath = 0; 979 } 980 981 rtl_freeMemory( pItemImpl ); 982 return oslTranslateFileError( GetLastError() ); 983 } 984 } 985 986 //##################################################### 987 oslFileError SAL_CALL osl_getNextDirectoryItem( 988 oslDirectory Directory, oslDirectoryItem *pItem, sal_uInt32 uHint) 989 { 990 Directory_Impl *pDirImpl = (Directory_Impl *)Directory; 991 992 /* Assume failure */ 993 994 if ( !pItem ) 995 return osl_File_E_INVAL; 996 *pItem = NULL; 997 998 if ( !pDirImpl ) 999 return osl_File_E_INVAL; 1000 1001 switch ( pDirImpl->uType ) 1002 { 1003 case DIRECTORYTYPE_LOCALROOT: 1004 return osl_getNextDrive( Directory, pItem, uHint ); 1005 case DIRECTORYTYPE_NETROOT: 1006 return osl_getNextNetResource( Directory, pItem, uHint ); 1007 case DIRECTORYTYPE_FILESYSTEM: 1008 return osl_getNextFileItem( Directory, pItem, uHint ); 1009 default: 1010 return osl_File_E_INVAL; 1011 } 1012 } 1013 1014 //##################################################### 1015 oslFileError SAL_CALL osl_closeDirectory(oslDirectory Directory) 1016 { 1017 Directory_Impl *pDirImpl = (Directory_Impl *)Directory; 1018 oslFileError eError = osl_File_E_INVAL; 1019 1020 if ( pDirImpl ) 1021 { 1022 switch ( pDirImpl->uType ) 1023 { 1024 case DIRECTORYTYPE_FILESYSTEM: 1025 eError = CloseDirectory( pDirImpl->hDirectory ) ? osl_File_E_None : oslTranslateFileError( GetLastError() ); 1026 break; 1027 case DIRECTORYTYPE_LOCALROOT: 1028 eError = CloseLogicalDrivesEnum( pDirImpl->hEnumDrives ) ? osl_File_E_None : oslTranslateFileError( GetLastError() ); 1029 break; 1030 case DIRECTORYTYPE_NETROOT: 1031 { 1032 DWORD err = WNetCloseEnum(pDirImpl->hDirectory); 1033 eError = (err == NO_ERROR) ? osl_File_E_None : oslTranslateFileError(err); 1034 } 1035 break; 1036 default: 1037 OSL_ENSURE( 0, "Invalid directory type" ); 1038 break; 1039 } 1040 1041 if ( pDirImpl->m_pDirectoryPath ) 1042 { 1043 rtl_uString_release( pDirImpl->m_pDirectoryPath ); 1044 pDirImpl->m_pDirectoryPath = 0; 1045 } 1046 1047 rtl_freeMemory(pDirImpl); 1048 } 1049 return eError; 1050 } 1051 1052 //##################################################### 1053 /* Different types of paths */ 1054 typedef enum _PATHTYPE 1055 { 1056 PATHTYPE_SYNTAXERROR = 0, 1057 PATHTYPE_NETROOT, 1058 PATHTYPE_NETSERVER, 1059 PATHTYPE_VOLUME, 1060 PATHTYPE_FILE 1061 } PATHTYPE; 1062 1063 oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString *strFilePath, oslDirectoryItem *pItem) 1064 { 1065 oslFileError error = osl_File_E_None; 1066 rtl_uString* strSysFilePath = NULL; 1067 PATHTYPE type = PATHTYPE_FILE; 1068 DWORD dwPathType; 1069 1070 /* Assume failure */ 1071 1072 if ( !pItem ) 1073 return osl_File_E_INVAL; 1074 1075 *pItem = NULL; 1076 1077 1078 error = _osl_getSystemPathFromFileURL( strFilePath, &strSysFilePath, sal_False ); 1079 1080 if ( osl_File_E_None != error ) 1081 return error; 1082 1083 dwPathType = IsValidFilePath( strSysFilePath, NULL, VALIDATEPATH_NORMAL, NULL ); 1084 1085 if ( dwPathType & PATHTYPE_IS_VOLUME ) 1086 type = PATHTYPE_VOLUME; 1087 else if ( dwPathType & PATHTYPE_IS_SERVER ) 1088 type = PATHTYPE_NETSERVER; 1089 else 1090 type = PATHTYPE_FILE; 1091 1092 switch ( type ) 1093 { 1094 case PATHTYPE_NETSERVER: 1095 { 1096 DirectoryItem_Impl* pItemImpl = 1097 reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); 1098 1099 if ( !pItemImpl ) 1100 error = osl_File_E_NOMEM; 1101 1102 if ( osl_File_E_None == error ) 1103 { 1104 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); 1105 pItemImpl->uType = DIRECTORYITEM_SERVER; 1106 1107 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); 1108 rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath ); 1109 1110 // Assign a title anyway 1111 { 1112 int iSrc = 2; 1113 int iDst = 0; 1114 1115 while( iSrc < strSysFilePath->length && strSysFilePath->buffer[iSrc] && strSysFilePath->buffer[iSrc] != '\\' ) 1116 { 1117 pItemImpl->FindData.cFileName[iDst++] = strSysFilePath->buffer[iSrc++]; 1118 } 1119 } 1120 1121 *pItem = pItemImpl; 1122 } 1123 } 1124 break; 1125 case PATHTYPE_VOLUME: 1126 { 1127 DirectoryItem_Impl* pItemImpl = 1128 reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); 1129 1130 if ( !pItemImpl ) 1131 error = osl_File_E_NOMEM; 1132 1133 if ( osl_File_E_None == error ) 1134 { 1135 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); 1136 pItemImpl->uType = DIRECTORYITEM_DRIVE; 1137 1138 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); 1139 1140 _tcscpy( pItemImpl->cDriveString, reinterpret_cast<LPCTSTR>(strSysFilePath->buffer) ); 1141 pItemImpl->cDriveString[0] = _toupper( pItemImpl->cDriveString[0] ); 1142 1143 if ( pItemImpl->cDriveString[_tcslen(pItemImpl->cDriveString) - 1] != '\\' ) 1144 _tcscat( pItemImpl->cDriveString, TEXT( "\\" ) ); 1145 1146 *pItem = pItemImpl; 1147 } 1148 } 1149 break; 1150 case PATHTYPE_SYNTAXERROR: 1151 case PATHTYPE_NETROOT: 1152 case PATHTYPE_FILE: 1153 { 1154 HANDLE hFind; 1155 WIN32_FIND_DATA aFindData; 1156 1157 if ( strSysFilePath->length > 0 && strSysFilePath->buffer[strSysFilePath->length - 1] == '\\' ) 1158 rtl_uString_newFromStr_WithLength( &strSysFilePath, strSysFilePath->buffer, strSysFilePath->length - 1 ); 1159 1160 hFind = FindFirstFile( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(strSysFilePath)), &aFindData ); 1161 1162 if ( hFind != INVALID_HANDLE_VALUE ) 1163 { 1164 DirectoryItem_Impl *pItemImpl = 1165 reinterpret_cast<DirectoryItem_Impl*>(rtl_allocateMemory(sizeof(DirectoryItem_Impl))); 1166 1167 ZeroMemory( pItemImpl, sizeof(DirectoryItem_Impl) ); 1168 osl_acquireDirectoryItem( (oslDirectoryItem)pItemImpl ); 1169 1170 CopyMemory( &pItemImpl->FindData, &aFindData, sizeof(WIN32_FIND_DATA) ); 1171 rtl_uString_newFromString( &pItemImpl->m_pFullPath, strSysFilePath ); 1172 1173 // MT: This costs 600ms startup time on fast v60x! 1174 // GetCaseCorrectPathName( pItemImpl->szFullPath, pItemImpl->szFullPath, sizeof(pItemImpl->szFullPath) ); 1175 1176 pItemImpl->uType = DIRECTORYITEM_FILE; 1177 *pItem = pItemImpl; 1178 FindClose( hFind ); 1179 } 1180 else 1181 error = oslTranslateFileError( GetLastError() ); 1182 } 1183 break; 1184 } 1185 1186 if ( strSysFilePath ) 1187 rtl_uString_release( strSysFilePath ); 1188 1189 return error; 1190 } 1191 1192 //##################################################### 1193 oslFileError SAL_CALL osl_acquireDirectoryItem( oslDirectoryItem Item ) 1194 { 1195 DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; 1196 1197 if ( !pItemImpl ) 1198 return osl_File_E_INVAL; 1199 1200 pItemImpl->nRefCount++; 1201 return osl_File_E_None; 1202 } 1203 1204 //##################################################### 1205 oslFileError SAL_CALL osl_releaseDirectoryItem( oslDirectoryItem Item ) 1206 { 1207 DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; 1208 1209 if ( !pItemImpl ) 1210 return osl_File_E_INVAL; 1211 1212 if ( ! --pItemImpl->nRefCount ) 1213 { 1214 if ( pItemImpl->m_pFullPath ) 1215 { 1216 rtl_uString_release( pItemImpl->m_pFullPath ); 1217 pItemImpl->m_pFullPath = 0; 1218 } 1219 1220 rtl_freeMemory( pItemImpl ); 1221 } 1222 1223 return osl_File_E_None; 1224 } 1225 1226 //##################################################### 1227 // volume / file info handling functions 1228 //##################################################### 1229 1230 //##################################################### 1231 static inline bool is_floppy_A_present() 1232 { return (GetLogicalDrives() & 1); } 1233 1234 //##################################################### 1235 static inline bool is_floppy_B_present() 1236 { return (GetLogicalDrives() & 2); } 1237 1238 //##################################################### 1239 bool is_floppy_volume_mount_point(const rtl::OUString& path) 1240 { 1241 // determines if a volume mount point shows to a floppy 1242 // disk by comparing the unique volume names 1243 static const LPCWSTR FLOPPY_A = L"A:\\"; 1244 static const LPCWSTR FLOPPY_B = L"B:\\"; 1245 1246 rtl::OUString p(path); 1247 osl::systemPathEnsureSeparator(p); 1248 1249 TCHAR vn[51]; 1250 if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn))) 1251 { 1252 TCHAR vnfloppy[51]; 1253 if (is_floppy_A_present() && 1254 GetVolumeNameForVolumeMountPoint(FLOPPY_A, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) && 1255 (0 == wcscmp(vn, vnfloppy))) 1256 return true; 1257 1258 if (is_floppy_B_present() && 1259 GetVolumeNameForVolumeMountPoint(FLOPPY_B, vnfloppy, ELEMENTS_OF_ARRAY(vnfloppy)) && 1260 (0 == wcscmp(vn, vnfloppy))) 1261 return true; 1262 } 1263 return false; 1264 } 1265 1266 //################################################ 1267 static bool is_floppy_drive(const rtl::OUString& path) 1268 { 1269 static const LPCWSTR FLOPPY_DRV_LETTERS = TEXT("AaBb"); 1270 1271 // we must take into account that even a floppy 1272 // drive may be mounted to a directory so checking 1273 // for the drive letter alone is not sufficient 1274 // we must compare the unique volume name with 1275 // that of the available floppy disks 1276 1277 const sal_Unicode* pszPath = path.getStr(); 1278 return ((wcschr(FLOPPY_DRV_LETTERS, pszPath[0]) && (L':' == pszPath[1])) || is_floppy_volume_mount_point(path)); 1279 } 1280 1281 //##################################################### 1282 static bool is_volume_mount_point(const rtl::OUString& path) 1283 { 1284 rtl::OUString p(path); 1285 osl::systemPathRemoveSeparator(p); 1286 1287 bool is_volume_root = false; 1288 1289 if (!is_floppy_drive(p)) 1290 { 1291 DWORD fattr = GetFileAttributes(reinterpret_cast<LPCTSTR>(p.getStr())); 1292 1293 if ((INVALID_FILE_ATTRIBUTES != fattr) && 1294 (FILE_ATTRIBUTE_REPARSE_POINT & fattr)) 1295 { 1296 WIN32_FIND_DATA find_data; 1297 HANDLE h_find = FindFirstFile(reinterpret_cast<LPCTSTR>(p.getStr()), &find_data); 1298 1299 if (IsValidHandle(h_find) && 1300 (FILE_ATTRIBUTE_REPARSE_POINT & find_data.dwFileAttributes) && 1301 (IO_REPARSE_TAG_MOUNT_POINT == find_data.dwReserved0)) 1302 { 1303 is_volume_root = true; 1304 } 1305 if (IsValidHandle(h_find)) 1306 FindClose(h_find); 1307 } 1308 } 1309 return is_volume_root; 1310 } 1311 1312 //############################################# 1313 static UINT get_volume_mount_point_drive_type(const rtl::OUString& path) 1314 { 1315 if (0 == path.getLength()) 1316 return GetDriveType(NULL); 1317 1318 rtl::OUString p(path); 1319 osl::systemPathEnsureSeparator(p); 1320 1321 TCHAR vn[51]; 1322 if (GetVolumeNameForVolumeMountPoint(reinterpret_cast<LPCTSTR>(p.getStr()), vn, ELEMENTS_OF_ARRAY(vn))) 1323 return GetDriveType(vn); 1324 1325 return DRIVE_NO_ROOT_DIR; 1326 } 1327 1328 //############################################# 1329 static inline bool is_drivetype_request(sal_uInt32 field_mask) 1330 { 1331 return (field_mask & osl_VolumeInfo_Mask_Attributes); 1332 } 1333 1334 //############################################# 1335 static oslFileError osl_get_drive_type( 1336 const rtl::OUString& path, oslVolumeInfo* pInfo) 1337 { 1338 // GetDriveType fails on empty volume mount points 1339 // see Knowledge Base Q244089 1340 UINT drive_type; 1341 if (is_volume_mount_point(path)) 1342 drive_type = get_volume_mount_point_drive_type(path); 1343 else 1344 drive_type = GetDriveType(reinterpret_cast<LPCTSTR>(path.getStr())); 1345 1346 if (DRIVE_NO_ROOT_DIR == drive_type) 1347 return oslTranslateFileError(ERROR_INVALID_DRIVE); 1348 1349 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; 1350 1351 switch (drive_type) 1352 { 1353 case DRIVE_CDROM: 1354 pInfo->uAttributes |= osl_Volume_Attribute_CompactDisc | osl_Volume_Attribute_Removeable; 1355 break; 1356 case DRIVE_REMOVABLE: 1357 pInfo->uAttributes |= osl_Volume_Attribute_Removeable; 1358 if (is_floppy_drive(path)) 1359 pInfo->uAttributes |= osl_Volume_Attribute_FloppyDisk; 1360 break; 1361 case DRIVE_FIXED: 1362 pInfo->uAttributes |= osl_Volume_Attribute_FixedDisk; 1363 break; 1364 case DRIVE_RAMDISK: 1365 pInfo->uAttributes |= osl_Volume_Attribute_RAMDisk; 1366 break; 1367 case DRIVE_REMOTE: 1368 pInfo->uAttributes |= osl_Volume_Attribute_Remote; 1369 break; 1370 case DRIVE_UNKNOWN: 1371 pInfo->uAttributes = 0; 1372 break; 1373 default: 1374 pInfo->uValidFields &= ~osl_VolumeInfo_Mask_Attributes; 1375 pInfo->uAttributes = 0; 1376 break; 1377 } 1378 return osl_File_E_None; 1379 } 1380 1381 //############################################# 1382 static inline bool is_volume_space_info_request(sal_uInt32 field_mask) 1383 { 1384 return (field_mask & 1385 (osl_VolumeInfo_Mask_TotalSpace | 1386 osl_VolumeInfo_Mask_UsedSpace | 1387 osl_VolumeInfo_Mask_FreeSpace)); 1388 } 1389 1390 //############################################# 1391 static void get_volume_space_information( 1392 const rtl::OUString& path, oslVolumeInfo *pInfo) 1393 { 1394 BOOL ret = GetDiskFreeSpaceEx( 1395 reinterpret_cast<LPCTSTR>(path.getStr()), 1396 (PULARGE_INTEGER)&(pInfo->uFreeSpace), 1397 (PULARGE_INTEGER)&(pInfo->uTotalSpace), 1398 NULL); 1399 1400 if (ret) 1401 { 1402 pInfo->uUsedSpace = pInfo->uTotalSpace - pInfo->uFreeSpace; 1403 pInfo->uValidFields |= osl_VolumeInfo_Mask_TotalSpace | 1404 osl_VolumeInfo_Mask_UsedSpace | 1405 osl_VolumeInfo_Mask_FreeSpace; 1406 } 1407 } 1408 1409 //############################################# 1410 static inline bool is_filesystem_attributes_request(sal_uInt32 field_mask) 1411 { 1412 return (field_mask & 1413 (osl_VolumeInfo_Mask_MaxNameLength | 1414 osl_VolumeInfo_Mask_MaxPathLength | 1415 osl_VolumeInfo_Mask_FileSystemName | 1416 osl_VolumeInfo_Mask_FileSystemCaseHandling)); 1417 } 1418 1419 //############################################# 1420 static oslFileError get_filesystem_attributes( 1421 const rtl::OUString& path, sal_uInt32 field_mask, oslVolumeInfo* pInfo) 1422 { 1423 pInfo->uAttributes = 0; 1424 1425 // osl_get_drive_type must be called first because 1426 // this function resets osl_VolumeInfo_Mask_Attributes 1427 // on failure 1428 if (is_drivetype_request(field_mask)) 1429 { 1430 oslFileError osl_error = osl_get_drive_type(path, pInfo); 1431 if (osl_File_E_None != osl_error) 1432 return osl_error; 1433 } 1434 if (is_filesystem_attributes_request(field_mask)) 1435 { 1436 /* the following two parameters can not be longer than MAX_PATH+1 */ 1437 WCHAR vn[MAX_PATH+1]; 1438 WCHAR fsn[MAX_PATH+1]; 1439 1440 DWORD serial; 1441 DWORD mcl; 1442 DWORD flags; 1443 1444 LPCTSTR pszPath = reinterpret_cast<LPCTSTR>(path.getStr()); 1445 if (GetVolumeInformation(pszPath, vn, MAX_PATH+1, &serial, &mcl, &flags, fsn, MAX_PATH+1)) 1446 { 1447 // Currently sal does not use this value, instead MAX_PATH is used 1448 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxNameLength; 1449 pInfo->uMaxNameLength = mcl; 1450 1451 // Should the uMaxPathLength be set to 32767, "\\?\" prefix allowes it 1452 pInfo->uValidFields |= osl_VolumeInfo_Mask_MaxPathLength; 1453 pInfo->uMaxPathLength = MAX_PATH; 1454 1455 pInfo->uValidFields |= osl_VolumeInfo_Mask_FileSystemName; 1456 rtl_uString_newFromStr(&pInfo->ustrFileSystemName, reinterpret_cast<const sal_Unicode*>(fsn)); 1457 1458 // volumes (even NTFS) will always be considered case 1459 // insensitive because the Win32 API is not able to 1460 // deal with case sensitive volumes see M$ Knowledge Base 1461 // article 100625 that's why we never set the attribute 1462 // osl_Volume_Attribute_Case_Sensitive 1463 1464 if (flags & FS_CASE_IS_PRESERVED) 1465 pInfo->uAttributes |= osl_Volume_Attribute_Case_Is_Preserved; 1466 1467 pInfo->uValidFields |= osl_VolumeInfo_Mask_Attributes; 1468 } 1469 } 1470 return osl_File_E_None; 1471 } 1472 1473 //##################################################### 1474 static bool path_get_parent(rtl::OUString& path) 1475 { 1476 OSL_PRECOND(path.lastIndexOf(SLASH) == -1, "Path must not have slashes"); 1477 1478 if (!has_path_parent(path)) 1479 { 1480 sal_Int32 i = path.lastIndexOf(BACKSLASH); 1481 if (-1 < i) 1482 { 1483 path = rtl::OUString(path.getStr(), i); 1484 return true; 1485 } 1486 } 1487 return false; 1488 } 1489 1490 //##################################################### 1491 static void path_travel_to_volume_root(const rtl::OUString& system_path, rtl::OUString& volume_root) 1492 { 1493 rtl::OUString sys_path(system_path); 1494 1495 while(!is_volume_mount_point(sys_path) && path_get_parent(sys_path)) 1496 /**/; 1497 1498 volume_root = sys_path; 1499 osl::systemPathEnsureSeparator(volume_root); 1500 } 1501 1502 //############################################# 1503 oslFileError SAL_CALL osl_getVolumeInformation( 1504 rtl_uString *ustrURL, oslVolumeInfo *pInfo, sal_uInt32 uFieldMask ) 1505 { 1506 if (!pInfo) 1507 return osl_File_E_INVAL; 1508 1509 rtl::OUString system_path; 1510 oslFileError error = _osl_getSystemPathFromFileURL(ustrURL, &system_path.pData, sal_False); 1511 1512 if (osl_File_E_None != error) 1513 return error; 1514 1515 rtl::OUString volume_root; 1516 path_travel_to_volume_root(system_path, volume_root); 1517 1518 pInfo->uValidFields = 0; 1519 1520 if ((error = get_filesystem_attributes(volume_root, uFieldMask, pInfo)) != osl_File_E_None) 1521 return error; 1522 1523 if (is_volume_space_info_request(uFieldMask)) 1524 get_volume_space_information(volume_root, pInfo); 1525 1526 if (uFieldMask & osl_VolumeInfo_Mask_DeviceHandle) 1527 { 1528 pInfo->uValidFields |= osl_VolumeInfo_Mask_DeviceHandle; 1529 osl_getFileURLFromSystemPath(volume_root.pData, (rtl_uString**)&pInfo->pDeviceHandle); 1530 } 1531 1532 return osl_File_E_None; 1533 } 1534 1535 //##################################################### 1536 static oslFileError SAL_CALL osl_getDriveInfo( 1537 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask) 1538 { 1539 DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; 1540 TCHAR cDrive[3] = TEXT("A:"); 1541 TCHAR cRoot[4] = TEXT("A:\\"); 1542 1543 if ( !pItemImpl ) 1544 return osl_File_E_INVAL; 1545 1546 pStatus->uValidFields = 0; 1547 1548 cDrive[0] = pItemImpl->cDriveString[0]; 1549 cRoot[0] = pItemImpl->cDriveString[0]; 1550 1551 if ( uFieldMask & osl_FileStatus_Mask_FileName ) 1552 { 1553 if ( pItemImpl->cDriveString[0] == '\\' && pItemImpl->cDriveString[1] == '\\' ) 1554 { 1555 LPCWSTR lpFirstBkSlash = wcschr( &pItemImpl->cDriveString[2], '\\' ); 1556 1557 if ( lpFirstBkSlash && lpFirstBkSlash[1] ) 1558 { 1559 LPCWSTR lpLastBkSlash = wcschr( &lpFirstBkSlash[1], '\\' ); 1560 1561 if ( lpLastBkSlash ) 1562 rtl_uString_newFromStr_WithLength( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]), lpLastBkSlash - lpFirstBkSlash - 1 ); 1563 else 1564 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(&lpFirstBkSlash[1]) ); 1565 pStatus->uValidFields |= osl_FileStatus_Mask_FileName; 1566 } 1567 } 1568 else switch ( GetDriveType( cRoot ) ) 1569 { 1570 case DRIVE_REMOTE: 1571 { 1572 TCHAR szBuffer[1024]; 1573 DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szBuffer); 1574 DWORD dwBufsize = dwBufsizeConst; 1575 1576 DWORD dwResult = WNetGetConnection( cDrive, szBuffer, &dwBufsize ); 1577 if ( NO_ERROR == dwResult ) 1578 { 1579 TCHAR szFileName[dwBufsizeConst + 16]; 1580 1581 swprintf( szFileName, L"%s [%s]", cDrive, szBuffer ); 1582 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) ); 1583 } 1584 else 1585 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) ); 1586 } 1587 pStatus->uValidFields |= osl_FileStatus_Mask_FileName; 1588 break; 1589 case DRIVE_FIXED: 1590 { 1591 TCHAR szVolumeNameBuffer[1024]; 1592 DWORD const dwBufsizeConst = ELEMENTS_OF_ARRAY(szVolumeNameBuffer); 1593 1594 if ( GetVolumeInformation( cRoot, szVolumeNameBuffer, dwBufsizeConst, NULL, NULL, NULL, NULL, 0 ) ) 1595 { 1596 TCHAR szFileName[dwBufsizeConst + 16]; 1597 1598 swprintf( szFileName, L"%s [%s]", cDrive, szVolumeNameBuffer ); 1599 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(szFileName) ); 1600 } 1601 else 1602 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cDrive) ); 1603 } 1604 pStatus->uValidFields |= osl_FileStatus_Mask_FileName; 1605 break; 1606 case DRIVE_CDROM: 1607 case DRIVE_REMOVABLE: 1608 pStatus->uValidFields |= osl_FileStatus_Mask_FileName; 1609 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(cRoot) ); 1610 break; 1611 case DRIVE_UNKNOWN: 1612 default: 1613 break; 1614 } 1615 } 1616 1617 pStatus->eType = osl_File_Type_Volume; 1618 pStatus->uValidFields |= osl_FileStatus_Mask_Type; 1619 1620 if ( uFieldMask & osl_FileStatus_Mask_FileURL ) 1621 { 1622 rtl_uString *ustrSystemPath = NULL; 1623 1624 rtl_uString_newFromStr( &ustrSystemPath, reinterpret_cast<const sal_Unicode*>(pItemImpl->cDriveString) ); 1625 osl_getFileURLFromSystemPath( ustrSystemPath, &pStatus->ustrFileURL ); 1626 rtl_uString_release( ustrSystemPath ); 1627 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL; 1628 } 1629 return osl_File_E_None; 1630 } 1631 1632 //##################################################### 1633 static oslFileError SAL_CALL osl_getServerInfo( 1634 oslDirectoryItem Item, oslFileStatus *pStatus, sal_uInt32 uFieldMask ) 1635 { 1636 DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; 1637 if ( !pItemImpl ) 1638 return osl_File_E_INVAL; 1639 1640 pStatus->uValidFields = 0; 1641 1642 // pStatus->uValidFields |= osl_FileStatus_Mask_FileName; 1643 1644 // if ( _tcscmp( pItemImpl->FindData.cFileName, TEXT(".") ) == 0 ) 1645 // rtl_uString_newFromAscii( &pStatus->ustrFileName, "/" ); 1646 // else 1647 // rtl_uString_newFromStr( &pStatus->ustrFileName, pItemImpl->FindData.cFileName ); 1648 1649 pStatus->eType = osl_File_Type_Directory; 1650 pStatus->uValidFields |= osl_FileStatus_Mask_Type; 1651 1652 if ( uFieldMask & osl_FileStatus_Mask_FileURL ) 1653 { 1654 osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL ); 1655 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL; 1656 } 1657 return osl_File_E_None; 1658 } 1659 1660 //############################################# 1661 oslFileError SAL_CALL osl_getFileStatus( 1662 oslDirectoryItem Item, 1663 oslFileStatus *pStatus, 1664 sal_uInt32 uFieldMask ) 1665 { 1666 DirectoryItem_Impl *pItemImpl = (DirectoryItem_Impl *)Item; 1667 1668 if ( !pItemImpl ) 1669 return osl_File_E_INVAL; 1670 1671 switch ( pItemImpl->uType ) 1672 { 1673 case DIRECTORYITEM_DRIVE: 1674 return osl_getDriveInfo( Item, pStatus, uFieldMask ); 1675 case DIRECTORYITEM_SERVER: 1676 return osl_getServerInfo( Item, pStatus, uFieldMask ); 1677 default: 1678 break; 1679 } 1680 1681 if ( uFieldMask & osl_FileStatus_Mask_Validate ) 1682 { 1683 HANDLE hFind = FindFirstFile( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ), &pItemImpl->FindData ); 1684 1685 if ( hFind != INVALID_HANDLE_VALUE ) 1686 FindClose( hFind ); 1687 else 1688 return oslTranslateFileError( GetLastError() ); 1689 1690 uFieldMask &= ~ osl_FileStatus_Mask_Validate; 1691 } 1692 1693 /* If no fields to retrieve left ignore pStatus */ 1694 if ( !uFieldMask ) 1695 return osl_File_E_None; 1696 1697 /* Otherwise, this must be a valid pointer */ 1698 if ( !pStatus ) 1699 return osl_File_E_INVAL; 1700 1701 if ( pStatus->uStructSize != sizeof(oslFileStatus) ) 1702 return osl_File_E_INVAL; 1703 1704 pStatus->uValidFields = 0; 1705 1706 /* File time stamps */ 1707 1708 if ( (uFieldMask & osl_FileStatus_Mask_ModifyTime) && 1709 FileTimeToTimeValue( &pItemImpl->FindData.ftLastWriteTime, &pStatus->aModifyTime ) ) 1710 pStatus->uValidFields |= osl_FileStatus_Mask_ModifyTime; 1711 1712 if ( (uFieldMask & osl_FileStatus_Mask_AccessTime) && 1713 FileTimeToTimeValue( &pItemImpl->FindData.ftLastAccessTime, &pStatus->aAccessTime ) ) 1714 pStatus->uValidFields |= osl_FileStatus_Mask_AccessTime; 1715 1716 if ( (uFieldMask & osl_FileStatus_Mask_CreationTime) && 1717 FileTimeToTimeValue( &pItemImpl->FindData.ftCreationTime, &pStatus->aCreationTime ) ) 1718 pStatus->uValidFields |= osl_FileStatus_Mask_CreationTime; 1719 1720 /* Most of the fields are already set, regardless of requiered fields */ 1721 1722 rtl_uString_newFromStr( &pStatus->ustrFileName, reinterpret_cast<const sal_Unicode*>(pItemImpl->FindData.cFileName) ); 1723 pStatus->uValidFields |= osl_FileStatus_Mask_FileName; 1724 1725 if ((FILE_ATTRIBUTE_REPARSE_POINT & pItemImpl->FindData.dwFileAttributes) && 1726 (IO_REPARSE_TAG_MOUNT_POINT == pItemImpl->FindData.dwReserved0)) 1727 pStatus->eType = osl_File_Type_Volume; 1728 else if (pItemImpl->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 1729 pStatus->eType = osl_File_Type_Directory; 1730 else 1731 pStatus->eType = osl_File_Type_Regular; 1732 1733 pStatus->uValidFields |= osl_FileStatus_Mask_Type; 1734 1735 pStatus->uAttributes = pItemImpl->FindData.dwFileAttributes; 1736 pStatus->uValidFields |= osl_FileStatus_Mask_Attributes; 1737 1738 pStatus->uFileSize = (sal_uInt64)pItemImpl->FindData.nFileSizeLow + ((sal_uInt64)pItemImpl->FindData.nFileSizeHigh << 32); 1739 pStatus->uValidFields |= osl_FileStatus_Mask_FileSize; 1740 1741 if ( uFieldMask & osl_FileStatus_Mask_LinkTargetURL ) 1742 { 1743 osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrLinkTargetURL ); 1744 1745 pStatus->uValidFields |= osl_FileStatus_Mask_LinkTargetURL; 1746 } 1747 1748 if ( uFieldMask & osl_FileStatus_Mask_FileURL ) 1749 { 1750 if ( !pItemImpl->bFullPathNormalized ) 1751 { 1752 sal_uInt32 nLen = rtl_uString_getLength( pItemImpl->m_pFullPath ); 1753 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); 1754 sal_uInt32 nNewLen = GetCaseCorrectPathName( reinterpret_cast<LPCTSTR>( rtl_uString_getStr( pItemImpl->m_pFullPath ) ), 1755 ::osl::mingw_reinterpret_cast<LPTSTR>( aBuffer ), 1756 aBuffer.getBufSizeInSymbols(), 1757 sal_True ); 1758 1759 if ( nNewLen ) 1760 { 1761 rtl_uString_newFromStr( &pItemImpl->m_pFullPath, aBuffer ); 1762 pItemImpl->bFullPathNormalized = TRUE; 1763 } 1764 } 1765 1766 osl_getFileURLFromSystemPath( pItemImpl->m_pFullPath, &pStatus->ustrFileURL ); 1767 pStatus->uValidFields |= osl_FileStatus_Mask_FileURL; 1768 } 1769 1770 return osl_File_E_None; 1771 } 1772 1773 //##################################################### 1774 // file attributes handling functions 1775 //##################################################### 1776 1777 //############################################# 1778 oslFileError SAL_CALL osl_setFileAttributes( 1779 rtl_uString *ustrFileURL, 1780 sal_uInt64 uAttributes ) 1781 { 1782 oslFileError error; 1783 rtl_uString *ustrSysPath = NULL; 1784 DWORD dwFileAttributes; 1785 BOOL fSuccess; 1786 1787 // Converts the normalized path into a systempath 1788 error = _osl_getSystemPathFromFileURL( ustrFileURL, &ustrSysPath, sal_False ); 1789 1790 if ( osl_File_E_None != error ) 1791 return error; 1792 1793 dwFileAttributes = GetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)) ); 1794 1795 if ( (DWORD)-1 != dwFileAttributes ) 1796 { 1797 dwFileAttributes &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN); 1798 1799 if ( uAttributes & osl_File_Attribute_ReadOnly ) 1800 dwFileAttributes |= FILE_ATTRIBUTE_READONLY; 1801 1802 if ( uAttributes & osl_File_Attribute_Hidden ) 1803 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN; 1804 1805 fSuccess = SetFileAttributes( reinterpret_cast<LPCTSTR>(rtl_uString_getStr(ustrSysPath)), dwFileAttributes ); 1806 } 1807 else 1808 fSuccess = FALSE; 1809 1810 if ( !fSuccess ) 1811 error = oslTranslateFileError( GetLastError() ); 1812 1813 rtl_uString_release( ustrSysPath ); 1814 1815 return error; 1816 } 1817 1818 //##################################################### 1819 oslFileError SAL_CALL osl_setFileTime( 1820 rtl_uString *filePath, 1821 const TimeValue *aCreationTime, 1822 const TimeValue *aLastAccessTime, 1823 const TimeValue *aLastWriteTime) 1824 { 1825 oslFileError error; 1826 rtl_uString *sysPath=NULL; 1827 FILETIME *lpCreationTime=NULL; 1828 FILETIME *lpLastAccessTime=NULL; 1829 FILETIME *lpLastWriteTime=NULL; 1830 FILETIME ftCreationTime; 1831 FILETIME ftLastAccessTime; 1832 FILETIME ftLastWriteTime; 1833 HANDLE hFile; 1834 BOOL fSuccess; 1835 1836 1837 error=_osl_getSystemPathFromFileURL(filePath, &sysPath, sal_False); 1838 1839 if (error==osl_File_E_INVAL) 1840 return error; 1841 1842 hFile=CreateFileW(reinterpret_cast<LPCWSTR>(rtl_uString_getStr(sysPath)), GENERIC_WRITE, 0, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 1843 rtl_uString_release(sysPath); 1844 1845 if (hFile==INVALID_HANDLE_VALUE) 1846 return osl_File_E_NOENT; 1847 1848 if (TimeValueToFileTime(aCreationTime, &ftCreationTime)) 1849 lpCreationTime=&ftCreationTime; 1850 1851 if (TimeValueToFileTime(aLastAccessTime, &ftLastAccessTime)) 1852 lpLastAccessTime=&ftLastAccessTime; 1853 1854 if (TimeValueToFileTime(aLastWriteTime, &ftLastWriteTime)) 1855 lpLastWriteTime=&ftLastWriteTime; 1856 1857 fSuccess=SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime); 1858 1859 CloseHandle(hFile); 1860 1861 if (!fSuccess) 1862 return osl_File_E_INVAL; 1863 else 1864 return osl_File_E_None; 1865 } 1866