winVolume.cpp
Engine/source/platformWin32/winVolume.cpp
Classes:
Namespaces:
namespace
namespace
Public Defines
define
NGROUPS_UMAX() 32
define
S_ISDIR(Flags) ((Flags) & FILE_ATTRIBUTE_DIRECTORY)
define
S_ISREG(Flags) !((Flags) & \ (FILE_ATTRIBUTE_DIRECTORY | \ FILE_ATTRIBUTE_OFFLINE | \ FILE_ATTRIBUTE_SYSTEM | \ FILE_ATTRIBUTE_TEMPORARY))
Detailed Description
Public Defines
NGROUPS_UMAX() 32
S_ISDIR(Flags) ((Flags) & FILE_ATTRIBUTE_DIRECTORY)
S_ISREG(Flags) !((Flags) & \ (FILE_ATTRIBUTE_DIRECTORY | \ FILE_ATTRIBUTE_OFFLINE | \ FILE_ATTRIBUTE_SYSTEM | \ FILE_ATTRIBUTE_TEMPORARY))
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include <windows.h> 25 26#include "core/crc.h" 27#include "core/frameAllocator.h" 28#include "core/util/str.h" 29#include "core/strings/stringFunctions.h" 30#include "core/strings/unicode.h" 31 32#include "platform/platformVolume.h" 33 34#include "platformWin32/winVolume.h" 35 36#include "console/console.h" 37 38 39#ifndef NGROUPS_UMAX 40 #define NGROUPS_UMAX 32 41#endif 42 43namespace Torque 44{ 45namespace Win32 46{ 47 48 // If the file is a Directory, Offline, System or Temporary then FALSE 49#define S_ISREG(Flags) \ 50 !((Flags) & \ 51 (FILE_ATTRIBUTE_DIRECTORY | \ 52 FILE_ATTRIBUTE_OFFLINE | \ 53 FILE_ATTRIBUTE_SYSTEM | \ 54 FILE_ATTRIBUTE_TEMPORARY)) 55 56#define S_ISDIR(Flags) \ 57 ((Flags) & FILE_ATTRIBUTE_DIRECTORY) 58 59//----------------------------------------------------------------------------- 60 61 class Win32FileSystemChangeNotifier : public FileSystemChangeNotifier 62 { 63 public: 64 Win32FileSystemChangeNotifier( FileSystem *fs ) 65 : FileSystemChangeNotifier( fs ) 66 { 67 VECTOR_SET_ASSOCIATION( mHandleList ); 68 VECTOR_SET_ASSOCIATION( mDirs ); 69 } 70 71 // for use in the thread itself 72 U32 getNumHandles() const { return mHandleList.size(); } 73 HANDLE *getHANDLES() { return mHandleList.address(); } 74 75 private: 76 virtual void internalProcessOnce(); 77 78 virtual bool internalAddNotification( const Path &dir ); 79 virtual bool internalRemoveNotification( const Path &dir ); 80 81 Vector<Path> mDirs; 82 Vector<HANDLE> mHandleList; 83 }; 84 85//----------------------------------------------------------------------------- 86 87static String _BuildFileName(const String& prefix,const Path& path) 88{ 89 // Need to join the path (minus the root) with our 90 // internal path name. 91 String file = prefix; 92 file = Path::Join(file, '/', path.getPath()); 93 file = Path::Join(file, '/', path.getFileName()); 94 file = Path::Join(file, '.', path.getExtension()); 95 return file; 96} 97 98/* 99static bool _IsFile(const String& file) 100{ 101 // Get file info 102 WIN32_FIND_DATA info; 103 HANDLE handle = ::FindFirstFile(PathToOS(file).utf16(), &info); 104 ::FindClose(handle); 105 if (handle == INVALID_HANDLE_VALUE) 106 return false; 107 108 return S_ISREG(info.dwFileAttributes); 109} 110*/ 111 112static bool _IsDirectory(const String& file) 113{ 114 // Get file info 115 WIN32_FIND_DATAW info; 116 HANDLE handle = ::FindFirstFileW(PathToOS(file).utf16(), &info); 117 ::FindClose(handle); 118 if (handle == INVALID_HANDLE_VALUE) 119 return false; 120 121 return S_ISDIR(info.dwFileAttributes); 122} 123 124 125//----------------------------------------------------------------------------- 126 127static void _CopyStatAttributes(const WIN32_FIND_DATAW& info, FileNode::Attributes* attr) 128{ 129 // Fill in the return struct. 130 attr->flags = 0; 131 if (S_ISDIR(info.dwFileAttributes)) 132 attr->flags |= FileNode::Directory; 133 if (S_ISREG(info.dwFileAttributes)) 134 attr->flags |= FileNode::File; 135 136 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) 137 attr->flags |= FileNode::ReadOnly; 138 139 attr->size = info.nFileSizeLow; 140 attr->mtime = Win32FileTimeToTime( 141 info.ftLastWriteTime.dwLowDateTime, 142 info.ftLastWriteTime.dwHighDateTime); 143 144 attr->atime = Win32FileTimeToTime( 145 info.ftLastAccessTime.dwLowDateTime, 146 info.ftLastAccessTime.dwHighDateTime); 147} 148 149 150//----------------------------------------------------------------------------- 151 152bool Win32FileSystemChangeNotifier::internalAddNotification( const Path &dir ) 153{ 154 for ( U32 i = 0; i < mDirs.size(); ++i ) 155 { 156 if ( mDirs[i] == dir ) 157 return false; 158 } 159 160 Path fullFSPath = mFS->mapTo( dir ); 161 String osPath = PathToOS( fullFSPath ); 162 163// Con::printf( "[Win32FileSystemChangeNotifier::internalAddNotification] : [%s]", osPath.c_str() ); 164 165 HANDLE changeHandle = ::FindFirstChangeNotificationW( 166 osPath.utf16(), // directory to watch 167 FALSE, // do not watch subtree 168 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES); // watch file write changes 169 170 if (changeHandle == INVALID_HANDLE_VALUE || changeHandle == NULL) 171 { 172 Con::errorf("[Win32FileSystemChangeNotifier::internalAddNotification] : failed on [%s] [%d]", osPath.c_str(), GetLastError()); 173 174 return false; 175 } 176 177 mDirs.push_back( dir ); 178 mHandleList.push_back( changeHandle ); 179 180 return true; 181} 182 183bool Win32FileSystemChangeNotifier::internalRemoveNotification( const Path &dir ) 184{ 185 for ( U32 i = 0; i < mDirs.size(); ++i ) 186 { 187 if ( mDirs[i] != dir ) 188 continue; 189 190 ::FindCloseChangeNotification( mHandleList[i] ); 191 mDirs.erase( i ); 192 mHandleList.erase( i ); 193 194 return true; 195 } 196 197 return false; 198} 199 200void Win32FileSystemChangeNotifier::internalProcessOnce() 201{ 202 // WaitForMultipleObjects has a limit of MAXIMUM_WAIT_OBJECTS (64 at 203 // the moment), so we have to loop till we've handled the entire set. 204 205 for ( U32 i=0; i < mHandleList.size(); i += MAXIMUM_WAIT_OBJECTS ) 206 { 207 U32 numHandles = getMin( (U32)MAXIMUM_WAIT_OBJECTS, (U32)mHandleList.size() - i ); 208 209 DWORD dwWaitStatus = WaitForMultipleObjects( numHandles, mHandleList.address()+i, FALSE, 0); 210 if ( dwWaitStatus == WAIT_FAILED || dwWaitStatus == WAIT_TIMEOUT ) 211 continue; 212 213 if ( dwWaitStatus >= WAIT_OBJECT_0 && dwWaitStatus <= (WAIT_OBJECT_0 + numHandles - 1)) 214 { 215 U32 index = i + dwWaitStatus; 216 217 // reset our notification 218 // NOTE: we do this before letting the volume system check mod times so we don't miss any. 219 // It is going to loop over the files and check their mod time vs. the saved time. 220 // This may result in extra calls to internalNotifyDirChanged(), but it will simpley check mod times again. 221 ::FindNextChangeNotification( mHandleList[index] ); 222 223 internalNotifyDirChanged( mDirs[index] ); 224 } 225 } 226} 227 228//----------------------------------------------------------------------------- 229 230Win32FileSystem::Win32FileSystem(String volume) 231{ 232 mVolume = volume; 233 mChangeNotifier = new Win32FileSystemChangeNotifier( this ); 234} 235 236Win32FileSystem::~Win32FileSystem() 237{ 238} 239 240void Win32FileSystem::verifyCompatibility(const Path& _path, WIN32_FIND_DATAW _info) 241{ 242 if (_path.getFullFileName().isNotEmpty() && _path.getFullFileName().compare(String(_info.cFileName)) != 0) 243 { 244 Con::warnf("Linux Compatibility Warning: %s != %s", String(_info.cFileName).c_str(), _path.getFullFileName().c_str()); 245 } 246} 247 248FileNodeRef Win32FileSystem::resolve(const Path& path) 249{ 250 String file = _BuildFileName(mVolume,path); 251 252 WIN32_FIND_DATAW info; 253 HANDLE handle = ::FindFirstFileW(PathToOS(file).utf16(), &info); 254 ::FindClose(handle); 255 if (handle != INVALID_HANDLE_VALUE) 256 { 257#ifdef TORQUE_DEBUG 258 verifyCompatibility(path, info); 259#endif 260 if (S_ISREG(info.dwFileAttributes)) 261 return new Win32File(path,file); 262 if (S_ISDIR(info.dwFileAttributes)) 263 return new Win32Directory(path,file); 264 } 265 return 0; 266} 267 268FileNodeRef Win32FileSystem::create(const Path& path, FileNode::Mode mode) 269{ 270 // The file will be created on disk when it's opened. 271 if (mode & FileNode::File) 272 return new Win32File(path,_BuildFileName(mVolume,path)); 273 274 // Create with default permissions. 275 if (mode & FileNode::Directory) 276 { 277 String file = PathToOS(_BuildFileName(mVolume,path)); 278 279 if (::CreateDirectoryW(file.utf16(), 0)) 280 return new Win32Directory(path, file); 281 } 282 return 0; 283} 284 285bool Win32FileSystem::remove(const Path& path) 286{ 287 // Should probably check for outstanding files or directory objects. 288 String file = PathToOS(_BuildFileName(mVolume,path)); 289 290 WIN32_FIND_DATAW info; 291 HANDLE handle = ::FindFirstFileW(file.utf16(), &info); 292 ::FindClose(handle); 293 if (handle == INVALID_HANDLE_VALUE) 294 return false; 295 296 if (S_ISDIR(info.dwFileAttributes)) 297 return ::RemoveDirectoryW(file.utf16()); 298 299 return ::DeleteFileW(file.utf16()); 300} 301 302bool Win32FileSystem::rename(const Path& from,const Path& to) 303{ 304 String fa = PathToOS(_BuildFileName(mVolume,from)); 305 String fb = PathToOS(_BuildFileName(mVolume,to)); 306 307 return MoveFile(fa.utf16(),fb.utf16()); 308} 309 310Path Win32FileSystem::mapTo(const Path& path) 311{ 312 return _BuildFileName(mVolume,path); 313} 314 315Path Win32FileSystem::mapFrom(const Path& path) 316{ 317 const String::SizeType volumePathLen = mVolume.length(); 318 319 String pathStr = path.getFullPath(); 320 321 if ( mVolume.compare( pathStr, volumePathLen, String::NoCase )) 322 return Path(); 323 324 return pathStr.substr( volumePathLen, pathStr.length() - volumePathLen ); 325} 326 327//----------------------------------------------------------------------------- 328 329Win32File::Win32File(const Path& path,String name) 330{ 331 mPath = path; 332 mName = name; 333 mStatus = Closed; 334 mHandle = 0; 335} 336 337Win32File::~Win32File() 338{ 339 if (mHandle) 340 close(); 341} 342 343Path Win32File::getName() const 344{ 345 return mPath; 346} 347 348FileNode::NodeStatus Win32File::getStatus() const 349{ 350 return mStatus; 351} 352 353bool Win32File::getAttributes(Attributes* attr) 354{ 355 WIN32_FIND_DATAW info; 356 HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info); 357 ::FindClose(handle); 358 if (handle == INVALID_HANDLE_VALUE) 359 return false; 360 361 _CopyStatAttributes(info,attr); 362 attr->name = mPath; 363 return true; 364} 365 366U64 Win32File::getSize() 367{ 368 U64 size; 369 370 if (mStatus == Open) 371 { 372 // Special case if file is open (handles unflushed buffers) 373 if ( !GetFileSizeEx(mHandle, (PLARGE_INTEGER)&size) ) 374 size = 0; 375 return size; 376 } 377 else 378 { 379 // Fallback to generic function 380 size = File::getSize(); 381 } 382 383 return size; 384} 385 386U32 Win32File::calculateChecksum() 387{ 388 if (!open( Read )) 389 return 0; 390 391 U64 fileSize = getSize(); 392 U32 bufSize = 1024 * 1024 * 4; // 4MB 393 FrameTemp<U8> buf( bufSize ); 394 U32 crc = CRC::INITIAL_CRC_VALUE; 395 396 while ( fileSize > 0 ) 397 { 398 U32 bytesRead = getMin( fileSize, bufSize ); 399 if ( read( buf, bytesRead ) != bytesRead ) 400 { 401 close(); 402 return 0; 403 } 404 405 fileSize -= bytesRead; 406 crc = CRC::calculateCRC(buf, bytesRead, crc); 407 } 408 409 close(); 410 411 return crc; 412} 413 414bool Win32File::open(AccessMode mode) 415{ 416 close(); 417 418 if (mName.isEmpty()) 419 return mStatus; 420 421 struct Mode 422 { 423 DWORD mode,share,open; 424 } Modes[] = 425 { 426 { GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING }, // Read 427 { GENERIC_WRITE,0,CREATE_ALWAYS }, // Write 428 { GENERIC_WRITE | GENERIC_READ,0,OPEN_ALWAYS }, // ReadWrite 429 { GENERIC_WRITE,0,OPEN_ALWAYS } // WriteAppend 430 }; 431 432 Mode& m = (mode == Read)? Modes[0]: (mode == Write)? Modes[1]: 433 (mode == ReadWrite)? Modes[2]: Modes[3]; 434 435 mHandle = (void*)::CreateFileW(PathToOS(mName).utf16(), 436 m.mode, m.share, 437 NULL, m.open, 438 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 439 NULL); 440 441 if ( mHandle == INVALID_HANDLE_VALUE || mHandle == NULL ) 442 { 443 _updateStatus(); 444 return false; 445 } 446 447 mStatus = Open; 448 return true; 449} 450 451bool Win32File::close() 452{ 453 if (mHandle) 454 { 455 ::CloseHandle((HANDLE)mHandle); 456 mHandle = 0; 457 } 458 459 mStatus = Closed; 460 return true; 461} 462 463U32 Win32File::getPosition() 464{ 465 if (mStatus == Open || mStatus == EndOfFile) 466 return ::SetFilePointer((HANDLE)mHandle,0,0,FILE_CURRENT); 467 return 0; 468} 469 470U32 Win32File::setPosition(U32 delta, SeekMode mode) 471{ 472 if (mStatus != Open && mStatus != EndOfFile) 473 return 0; 474 475 DWORD fmode; 476 switch (mode) 477 { 478 case Begin: fmode = FILE_BEGIN; break; 479 case Current: fmode = FILE_CURRENT; break; 480 case End: fmode = FILE_END; break; 481 default: fmode = 0; break; 482 } 483 484 DWORD pos = ::SetFilePointer((HANDLE)mHandle,delta,0,fmode); 485 if (pos == INVALID_SET_FILE_POINTER) 486 { 487 mStatus = UnknownError; 488 return 0; 489 } 490 491 mStatus = Open; 492 493 return pos; 494} 495 496U32 Win32File::read(void* dst, U32 size) 497{ 498 if (mStatus != Open && mStatus != EndOfFile) 499 return 0; 500 501 DWORD bytesRead; 502 if (!::ReadFile((HANDLE)mHandle,dst,size,&bytesRead,0)) 503 _updateStatus(); 504 else if (bytesRead != size) 505 mStatus = EndOfFile; 506 507 return bytesRead; 508} 509 510U32 Win32File::write(const void* src, U32 size) 511{ 512 if ((mStatus != Open && mStatus != EndOfFile) || !size) 513 return 0; 514 515 DWORD bytesWritten; 516 if (!::WriteFile((HANDLE)mHandle,src,size,&bytesWritten,0)) 517 _updateStatus(); 518 return bytesWritten; 519} 520 521void Win32File::_updateStatus() 522{ 523 switch (::GetLastError()) 524 { 525 case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break; 526 case ERROR_TOO_MANY_OPEN_FILES: mStatus = UnknownError; break; 527 case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break; 528 case ERROR_FILE_NOT_FOUND: mStatus = NoSuchFile; break; 529 case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break; 530 case ERROR_HANDLE_DISK_FULL: mStatus = FileSystemFull; break; 531 case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break; 532 default: mStatus = UnknownError; break; 533 } 534} 535 536//----------------------------------------------------------------------------- 537 538Win32Directory::Win32Directory(const Path& path,String name) 539{ 540 mPath = path; 541 mName = name; 542 mStatus = Closed; 543 mHandle = 0; 544} 545 546Win32Directory::~Win32Directory() 547{ 548 if (mHandle) 549 close(); 550} 551 552Path Win32Directory::getName() const 553{ 554 return mPath; 555} 556 557bool Win32Directory::open() 558{ 559 if (!_IsDirectory(mName)) 560 { 561 mStatus = NoSuchFile; 562 return false; 563 } 564 mStatus = Open; 565 return true; 566} 567 568bool Win32Directory::close() 569{ 570 if (mHandle) 571 { 572 ::FindClose((HANDLE)mHandle); 573 mHandle = 0; 574 return true; 575 } 576 return false; 577} 578 579bool Win32Directory::read(Attributes* entry) 580{ 581 if (mStatus != Open) 582 return false; 583 584 WIN32_FIND_DATA info; 585 if (!mHandle) 586 { 587 mHandle = ::FindFirstFileW((PathToOS(mName) + "\\*").utf16(), &info); 588 589 if (mHandle == NULL) 590 { 591 _updateStatus(); 592 return false; 593 } 594 } 595 else 596 if (!::FindNextFileW((HANDLE)mHandle, &info)) 597 { 598 _updateStatus(); 599 return false; 600 } 601 602 // Skip "." and ".." entries 603 if (info.cFileName[0] == '.' && (info.cFileName[1] == '\0' || 604 (info.cFileName[1] == '.' && info.cFileName[2] == '\0'))) 605 return read(entry); 606 607 _CopyStatAttributes(info,entry); 608 entry->name = info.cFileName; 609 return true; 610} 611 612 613U32 Win32Directory::calculateChecksum() 614{ 615 // Return checksum of current entry 616 return 0; 617} 618 619bool Win32Directory::getAttributes(Attributes* attr) 620{ 621 WIN32_FIND_DATA info; 622 HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info); 623 ::FindClose(handle); 624 if (handle == INVALID_HANDLE_VALUE) 625 { 626 _updateStatus(); 627 return false; 628 } 629 630 _CopyStatAttributes(info,attr); 631 attr->name = mPath; 632 return true; 633} 634 635FileNode::NodeStatus Win32Directory::getStatus() const 636{ 637 return mStatus; 638} 639 640void Win32Directory::_updateStatus() 641{ 642 switch (::GetLastError()) 643 { 644 case ERROR_NO_MORE_FILES: mStatus = EndOfFile; break; 645 case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break; 646 case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break; 647 case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break; 648 case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break; 649 default: mStatus = UnknownError; break; 650 } 651} 652 653} // Namespace Win32 654 655bool FS::VerifyWriteAccess(const Path &path) 656{ 657 // due to UAC's habit of creating "virtual stores" when permission isn't actually available 658 // actually create, write, read, verify, and delete a file to the folder being tested 659 660 String temp = path.getFullPath(); 661 temp += "\\torque_writetest.tmp"; 662 663 // first, (try and) delete the file if it exists 664 ::DeleteFileW(temp.utf16()); 665 666 // now, create the file 667 668 HANDLE hFile = ::CreateFileW(PathToOS(temp).utf16(), 669 GENERIC_WRITE, 0, 670 NULL, CREATE_ALWAYS, 671 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 672 NULL); 673 674 if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL ) 675 return false; 676 677 U32 t = Platform::getTime(); 678 679 DWORD bytesWritten; 680 if (!::WriteFile(hFile,&t,sizeof(t),&bytesWritten,0)) 681 { 682 ::CloseHandle(hFile); 683 ::DeleteFileW(temp.utf16()); 684 return false; 685 } 686 687 // close the file 688 ::CloseHandle(hFile); 689 690 // open for read 691 692 hFile = ::CreateFileW(PathToOS(temp).utf16(), 693 GENERIC_READ, FILE_SHARE_READ, 694 NULL, OPEN_EXISTING, 695 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 696 NULL); 697 698 if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL ) 699 return false; 700 701 U32 t2 = 0; 702 703 DWORD bytesRead; 704 if (!::ReadFile(hFile,&t2,sizeof(t2),&bytesRead,0)) 705 { 706 ::CloseHandle(hFile); 707 ::DeleteFileW(temp.utf16()); 708 return false; 709 } 710 711 ::CloseHandle(hFile); 712 ::DeleteFileW(temp.utf16()); 713 714 return t == t2; 715} 716 717 718} // Namespace Torque 719 720//----------------------------------------------------------------------------- 721 722Torque::FS::FileSystemRef Platform::FS::createNativeFS( const String &volume ) 723{ 724 return new Win32::Win32FileSystem( volume ); 725} 726 727String Platform::FS::getAssetDir() 728{ 729 char cen_buf[2048]; 730#ifdef TORQUE_UNICODE 731 if (!Platform::getWebDeployment()) 732 { 733 TCHAR buf[ 2048 ]; 734 ::GetModuleFileNameW( NULL, buf, sizeof( buf ) ); 735 convertUTF16toUTF8( buf, cen_buf ); 736 } 737 else 738 { 739 TCHAR buf[ 2048 ]; 740 GetCurrentDirectoryW( sizeof( buf ) / sizeof( buf[ 0 ] ), buf ); 741 convertUTF16toUTF8( buf, cen_buf ); 742 return Path::CleanSeparators(cen_buf); 743 } 744#else 745 ::GetModuleFileNameA( NULL, cen_buf, 2047); 746#endif 747 748 char *delimiter = dStrrchr( cen_buf, '\\' ); 749 750 if( delimiter != NULL ) 751 *delimiter = '\0'; 752 753 return Path::CleanSeparators(cen_buf); 754} 755 756/// Function invoked by the kernel layer to install OS specific 757/// file systems. 758bool Platform::FS::InstallFileSystems() 759{ 760 WCHAR buffer[1024]; 761 762 // [8/24/2009 tomb] This stops Windows from complaining about drives that have no disks in 763 SetErrorMode(SEM_FAILCRITICALERRORS); 764 765 // Load all the Win32 logical drives. 766 DWORD mask = ::GetLogicalDrives(); 767 char drive[] = "A"; 768 char volume[] = "A:/"; 769 while (mask) 770 { 771 if (mask & 1) 772 { 773 volume[0] = drive[0]; 774 Platform::FS::Mount(drive, Platform::FS::createNativeFS(volume)); 775 } 776 mask >>= 1; 777 drive[0]++; 778 } 779 780 // Set the current working dir. Windows normally returns 781 // upper case driver letters, but the cygwin bash shell 782 // seems to make it return lower case drives. Force upper 783 // to be consistent with the mounts. 784 ::GetCurrentDirectory(sizeof(buffer), buffer); 785 786 if (buffer[1] == ':') 787 buffer[0] = dToupper(buffer[0]); 788 789 String wd = buffer; 790 791 wd += '/'; 792 793 Platform::FS::SetCwd(wd); 794 795 return true; 796} 797 798 799