winVolume.cpp 20 KB

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