123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include <windows.h>
- #include "core/crc.h"
- #include "core/frameAllocator.h"
- #include "core/util/str.h"
- #include "core/strings/stringFunctions.h"
- #include "core/strings/unicode.h"
- #include "platform/platformVolume.h"
- #include "platformWin32/winVolume.h"
- #include "console/console.h"
- #ifndef NGROUPS_UMAX
- #define NGROUPS_UMAX 32
- #endif
- namespace Torque
- {
- namespace Win32
- {
- // If the file is a Directory, Offline, System or Temporary then FALSE
- #define S_ISREG(Flags) \
- !((Flags) & \
- (FILE_ATTRIBUTE_DIRECTORY | \
- FILE_ATTRIBUTE_OFFLINE | \
- FILE_ATTRIBUTE_SYSTEM | \
- FILE_ATTRIBUTE_TEMPORARY))
- #define S_ISDIR(Flags) \
- ((Flags) & FILE_ATTRIBUTE_DIRECTORY)
- //-----------------------------------------------------------------------------
- class Win32FileSystemChangeNotifier : public FileSystemChangeNotifier
- {
- public:
- Win32FileSystemChangeNotifier( FileSystem *fs )
- : FileSystemChangeNotifier( fs )
- {
- VECTOR_SET_ASSOCIATION( mHandleList );
- VECTOR_SET_ASSOCIATION( mDirs );
- }
- // for use in the thread itself
- U32 getNumHandles() const { return mHandleList.size(); }
- HANDLE *getHANDLES() { return mHandleList.address(); }
- private:
- virtual void internalProcessOnce();
- virtual bool internalAddNotification( const Path &dir );
- virtual bool internalRemoveNotification( const Path &dir );
- Vector<Path> mDirs;
- Vector<HANDLE> mHandleList;
- };
- //-----------------------------------------------------------------------------
- static String _BuildFileName(const String& prefix,const Path& path)
- {
- // Need to join the path (minus the root) with our
- // internal path name.
- String file = prefix;
- file = Path::Join(file, '/', path.getPath());
- if (path.getFileName().isEmpty() && path.getExtension().isNotEmpty()) //weird, filename-less file, so handle it slightly special-case
- file += String("/");
- else
- file = Path::Join(file, '/', path.getFileName());
- file = Path::Join(file, '.', path.getExtension());
- return file;
- }
- /*
- static bool _IsFile(const String& file)
- {
- // Get file info
- WIN32_FIND_DATA info;
- HANDLE handle = ::FindFirstFile(PathToOS(file).utf16(), &info);
- ::FindClose(handle);
- if (handle == INVALID_HANDLE_VALUE)
- return false;
- return S_ISREG(info.dwFileAttributes);
- }
- */
- static bool _IsDirectory(const String& file)
- {
- // Get file info
- WIN32_FIND_DATAW info;
- HANDLE handle = ::FindFirstFileW(PathToOS(file).utf16(), &info);
- ::FindClose(handle);
- if (handle == INVALID_HANDLE_VALUE)
- return false;
- return S_ISDIR(info.dwFileAttributes);
- }
- //-----------------------------------------------------------------------------
- static void _CopyStatAttributes(const WIN32_FIND_DATAW& info, FileNode::Attributes* attr)
- {
- // Fill in the return struct.
- attr->flags = 0;
- if (S_ISDIR(info.dwFileAttributes))
- attr->flags |= FileNode::Directory;
- if (S_ISREG(info.dwFileAttributes))
- attr->flags |= FileNode::File;
- if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
- attr->flags |= FileNode::ReadOnly;
- attr->size = info.nFileSizeLow;
- attr->mtime = Win32FileTimeToTime(
- info.ftLastWriteTime.dwLowDateTime,
- info.ftLastWriteTime.dwHighDateTime);
- attr->atime = Win32FileTimeToTime(
- info.ftLastAccessTime.dwLowDateTime,
- info.ftLastAccessTime.dwHighDateTime);
- attr->ctime = Win32FileTimeToTime(
- info.ftCreationTime.dwLowDateTime,
- info.ftCreationTime.dwHighDateTime);
- }
- //-----------------------------------------------------------------------------
- bool Win32FileSystemChangeNotifier::internalAddNotification( const Path &dir )
- {
- for ( U32 i = 0; i < mDirs.size(); ++i )
- {
- if ( mDirs[i] == dir )
- return false;
- }
- Path fullFSPath = mFS->mapTo( dir );
- String osPath = PathToOS( fullFSPath );
- // Con::printf( "[Win32FileSystemChangeNotifier::internalAddNotification] : [%s]", osPath.c_str() );
- HANDLE changeHandle = ::FindFirstChangeNotificationW(
- osPath.utf16(), // directory to watch
- FALSE, // do not watch subtree
- FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES); // watch file write changes
- if (changeHandle == INVALID_HANDLE_VALUE || changeHandle == NULL)
- {
- Con::errorf("[Win32FileSystemChangeNotifier::internalAddNotification] : failed on [%s] [%d]", osPath.c_str(), GetLastError());
-
- return false;
- }
- mDirs.push_back( dir );
- mHandleList.push_back( changeHandle );
- return true;
- }
- bool Win32FileSystemChangeNotifier::internalRemoveNotification( const Path &dir )
- {
- for ( U32 i = 0; i < mDirs.size(); ++i )
- {
- if ( mDirs[i] != dir )
- continue;
- ::FindCloseChangeNotification( mHandleList[i] );
- mDirs.erase( i );
- mHandleList.erase( i );
- return true;
- }
- return false;
- }
- void Win32FileSystemChangeNotifier::internalProcessOnce()
- {
- // WaitForMultipleObjects has a limit of MAXIMUM_WAIT_OBJECTS (64 at
- // the moment), so we have to loop till we've handled the entire set.
- for ( U32 i=0; i < mHandleList.size(); i += MAXIMUM_WAIT_OBJECTS )
- {
- U32 numHandles = getMin( (U32)MAXIMUM_WAIT_OBJECTS, (U32)mHandleList.size() - i );
- DWORD dwWaitStatus = WaitForMultipleObjects( numHandles, mHandleList.address()+i, FALSE, 0);
- if ( dwWaitStatus == WAIT_FAILED || dwWaitStatus == WAIT_TIMEOUT )
- continue;
- if ( dwWaitStatus >= WAIT_OBJECT_0 && dwWaitStatus <= (WAIT_OBJECT_0 + numHandles - 1))
- {
- U32 index = i + dwWaitStatus;
- // reset our notification
- // NOTE: we do this before letting the volume system check mod times so we don't miss any.
- // It is going to loop over the files and check their mod time vs. the saved time.
- // This may result in extra calls to internalNotifyDirChanged(), but it will simpley check mod times again.
- ::FindNextChangeNotification( mHandleList[index] );
- internalNotifyDirChanged( mDirs[index] );
- }
- }
- }
- //-----------------------------------------------------------------------------
- Win32FileSystem::Win32FileSystem(String volume)
- {
- mVolume = volume;
- mChangeNotifier = new Win32FileSystemChangeNotifier( this );
- }
- Win32FileSystem::~Win32FileSystem()
- {
- }
- void Win32FileSystem::verifyCompatibility(const Path& _path, WIN32_FIND_DATAW _info)
- {
- #ifndef TORQUE_POSIX_PATH_CASE_INSENSITIVE
- if (_path.getFullFileName().isNotEmpty() && _path.getFullFileName().compare(String(_info.cFileName)) != 0)
- {
- Con::warnf("Linux Compatibility Warning: %s != %s", String(_info.cFileName).c_str(), _path.getFullFileName().c_str());
- }
- #endif
- }
- FileNodeRef Win32FileSystem::resolve(const Path& path)
- {
- String file = _BuildFileName(mVolume,path);
- WIN32_FIND_DATAW info;
- HANDLE handle = ::FindFirstFileW(PathToOS(file).utf16(), &info);
- ::FindClose(handle);
- if (handle != INVALID_HANDLE_VALUE)
- {
- #ifdef TORQUE_DEBUG
- verifyCompatibility(path, info);
- #endif
- if (S_ISREG(info.dwFileAttributes))
- return new Win32File(path,file);
- if (S_ISDIR(info.dwFileAttributes))
- return new Win32Directory(path,file);
- }
- return 0;
- }
- FileNodeRef Win32FileSystem::create(const Path& path, FileNode::Mode mode)
- {
- // The file will be created on disk when it's opened.
- if (mode & FileNode::File)
- return new Win32File(path,_BuildFileName(mVolume,path));
- // Create with default permissions.
- if (mode & FileNode::Directory)
- {
- String file = PathToOS(_BuildFileName(mVolume,path));
- if (::CreateDirectoryW(file.utf16(), 0))
- return new Win32Directory(path, file);
- }
- return 0;
- }
- bool Win32FileSystem::remove(const Path& path)
- {
- // Should probably check for outstanding files or directory objects.
- String file = PathToOS(_BuildFileName(mVolume,path));
- WIN32_FIND_DATAW info;
- HANDLE handle = ::FindFirstFileW(file.utf16(), &info);
- ::FindClose(handle);
- if (handle == INVALID_HANDLE_VALUE)
- return false;
- if (S_ISDIR(info.dwFileAttributes))
- return ::RemoveDirectoryW(file.utf16());
- return ::DeleteFileW(file.utf16());
- }
- bool Win32FileSystem::rename(const Path& from,const Path& to)
- {
- String fa = PathToOS(_BuildFileName(mVolume,from));
- String fb = PathToOS(_BuildFileName(mVolume,to));
- return MoveFile(fa.utf16(),fb.utf16());
- }
- Path Win32FileSystem::mapTo(const Path& path)
- {
- return _BuildFileName(mVolume,path);
- }
- Path Win32FileSystem::mapFrom(const Path& path)
- {
- const String::SizeType volumePathLen = mVolume.length();
-
- String pathStr = path.getFullPath();
- if ( mVolume.compare( pathStr, volumePathLen, String::NoCase ))
- return Path();
- return pathStr.substr( volumePathLen, pathStr.length() - volumePathLen );
- }
- //-----------------------------------------------------------------------------
- Win32File::Win32File(const Path& path,String name)
- {
- mPath = path;
- mName = name;
- mStatus = Closed;
- mHandle = 0;
- }
- Win32File::~Win32File()
- {
- if (mHandle)
- close();
- }
- Path Win32File::getName() const
- {
- return mPath;
- }
- FileNode::NodeStatus Win32File::getStatus() const
- {
- return mStatus;
- }
- bool Win32File::getAttributes(Attributes* attr)
- {
- WIN32_FIND_DATAW info;
- HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info);
- ::FindClose(handle);
- if (handle == INVALID_HANDLE_VALUE)
- return false;
- _CopyStatAttributes(info,attr);
- attr->name = mPath;
- return true;
- }
- U64 Win32File::getSize()
- {
- U64 size;
- if (mStatus == Open)
- {
- // Special case if file is open (handles unflushed buffers)
- if ( !GetFileSizeEx(mHandle, (PLARGE_INTEGER)&size) )
- size = 0;
- return size;
- }
- else
- {
- // Fallback to generic function
- size = File::getSize();
- }
- return size;
- }
- U32 Win32File::calculateChecksum()
- {
- if (!open( Read ))
- return 0;
- U64 fileSize = getSize();
- U32 bufSize = 1024 * 1024 * 4; // 4MB
- FrameTemp<U8> buf( bufSize );
- U32 crc = CRC::INITIAL_CRC_VALUE;
- while ( fileSize > 0 )
- {
- U32 bytesRead = getMin( fileSize, bufSize );
- if ( read( buf, bytesRead ) != bytesRead )
- {
- close();
- return 0;
- }
- fileSize -= bytesRead;
- crc = CRC::calculateCRC(buf, bytesRead, crc);
- }
- close();
- return crc;
- }
- bool Win32File::open(AccessMode mode)
- {
- close();
- if (mName.isEmpty())
- return mStatus;
- struct Mode
- {
- DWORD mode,share,open;
- } Modes[] =
- {
- { GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING }, // Read
- { GENERIC_WRITE,0,CREATE_ALWAYS }, // Write
- { GENERIC_WRITE | GENERIC_READ,0,OPEN_ALWAYS }, // ReadWrite
- { GENERIC_WRITE,0,OPEN_ALWAYS } // WriteAppend
- };
- Mode& m = (mode == Read)? Modes[0]: (mode == Write)? Modes[1]:
- (mode == ReadWrite)? Modes[2]: Modes[3];
- mHandle = (void*)::CreateFileW(PathToOS(mName).utf16(),
- m.mode, m.share,
- NULL, m.open,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
- NULL);
- if ( mHandle == INVALID_HANDLE_VALUE || mHandle == NULL )
- {
- _updateStatus();
- return false;
- }
- mStatus = Open;
- return true;
- }
- bool Win32File::close()
- {
- if (mHandle)
- {
- ::CloseHandle((HANDLE)mHandle);
- mHandle = 0;
- }
- mStatus = Closed;
- return true;
- }
- U32 Win32File::getPosition()
- {
- if (mStatus == Open || mStatus == EndOfFile)
- return ::SetFilePointer((HANDLE)mHandle,0,0,FILE_CURRENT);
- return 0;
- }
- U32 Win32File::setPosition(U32 delta, SeekMode mode)
- {
- if (mStatus != Open && mStatus != EndOfFile)
- return 0;
- DWORD fmode;
- switch (mode)
- {
- case Begin: fmode = FILE_BEGIN; break;
- case Current: fmode = FILE_CURRENT; break;
- case End: fmode = FILE_END; break;
- default: fmode = 0; break;
- }
- DWORD pos = ::SetFilePointer((HANDLE)mHandle,delta,0,fmode);
- if (pos == INVALID_SET_FILE_POINTER)
- {
- mStatus = UnknownError;
- return 0;
- }
- mStatus = Open;
- return pos;
- }
- U32 Win32File::read(void* dst, U32 size)
- {
- if (mStatus != Open && mStatus != EndOfFile)
- return 0;
- DWORD bytesRead;
- if (!::ReadFile((HANDLE)mHandle,dst,size,&bytesRead,0))
- _updateStatus();
- else if (bytesRead != size)
- mStatus = EndOfFile;
- return bytesRead;
- }
- U32 Win32File::write(const void* src, U32 size)
- {
- if ((mStatus != Open && mStatus != EndOfFile) || !size)
- return 0;
- DWORD bytesWritten;
- if (!::WriteFile((HANDLE)mHandle,src,size,&bytesWritten,0))
- _updateStatus();
- return bytesWritten;
- }
- void Win32File::_updateStatus()
- {
- switch (::GetLastError())
- {
- case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break;
- case ERROR_TOO_MANY_OPEN_FILES: mStatus = UnknownError; break;
- case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break;
- case ERROR_FILE_NOT_FOUND: mStatus = NoSuchFile; break;
- case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break;
- case ERROR_HANDLE_DISK_FULL: mStatus = FileSystemFull; break;
- case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break;
- default: mStatus = UnknownError; break;
- }
- }
- //-----------------------------------------------------------------------------
- Win32Directory::Win32Directory(const Path& path,String name)
- {
- mPath = path;
- mName = name;
- mStatus = Closed;
- mHandle = 0;
- }
- Win32Directory::~Win32Directory()
- {
- if (mHandle)
- close();
- }
- Path Win32Directory::getName() const
- {
- return mPath;
- }
- bool Win32Directory::open()
- {
- if (!_IsDirectory(mName))
- {
- mStatus = NoSuchFile;
- return false;
- }
- mStatus = Open;
- return true;
- }
- bool Win32Directory::close()
- {
- if (mHandle)
- {
- ::FindClose((HANDLE)mHandle);
- mHandle = 0;
- return true;
- }
- return false;
- }
- bool Win32Directory::read(Attributes* entry)
- {
- if (mStatus != Open)
- return false;
- WIN32_FIND_DATA info;
- if (!mHandle)
- {
- mHandle = ::FindFirstFileW((PathToOS(mName) + "\\*").utf16(), &info);
- if (mHandle == NULL)
- {
- _updateStatus();
- return false;
- }
- }
- else
- if (!::FindNextFileW((HANDLE)mHandle, &info))
- {
- _updateStatus();
- return false;
- }
- // Skip "." and ".." entries
- if (info.cFileName[0] == '.' && (info.cFileName[1] == '\0' ||
- (info.cFileName[1] == '.' && info.cFileName[2] == '\0')))
- return read(entry);
- _CopyStatAttributes(info,entry);
- entry->name = info.cFileName;
- return true;
- }
- U32 Win32Directory::calculateChecksum()
- {
- // Return checksum of current entry
- return 0;
- }
- bool Win32Directory::getAttributes(Attributes* attr)
- {
- WIN32_FIND_DATA info;
- HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info);
- ::FindClose(handle);
- if (handle == INVALID_HANDLE_VALUE)
- {
- _updateStatus();
- return false;
- }
- _CopyStatAttributes(info,attr);
- attr->name = mPath;
- return true;
- }
- FileNode::NodeStatus Win32Directory::getStatus() const
- {
- return mStatus;
- }
- void Win32Directory::_updateStatus()
- {
- switch (::GetLastError())
- {
- case ERROR_NO_MORE_FILES: mStatus = EndOfFile; break;
- case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break;
- case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break;
- case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break;
- case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break;
- default: mStatus = UnknownError; break;
- }
- }
- } // Namespace Win32
- bool FS::VerifyWriteAccess(const Path &path)
- {
- // due to UAC's habit of creating "virtual stores" when permission isn't actually available
- // actually create, write, read, verify, and delete a file to the folder being tested
- String temp = path.getFullPath();
- temp += "\\torque_writetest.tmp";
- // first, (try and) delete the file if it exists
- ::DeleteFileW(temp.utf16());
- // now, create the file
- HANDLE hFile = ::CreateFileW(PathToOS(temp).utf16(),
- GENERIC_WRITE, 0,
- NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
- NULL);
- if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL )
- return false;
- U32 t = Platform::getTime();
- DWORD bytesWritten;
- if (!::WriteFile(hFile,&t,sizeof(t),&bytesWritten,0))
- {
- ::CloseHandle(hFile);
- ::DeleteFileW(temp.utf16());
- return false;
- }
- // close the file
- ::CloseHandle(hFile);
- // open for read
- hFile = ::CreateFileW(PathToOS(temp).utf16(),
- GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
- NULL);
- if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL )
- return false;
- U32 t2 = 0;
- DWORD bytesRead;
- if (!::ReadFile(hFile,&t2,sizeof(t2),&bytesRead,0))
- {
- ::CloseHandle(hFile);
- ::DeleteFileW(temp.utf16());
- return false;
- }
- ::CloseHandle(hFile);
- ::DeleteFileW(temp.utf16());
- return t == t2;
- }
- } // Namespace Torque
- //-----------------------------------------------------------------------------
- Torque::FS::FileSystemRef Platform::FS::createNativeFS( const String &volume )
- {
- return new Win32::Win32FileSystem( volume );
- }
- String Platform::FS::getAssetDir()
- {
- char cen_buf[2048];
- #ifdef TORQUE_UNICODE
- if (!Platform::getWebDeployment())
- {
- TCHAR buf[ 2048 ];
- ::GetModuleFileNameW( NULL, buf, sizeof( buf ) );
- convertUTF16toUTF8( buf, cen_buf );
- }
- else
- {
- TCHAR buf[ 2048 ];
- GetCurrentDirectoryW( sizeof( buf ) / sizeof( buf[ 0 ] ), buf );
- convertUTF16toUTF8( buf, cen_buf );
- return Path::CleanSeparators(cen_buf);
- }
- #else
- ::GetModuleFileNameA( NULL, cen_buf, 2047);
- #endif
- char *delimiter = dStrrchr( cen_buf, '\\' );
- if( delimiter != NULL )
- *delimiter = '\0';
- return Path::CleanSeparators(cen_buf);
- }
- /// Function invoked by the kernel layer to install OS specific
- /// file systems.
- bool Platform::FS::InstallFileSystems()
- {
- #ifndef TORQUE_SECURE_VFS
- WCHAR buffer[1024];
- // [8/24/2009 tomb] This stops Windows from complaining about drives that have no disks in
- SetErrorMode(SEM_FAILCRITICALERRORS);
- // Load all the Win32 logical drives.
- DWORD mask = ::GetLogicalDrives();
- char drive[] = "A";
- char volume[] = "A:/";
- while (mask)
- {
- if (mask & 1)
- {
- volume[0] = drive[0];
- Platform::FS::Mount(drive, Platform::FS::createNativeFS(volume));
- }
- mask >>= 1;
- drive[0]++;
- }
- // Set the current working dir. Windows normally returns
- // upper case driver letters, but the cygwin bash shell
- // seems to make it return lower case drives. Force upper
- // to be consistent with the mounts.
- ::GetCurrentDirectory(sizeof(buffer), buffer);
- if (buffer[1] == ':')
- buffer[0] = dToupper(buffer[0]);
- String wd = buffer;
-
- wd += '/';
- Platform::FS::SetCwd(wd);
- #endif
- return true;
- }
|