winVolume.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  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. void Win32FileSystem::verifyCompatibility(const Path& _path, WIN32_FIND_DATAW _info)
  188. {
  189. #ifndef TORQUE_POSIX_PATH_CASE_INSENSITIVE
  190. if (_path.getFullFileName().isNotEmpty() && _path.getFullFileName().compare(String(_info.cFileName)) != 0)
  191. {
  192. Con::warnf("Linux Compatibility Warning: %s != %s", String(_info.cFileName).c_str(), _path.getFullFileName().c_str());
  193. }
  194. #endif
  195. }
  196. FileNodeRef Win32FileSystem::resolve(const Path& path)
  197. {
  198. String file = _BuildFileName(mVolume,path);
  199. WIN32_FIND_DATAW info;
  200. HANDLE handle = ::FindFirstFileW(PathToOS(file).utf16(), &info);
  201. ::FindClose(handle);
  202. if (handle != INVALID_HANDLE_VALUE)
  203. {
  204. #ifdef TORQUE_DEBUG
  205. verifyCompatibility(path, info);
  206. #endif
  207. if (S_ISREG(info.dwFileAttributes))
  208. return new Win32File(path,file);
  209. if (S_ISDIR(info.dwFileAttributes))
  210. return new Win32Directory(path,file);
  211. }
  212. return 0;
  213. }
  214. FileNodeRef Win32FileSystem::create(const Path& path, FileNode::Mode mode)
  215. {
  216. // The file will be created on disk when it's opened.
  217. if (mode & FileNode::File)
  218. return new Win32File(path,_BuildFileName(mVolume,path));
  219. // Create with default permissions.
  220. if (mode & FileNode::Directory)
  221. {
  222. String file = PathToOS(_BuildFileName(mVolume,path));
  223. if (::CreateDirectoryW(file.utf16(), 0))
  224. return new Win32Directory(path, file);
  225. }
  226. return 0;
  227. }
  228. bool Win32FileSystem::remove(const Path& path)
  229. {
  230. // Should probably check for outstanding files or directory objects.
  231. String file = PathToOS(_BuildFileName(mVolume,path));
  232. WIN32_FIND_DATAW info;
  233. HANDLE handle = ::FindFirstFileW(file.utf16(), &info);
  234. ::FindClose(handle);
  235. if (handle == INVALID_HANDLE_VALUE)
  236. return false;
  237. if (S_ISDIR(info.dwFileAttributes))
  238. return ::RemoveDirectoryW(file.utf16());
  239. return ::DeleteFileW(file.utf16());
  240. }
  241. bool Win32FileSystem::rename(const Path& from,const Path& to)
  242. {
  243. String fa = PathToOS(_BuildFileName(mVolume,from));
  244. String fb = PathToOS(_BuildFileName(mVolume,to));
  245. return MoveFile(fa.utf16(),fb.utf16());
  246. }
  247. Path Win32FileSystem::mapTo(const Path& path)
  248. {
  249. return _BuildFileName(mVolume,path);
  250. }
  251. Path Win32FileSystem::mapFrom(const Path& path)
  252. {
  253. const String::SizeType volumePathLen = mVolume.length();
  254. String pathStr = path.getFullPath();
  255. if ( mVolume.compare( pathStr, volumePathLen, String::NoCase ))
  256. return Path();
  257. return pathStr.substr( volumePathLen, pathStr.length() - volumePathLen );
  258. }
  259. //-----------------------------------------------------------------------------
  260. Win32File::Win32File(const Path& path,String name)
  261. {
  262. mPath = path;
  263. mName = name;
  264. mStatus = Closed;
  265. mHandle = 0;
  266. }
  267. Win32File::~Win32File()
  268. {
  269. if (mHandle)
  270. close();
  271. }
  272. Path Win32File::getName() const
  273. {
  274. return mPath;
  275. }
  276. FileNode::NodeStatus Win32File::getStatus() const
  277. {
  278. return mStatus;
  279. }
  280. bool Win32File::getAttributes(Attributes* attr)
  281. {
  282. WIN32_FIND_DATAW info;
  283. HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info);
  284. ::FindClose(handle);
  285. if (handle == INVALID_HANDLE_VALUE)
  286. return false;
  287. _CopyStatAttributes(info,attr);
  288. attr->name = mPath;
  289. return true;
  290. }
  291. U64 Win32File::getSize()
  292. {
  293. U64 size;
  294. if (mStatus == Open)
  295. {
  296. // Special case if file is open (handles unflushed buffers)
  297. if ( !GetFileSizeEx(mHandle, (PLARGE_INTEGER)&size) )
  298. size = 0;
  299. return size;
  300. }
  301. else
  302. {
  303. // Fallback to generic function
  304. size = File::getSize();
  305. }
  306. return size;
  307. }
  308. U32 Win32File::calculateChecksum()
  309. {
  310. if (!open( Read ))
  311. return 0;
  312. U64 fileSize = getSize();
  313. U32 bufSize = 1024 * 1024 * 4; // 4MB
  314. FrameTemp<U8> buf( bufSize );
  315. U32 crc = CRC::INITIAL_CRC_VALUE;
  316. while ( fileSize > 0 )
  317. {
  318. U32 bytesRead = getMin( fileSize, bufSize );
  319. if ( read( buf, bytesRead ) != bytesRead )
  320. {
  321. close();
  322. return 0;
  323. }
  324. fileSize -= bytesRead;
  325. crc = CRC::calculateCRC(buf, bytesRead, crc);
  326. }
  327. close();
  328. return crc;
  329. }
  330. bool Win32File::open(AccessMode mode)
  331. {
  332. close();
  333. if (mName.isEmpty())
  334. return mStatus;
  335. struct Mode
  336. {
  337. DWORD mode,share,open;
  338. } Modes[] =
  339. {
  340. { GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING }, // Read
  341. { GENERIC_WRITE,0,CREATE_ALWAYS }, // Write
  342. { GENERIC_WRITE | GENERIC_READ,0,OPEN_ALWAYS }, // ReadWrite
  343. { GENERIC_WRITE,0,OPEN_ALWAYS } // WriteAppend
  344. };
  345. Mode& m = (mode == Read)? Modes[0]: (mode == Write)? Modes[1]:
  346. (mode == ReadWrite)? Modes[2]: Modes[3];
  347. mHandle = (void*)::CreateFileW(PathToOS(mName).utf16(),
  348. m.mode, m.share,
  349. NULL, m.open,
  350. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  351. NULL);
  352. if ( mHandle == INVALID_HANDLE_VALUE || mHandle == NULL )
  353. {
  354. _updateStatus();
  355. return false;
  356. }
  357. mStatus = Open;
  358. return true;
  359. }
  360. bool Win32File::close()
  361. {
  362. if (mHandle)
  363. {
  364. ::CloseHandle((HANDLE)mHandle);
  365. mHandle = 0;
  366. }
  367. mStatus = Closed;
  368. return true;
  369. }
  370. U32 Win32File::getPosition()
  371. {
  372. if (mStatus == Open || mStatus == EndOfFile)
  373. return ::SetFilePointer((HANDLE)mHandle,0,0,FILE_CURRENT);
  374. return 0;
  375. }
  376. U32 Win32File::setPosition(U32 delta, SeekMode mode)
  377. {
  378. if (mStatus != Open && mStatus != EndOfFile)
  379. return 0;
  380. DWORD fmode;
  381. switch (mode)
  382. {
  383. case Begin: fmode = FILE_BEGIN; break;
  384. case Current: fmode = FILE_CURRENT; break;
  385. case End: fmode = FILE_END; break;
  386. default: fmode = 0; break;
  387. }
  388. DWORD pos = ::SetFilePointer((HANDLE)mHandle,delta,0,fmode);
  389. if (pos == INVALID_SET_FILE_POINTER)
  390. {
  391. mStatus = UnknownError;
  392. return 0;
  393. }
  394. mStatus = Open;
  395. return pos;
  396. }
  397. U32 Win32File::read(void* dst, U32 size)
  398. {
  399. if (mStatus != Open && mStatus != EndOfFile)
  400. return 0;
  401. DWORD bytesRead;
  402. if (!::ReadFile((HANDLE)mHandle,dst,size,&bytesRead,0))
  403. _updateStatus();
  404. else if (bytesRead != size)
  405. mStatus = EndOfFile;
  406. return bytesRead;
  407. }
  408. U32 Win32File::write(const void* src, U32 size)
  409. {
  410. if ((mStatus != Open && mStatus != EndOfFile) || !size)
  411. return 0;
  412. DWORD bytesWritten;
  413. if (!::WriteFile((HANDLE)mHandle,src,size,&bytesWritten,0))
  414. _updateStatus();
  415. return bytesWritten;
  416. }
  417. void Win32File::_updateStatus()
  418. {
  419. switch (::GetLastError())
  420. {
  421. case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break;
  422. case ERROR_TOO_MANY_OPEN_FILES: mStatus = UnknownError; break;
  423. case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break;
  424. case ERROR_FILE_NOT_FOUND: mStatus = NoSuchFile; break;
  425. case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break;
  426. case ERROR_HANDLE_DISK_FULL: mStatus = FileSystemFull; break;
  427. case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break;
  428. default: mStatus = UnknownError; break;
  429. }
  430. }
  431. //-----------------------------------------------------------------------------
  432. Win32Directory::Win32Directory(const Path& path,String name)
  433. {
  434. mPath = path;
  435. mName = name;
  436. mStatus = Closed;
  437. mHandle = 0;
  438. }
  439. Win32Directory::~Win32Directory()
  440. {
  441. if (mHandle)
  442. close();
  443. }
  444. Path Win32Directory::getName() const
  445. {
  446. return mPath;
  447. }
  448. bool Win32Directory::open()
  449. {
  450. if (!_IsDirectory(mName))
  451. {
  452. mStatus = NoSuchFile;
  453. return false;
  454. }
  455. mStatus = Open;
  456. return true;
  457. }
  458. bool Win32Directory::close()
  459. {
  460. if (mHandle)
  461. {
  462. ::FindClose((HANDLE)mHandle);
  463. mHandle = 0;
  464. return true;
  465. }
  466. return false;
  467. }
  468. bool Win32Directory::read(Attributes* entry)
  469. {
  470. if (mStatus != Open)
  471. return false;
  472. WIN32_FIND_DATA info;
  473. if (!mHandle)
  474. {
  475. mHandle = ::FindFirstFileW((PathToOS(mName) + "\\*").utf16(), &info);
  476. if (mHandle == NULL)
  477. {
  478. _updateStatus();
  479. return false;
  480. }
  481. }
  482. else
  483. if (!::FindNextFileW((HANDLE)mHandle, &info))
  484. {
  485. _updateStatus();
  486. return false;
  487. }
  488. // Skip "." and ".." entries
  489. if (info.cFileName[0] == '.' && (info.cFileName[1] == '\0' ||
  490. (info.cFileName[1] == '.' && info.cFileName[2] == '\0')))
  491. return read(entry);
  492. _CopyStatAttributes(info,entry);
  493. entry->name = info.cFileName;
  494. return true;
  495. }
  496. U32 Win32Directory::calculateChecksum()
  497. {
  498. // Return checksum of current entry
  499. return 0;
  500. }
  501. bool Win32Directory::getAttributes(Attributes* attr)
  502. {
  503. WIN32_FIND_DATA info;
  504. HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info);
  505. ::FindClose(handle);
  506. if (handle == INVALID_HANDLE_VALUE)
  507. {
  508. _updateStatus();
  509. return false;
  510. }
  511. _CopyStatAttributes(info,attr);
  512. attr->name = mPath;
  513. return true;
  514. }
  515. FileNode::NodeStatus Win32Directory::getStatus() const
  516. {
  517. return mStatus;
  518. }
  519. void Win32Directory::_updateStatus()
  520. {
  521. switch (::GetLastError())
  522. {
  523. case ERROR_NO_MORE_FILES: mStatus = EndOfFile; break;
  524. case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break;
  525. case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break;
  526. case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break;
  527. case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break;
  528. default: mStatus = UnknownError; break;
  529. }
  530. }
  531. } // Namespace Win32
  532. bool FS::VerifyWriteAccess(const Path &path)
  533. {
  534. // due to UAC's habit of creating "virtual stores" when permission isn't actually available
  535. // actually create, write, read, verify, and delete a file to the folder being tested
  536. String temp = path.getFullPath();
  537. temp += "\\torque_writetest.tmp";
  538. // first, (try and) delete the file if it exists
  539. ::DeleteFileW(temp.utf16());
  540. // now, create the file
  541. HANDLE hFile = ::CreateFileW(PathToOS(temp).utf16(),
  542. GENERIC_WRITE, 0,
  543. NULL, CREATE_ALWAYS,
  544. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  545. NULL);
  546. if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL )
  547. return false;
  548. U32 t = Platform::getTime();
  549. DWORD bytesWritten;
  550. if (!::WriteFile(hFile,&t,sizeof(t),&bytesWritten,0))
  551. {
  552. ::CloseHandle(hFile);
  553. ::DeleteFileW(temp.utf16());
  554. return false;
  555. }
  556. // close the file
  557. ::CloseHandle(hFile);
  558. // open for read
  559. hFile = ::CreateFileW(PathToOS(temp).utf16(),
  560. GENERIC_READ, FILE_SHARE_READ,
  561. NULL, OPEN_EXISTING,
  562. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  563. NULL);
  564. if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL )
  565. return false;
  566. U32 t2 = 0;
  567. DWORD bytesRead;
  568. if (!::ReadFile(hFile,&t2,sizeof(t2),&bytesRead,0))
  569. {
  570. ::CloseHandle(hFile);
  571. ::DeleteFileW(temp.utf16());
  572. return false;
  573. }
  574. ::CloseHandle(hFile);
  575. ::DeleteFileW(temp.utf16());
  576. return t == t2;
  577. }
  578. } // Namespace Torque
  579. //-----------------------------------------------------------------------------
  580. Torque::FS::FileSystemRef Platform::FS::createNativeFS( const String &volume )
  581. {
  582. return new Win32::Win32FileSystem( volume );
  583. }
  584. String Platform::FS::getAssetDir()
  585. {
  586. char cen_buf[2048];
  587. #ifdef TORQUE_UNICODE
  588. if (!Platform::getWebDeployment())
  589. {
  590. TCHAR buf[ 2048 ];
  591. ::GetModuleFileNameW( NULL, buf, sizeof( buf ) );
  592. convertUTF16toUTF8( buf, cen_buf );
  593. }
  594. else
  595. {
  596. TCHAR buf[ 2048 ];
  597. GetCurrentDirectoryW( sizeof( buf ) / sizeof( buf[ 0 ] ), buf );
  598. convertUTF16toUTF8( buf, cen_buf );
  599. return Path::CleanSeparators(cen_buf);
  600. }
  601. #else
  602. ::GetModuleFileNameA( NULL, cen_buf, 2047);
  603. #endif
  604. char *delimiter = dStrrchr( cen_buf, '\\' );
  605. if( delimiter != NULL )
  606. *delimiter = '\0';
  607. return Path::CleanSeparators(cen_buf);
  608. }
  609. /// Function invoked by the kernel layer to install OS specific
  610. /// file systems.
  611. bool Platform::FS::InstallFileSystems()
  612. {
  613. WCHAR buffer[1024];
  614. // [8/24/2009 tomb] This stops Windows from complaining about drives that have no disks in
  615. SetErrorMode(SEM_FAILCRITICALERRORS);
  616. // Load all the Win32 logical drives.
  617. DWORD mask = ::GetLogicalDrives();
  618. char drive[] = "A";
  619. char volume[] = "A:/";
  620. while (mask)
  621. {
  622. if (mask & 1)
  623. {
  624. volume[0] = drive[0];
  625. Platform::FS::Mount(drive, Platform::FS::createNativeFS(volume));
  626. }
  627. mask >>= 1;
  628. drive[0]++;
  629. }
  630. // Set the current working dir. Windows normally returns
  631. // upper case driver letters, but the cygwin bash shell
  632. // seems to make it return lower case drives. Force upper
  633. // to be consistent with the mounts.
  634. ::GetCurrentDirectory(sizeof(buffer), buffer);
  635. if (buffer[1] == ':')
  636. buffer[0] = dToupper(buffer[0]);
  637. String wd = buffer;
  638. wd += '/';
  639. Platform::FS::SetCwd(wd);
  640. return true;
  641. }