winVolume.cpp 20 KB

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