winVolume.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  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. if (path.getFileName().isEmpty() && path.getExtension().isNotEmpty()) //weird, filename-less file, so handle it slightly special-case
  75. file += String("/");
  76. else
  77. file = Path::Join(file, '/', path.getFileName());
  78. file = Path::Join(file, '.', path.getExtension());
  79. return file;
  80. }
  81. /*
  82. static bool _IsFile(const String& file)
  83. {
  84. // Get file info
  85. WIN32_FIND_DATA info;
  86. HANDLE handle = ::FindFirstFile(PathToOS(file).utf16(), &info);
  87. ::FindClose(handle);
  88. if (handle == INVALID_HANDLE_VALUE)
  89. return false;
  90. return S_ISREG(info.dwFileAttributes);
  91. }
  92. */
  93. static bool _IsDirectory(const String& file)
  94. {
  95. // Get file info
  96. WIN32_FIND_DATAW info;
  97. HANDLE handle = ::FindFirstFileW(PathToOS(file).utf16(), &info);
  98. ::FindClose(handle);
  99. if (handle == INVALID_HANDLE_VALUE)
  100. return false;
  101. return S_ISDIR(info.dwFileAttributes);
  102. }
  103. //-----------------------------------------------------------------------------
  104. static void _CopyStatAttributes(const WIN32_FIND_DATAW& info, FileNode::Attributes* attr)
  105. {
  106. // Fill in the return struct.
  107. attr->flags = 0;
  108. if (S_ISDIR(info.dwFileAttributes))
  109. attr->flags |= FileNode::Directory;
  110. if (S_ISREG(info.dwFileAttributes))
  111. attr->flags |= FileNode::File;
  112. if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  113. attr->flags |= FileNode::ReadOnly;
  114. attr->size = info.nFileSizeLow;
  115. attr->mtime = Win32FileTimeToTime(
  116. info.ftLastWriteTime.dwLowDateTime,
  117. info.ftLastWriteTime.dwHighDateTime);
  118. attr->atime = Win32FileTimeToTime(
  119. info.ftLastAccessTime.dwLowDateTime,
  120. info.ftLastAccessTime.dwHighDateTime);
  121. attr->ctime = Win32FileTimeToTime(
  122. info.ftCreationTime.dwLowDateTime,
  123. info.ftCreationTime.dwHighDateTime);
  124. }
  125. //-----------------------------------------------------------------------------
  126. bool Win32FileSystemChangeNotifier::internalAddNotification( const Path &dir )
  127. {
  128. for ( U32 i = 0; i < mDirs.size(); ++i )
  129. {
  130. if ( mDirs[i] == dir )
  131. return false;
  132. }
  133. Path fullFSPath = mFS->mapTo( dir );
  134. String osPath = PathToOS( fullFSPath );
  135. // Con::printf( "[Win32FileSystemChangeNotifier::internalAddNotification] : [%s]", osPath.c_str() );
  136. HANDLE changeHandle = ::FindFirstChangeNotificationW(
  137. osPath.utf16(), // directory to watch
  138. FALSE, // do not watch subtree
  139. FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES); // watch file write changes
  140. if (changeHandle == INVALID_HANDLE_VALUE || changeHandle == NULL)
  141. {
  142. Con::errorf("[Win32FileSystemChangeNotifier::internalAddNotification] : failed on [%s] [%d]", osPath.c_str(), GetLastError());
  143. return false;
  144. }
  145. mDirs.push_back( dir );
  146. mHandleList.push_back( changeHandle );
  147. return true;
  148. }
  149. bool Win32FileSystemChangeNotifier::internalRemoveNotification( const Path &dir )
  150. {
  151. for ( U32 i = 0; i < mDirs.size(); ++i )
  152. {
  153. if ( mDirs[i] != dir )
  154. continue;
  155. ::FindCloseChangeNotification( mHandleList[i] );
  156. mDirs.erase( i );
  157. mHandleList.erase( i );
  158. return true;
  159. }
  160. return false;
  161. }
  162. void Win32FileSystemChangeNotifier::internalProcessOnce()
  163. {
  164. // WaitForMultipleObjects has a limit of MAXIMUM_WAIT_OBJECTS (64 at
  165. // the moment), so we have to loop till we've handled the entire set.
  166. for ( U32 i=0; i < mHandleList.size(); i += MAXIMUM_WAIT_OBJECTS )
  167. {
  168. U32 numHandles = getMin( (U32)MAXIMUM_WAIT_OBJECTS, (U32)mHandleList.size() - i );
  169. DWORD dwWaitStatus = WaitForMultipleObjects( numHandles, mHandleList.address()+i, FALSE, 0);
  170. if ( dwWaitStatus == WAIT_FAILED || dwWaitStatus == WAIT_TIMEOUT )
  171. continue;
  172. if ( dwWaitStatus >= WAIT_OBJECT_0 && dwWaitStatus <= (WAIT_OBJECT_0 + numHandles - 1))
  173. {
  174. U32 index = i + dwWaitStatus;
  175. // reset our notification
  176. // NOTE: we do this before letting the volume system check mod times so we don't miss any.
  177. // It is going to loop over the files and check their mod time vs. the saved time.
  178. // This may result in extra calls to internalNotifyDirChanged(), but it will simpley check mod times again.
  179. ::FindNextChangeNotification( mHandleList[index] );
  180. internalNotifyDirChanged( mDirs[index] );
  181. }
  182. }
  183. }
  184. //-----------------------------------------------------------------------------
  185. Win32FileSystem::Win32FileSystem(String volume)
  186. {
  187. mVolume = volume;
  188. mChangeNotifier = new Win32FileSystemChangeNotifier( this );
  189. }
  190. Win32FileSystem::~Win32FileSystem()
  191. {
  192. }
  193. void Win32FileSystem::verifyCompatibility(const Path& _path, WIN32_FIND_DATAW _info)
  194. {
  195. #ifndef TORQUE_POSIX_PATH_CASE_INSENSITIVE
  196. if (_path.getFullFileName().isNotEmpty() && _path.getFullFileName().compare(String(_info.cFileName)) != 0)
  197. {
  198. Con::warnf("Linux Compatibility Warning: %s != %s", String(_info.cFileName).c_str(), _path.getFullFileName().c_str());
  199. }
  200. #endif
  201. }
  202. FileNodeRef Win32FileSystem::resolve(const Path& path)
  203. {
  204. String file = _BuildFileName(mVolume,path);
  205. WIN32_FIND_DATAW info;
  206. HANDLE handle = ::FindFirstFileW(PathToOS(file).utf16(), &info);
  207. ::FindClose(handle);
  208. if (handle != INVALID_HANDLE_VALUE)
  209. {
  210. #ifdef TORQUE_DEBUG
  211. verifyCompatibility(path, info);
  212. #endif
  213. if (S_ISREG(info.dwFileAttributes))
  214. return new Win32File(path,file);
  215. if (S_ISDIR(info.dwFileAttributes))
  216. return new Win32Directory(path,file);
  217. }
  218. return 0;
  219. }
  220. FileNodeRef Win32FileSystem::create(const Path& path, FileNode::Mode mode)
  221. {
  222. // The file will be created on disk when it's opened.
  223. if (mode & FileNode::File)
  224. return new Win32File(path,_BuildFileName(mVolume,path));
  225. // Create with default permissions.
  226. if (mode & FileNode::Directory)
  227. {
  228. String file = PathToOS(_BuildFileName(mVolume,path));
  229. if (::CreateDirectoryW(file.utf16(), 0))
  230. return new Win32Directory(path, file);
  231. }
  232. return 0;
  233. }
  234. bool Win32FileSystem::remove(const Path& path)
  235. {
  236. // Should probably check for outstanding files or directory objects.
  237. String file = PathToOS(_BuildFileName(mVolume,path));
  238. WIN32_FIND_DATAW info;
  239. HANDLE handle = ::FindFirstFileW(file.utf16(), &info);
  240. ::FindClose(handle);
  241. if (handle == INVALID_HANDLE_VALUE)
  242. return false;
  243. if (S_ISDIR(info.dwFileAttributes))
  244. return ::RemoveDirectoryW(file.utf16());
  245. return ::DeleteFileW(file.utf16());
  246. }
  247. bool Win32FileSystem::rename(const Path& from,const Path& to)
  248. {
  249. String fa = PathToOS(_BuildFileName(mVolume,from));
  250. String fb = PathToOS(_BuildFileName(mVolume,to));
  251. return MoveFile(fa.utf16(),fb.utf16());
  252. }
  253. Path Win32FileSystem::mapTo(const Path& path)
  254. {
  255. return _BuildFileName(mVolume,path);
  256. }
  257. Path Win32FileSystem::mapFrom(const Path& path)
  258. {
  259. const String::SizeType volumePathLen = mVolume.length();
  260. String pathStr = path.getFullPath();
  261. if ( mVolume.compare( pathStr, volumePathLen, String::NoCase ))
  262. return Path();
  263. return pathStr.substr( volumePathLen, pathStr.length() - volumePathLen );
  264. }
  265. //-----------------------------------------------------------------------------
  266. Win32File::Win32File(const Path& path,String name)
  267. {
  268. mPath = path;
  269. mName = name;
  270. mStatus = Closed;
  271. mHandle = 0;
  272. }
  273. Win32File::~Win32File()
  274. {
  275. if (mHandle)
  276. close();
  277. }
  278. Path Win32File::getName() const
  279. {
  280. return mPath;
  281. }
  282. FileNode::NodeStatus Win32File::getStatus() const
  283. {
  284. return mStatus;
  285. }
  286. bool Win32File::getAttributes(Attributes* attr)
  287. {
  288. WIN32_FIND_DATAW info;
  289. HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info);
  290. ::FindClose(handle);
  291. if (handle == INVALID_HANDLE_VALUE)
  292. return false;
  293. _CopyStatAttributes(info,attr);
  294. attr->name = mPath;
  295. return true;
  296. }
  297. U64 Win32File::getSize()
  298. {
  299. U64 size;
  300. if (mStatus == Open)
  301. {
  302. // Special case if file is open (handles unflushed buffers)
  303. if ( !GetFileSizeEx(mHandle, (PLARGE_INTEGER)&size) )
  304. size = 0;
  305. return size;
  306. }
  307. else
  308. {
  309. // Fallback to generic function
  310. size = File::getSize();
  311. }
  312. return size;
  313. }
  314. U32 Win32File::calculateChecksum()
  315. {
  316. if (!open( Read ))
  317. return 0;
  318. U64 fileSize = getSize();
  319. U32 bufSize = 1024 * 1024 * 4; // 4MB
  320. FrameTemp<U8> buf( bufSize );
  321. U32 crc = CRC::INITIAL_CRC_VALUE;
  322. while ( fileSize > 0 )
  323. {
  324. U32 bytesRead = getMin( fileSize, bufSize );
  325. if ( read( buf, bytesRead ) != bytesRead )
  326. {
  327. close();
  328. return 0;
  329. }
  330. fileSize -= bytesRead;
  331. crc = CRC::calculateCRC(buf, bytesRead, crc);
  332. }
  333. close();
  334. return crc;
  335. }
  336. bool Win32File::open(AccessMode mode)
  337. {
  338. close();
  339. if (mName.isEmpty())
  340. return mStatus;
  341. struct Mode
  342. {
  343. DWORD mode,share,open;
  344. } Modes[] =
  345. {
  346. { GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING }, // Read
  347. { GENERIC_WRITE,0,CREATE_ALWAYS }, // Write
  348. { GENERIC_WRITE | GENERIC_READ,0,OPEN_ALWAYS }, // ReadWrite
  349. { GENERIC_WRITE,0,OPEN_ALWAYS } // WriteAppend
  350. };
  351. Mode& m = (mode == Read)? Modes[0]: (mode == Write)? Modes[1]:
  352. (mode == ReadWrite)? Modes[2]: Modes[3];
  353. mHandle = (void*)::CreateFileW(PathToOS(mName).utf16(),
  354. m.mode, m.share,
  355. NULL, m.open,
  356. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  357. NULL);
  358. if ( mHandle == INVALID_HANDLE_VALUE || mHandle == NULL )
  359. {
  360. _updateStatus();
  361. return false;
  362. }
  363. mStatus = Open;
  364. return true;
  365. }
  366. bool Win32File::close()
  367. {
  368. if (mHandle)
  369. {
  370. ::CloseHandle((HANDLE)mHandle);
  371. mHandle = 0;
  372. }
  373. mStatus = Closed;
  374. return true;
  375. }
  376. U32 Win32File::getPosition()
  377. {
  378. if (mStatus == Open || mStatus == EndOfFile)
  379. return ::SetFilePointer((HANDLE)mHandle,0,0,FILE_CURRENT);
  380. return 0;
  381. }
  382. U32 Win32File::setPosition(U32 delta, SeekMode mode)
  383. {
  384. if (mStatus != Open && mStatus != EndOfFile)
  385. return 0;
  386. DWORD fmode;
  387. switch (mode)
  388. {
  389. case Begin: fmode = FILE_BEGIN; break;
  390. case Current: fmode = FILE_CURRENT; break;
  391. case End: fmode = FILE_END; break;
  392. default: fmode = 0; break;
  393. }
  394. DWORD pos = ::SetFilePointer((HANDLE)mHandle,delta,0,fmode);
  395. if (pos == INVALID_SET_FILE_POINTER)
  396. {
  397. mStatus = UnknownError;
  398. return 0;
  399. }
  400. mStatus = Open;
  401. return pos;
  402. }
  403. U32 Win32File::read(void* dst, U32 size)
  404. {
  405. if (mStatus != Open && mStatus != EndOfFile)
  406. return 0;
  407. DWORD bytesRead;
  408. if (!::ReadFile((HANDLE)mHandle,dst,size,&bytesRead,0))
  409. _updateStatus();
  410. else if (bytesRead != size)
  411. mStatus = EndOfFile;
  412. return bytesRead;
  413. }
  414. U32 Win32File::write(const void* src, U32 size)
  415. {
  416. if ((mStatus != Open && mStatus != EndOfFile) || !size)
  417. return 0;
  418. DWORD bytesWritten;
  419. if (!::WriteFile((HANDLE)mHandle,src,size,&bytesWritten,0))
  420. _updateStatus();
  421. return bytesWritten;
  422. }
  423. void Win32File::_updateStatus()
  424. {
  425. switch (::GetLastError())
  426. {
  427. case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break;
  428. case ERROR_TOO_MANY_OPEN_FILES: mStatus = UnknownError; break;
  429. case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break;
  430. case ERROR_FILE_NOT_FOUND: mStatus = NoSuchFile; break;
  431. case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break;
  432. case ERROR_HANDLE_DISK_FULL: mStatus = FileSystemFull; break;
  433. case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break;
  434. default: mStatus = UnknownError; break;
  435. }
  436. }
  437. //-----------------------------------------------------------------------------
  438. Win32Directory::Win32Directory(const Path& path,String name)
  439. {
  440. mPath = path;
  441. mName = name;
  442. mStatus = Closed;
  443. mHandle = 0;
  444. }
  445. Win32Directory::~Win32Directory()
  446. {
  447. if (mHandle)
  448. close();
  449. }
  450. Path Win32Directory::getName() const
  451. {
  452. return mPath;
  453. }
  454. bool Win32Directory::open()
  455. {
  456. if (!_IsDirectory(mName))
  457. {
  458. mStatus = NoSuchFile;
  459. return false;
  460. }
  461. mStatus = Open;
  462. return true;
  463. }
  464. bool Win32Directory::close()
  465. {
  466. if (mHandle)
  467. {
  468. ::FindClose((HANDLE)mHandle);
  469. mHandle = 0;
  470. return true;
  471. }
  472. return false;
  473. }
  474. bool Win32Directory::read(Attributes* entry)
  475. {
  476. if (mStatus != Open)
  477. return false;
  478. WIN32_FIND_DATA info;
  479. if (!mHandle)
  480. {
  481. mHandle = ::FindFirstFileW((PathToOS(mName) + "\\*").utf16(), &info);
  482. if (mHandle == NULL)
  483. {
  484. _updateStatus();
  485. return false;
  486. }
  487. }
  488. else
  489. if (!::FindNextFileW((HANDLE)mHandle, &info))
  490. {
  491. _updateStatus();
  492. return false;
  493. }
  494. // Skip "." and ".." entries
  495. if (info.cFileName[0] == '.' && (info.cFileName[1] == '\0' ||
  496. (info.cFileName[1] == '.' && info.cFileName[2] == '\0')))
  497. return read(entry);
  498. _CopyStatAttributes(info,entry);
  499. entry->name = info.cFileName;
  500. return true;
  501. }
  502. U32 Win32Directory::calculateChecksum()
  503. {
  504. // Return checksum of current entry
  505. return 0;
  506. }
  507. bool Win32Directory::getAttributes(Attributes* attr)
  508. {
  509. WIN32_FIND_DATA info;
  510. HANDLE handle = ::FindFirstFileW(PathToOS(mName).utf16(), &info);
  511. ::FindClose(handle);
  512. if (handle == INVALID_HANDLE_VALUE)
  513. {
  514. _updateStatus();
  515. return false;
  516. }
  517. _CopyStatAttributes(info,attr);
  518. attr->name = mPath;
  519. return true;
  520. }
  521. FileNode::NodeStatus Win32Directory::getStatus() const
  522. {
  523. return mStatus;
  524. }
  525. void Win32Directory::_updateStatus()
  526. {
  527. switch (::GetLastError())
  528. {
  529. case ERROR_NO_MORE_FILES: mStatus = EndOfFile; break;
  530. case ERROR_INVALID_ACCESS: mStatus = AccessDenied; break;
  531. case ERROR_PATH_NOT_FOUND: mStatus = NoSuchFile; break;
  532. case ERROR_SHARING_VIOLATION: mStatus = SharingViolation; break;
  533. case ERROR_ACCESS_DENIED: mStatus = AccessDenied; break;
  534. default: mStatus = UnknownError; break;
  535. }
  536. }
  537. } // Namespace Win32
  538. bool FS::VerifyWriteAccess(const Path &path)
  539. {
  540. // due to UAC's habit of creating "virtual stores" when permission isn't actually available
  541. // actually create, write, read, verify, and delete a file to the folder being tested
  542. String temp = path.getFullPath();
  543. temp += "\\torque_writetest.tmp";
  544. // first, (try and) delete the file if it exists
  545. ::DeleteFileW(temp.utf16());
  546. // now, create the file
  547. HANDLE hFile = ::CreateFileW(PathToOS(temp).utf16(),
  548. GENERIC_WRITE, 0,
  549. NULL, CREATE_ALWAYS,
  550. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  551. NULL);
  552. if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL )
  553. return false;
  554. U32 t = Platform::getTime();
  555. DWORD bytesWritten;
  556. if (!::WriteFile(hFile,&t,sizeof(t),&bytesWritten,0))
  557. {
  558. ::CloseHandle(hFile);
  559. ::DeleteFileW(temp.utf16());
  560. return false;
  561. }
  562. // close the file
  563. ::CloseHandle(hFile);
  564. // open for read
  565. hFile = ::CreateFileW(PathToOS(temp).utf16(),
  566. GENERIC_READ, FILE_SHARE_READ,
  567. NULL, OPEN_EXISTING,
  568. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  569. NULL);
  570. if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL )
  571. return false;
  572. U32 t2 = 0;
  573. DWORD bytesRead;
  574. if (!::ReadFile(hFile,&t2,sizeof(t2),&bytesRead,0))
  575. {
  576. ::CloseHandle(hFile);
  577. ::DeleteFileW(temp.utf16());
  578. return false;
  579. }
  580. ::CloseHandle(hFile);
  581. ::DeleteFileW(temp.utf16());
  582. return t == t2;
  583. }
  584. } // Namespace Torque
  585. //-----------------------------------------------------------------------------
  586. Torque::FS::FileSystemRef Platform::FS::createNativeFS( const String &volume )
  587. {
  588. return new Win32::Win32FileSystem( volume );
  589. }
  590. String Platform::FS::getAssetDir()
  591. {
  592. char cen_buf[2048];
  593. #ifdef TORQUE_UNICODE
  594. if (!Platform::getWebDeployment())
  595. {
  596. TCHAR buf[ 2048 ];
  597. ::GetModuleFileNameW( NULL, buf, sizeof( buf ) );
  598. convertUTF16toUTF8( buf, cen_buf );
  599. }
  600. else
  601. {
  602. TCHAR buf[ 2048 ];
  603. GetCurrentDirectoryW( sizeof( buf ) / sizeof( buf[ 0 ] ), buf );
  604. convertUTF16toUTF8( buf, cen_buf );
  605. return Path::CleanSeparators(cen_buf);
  606. }
  607. #else
  608. ::GetModuleFileNameA( NULL, cen_buf, 2047);
  609. #endif
  610. char *delimiter = dStrrchr( cen_buf, '\\' );
  611. if( delimiter != NULL )
  612. *delimiter = '\0';
  613. return Path::CleanSeparators(cen_buf);
  614. }
  615. /// Function invoked by the kernel layer to install OS specific
  616. /// file systems.
  617. bool Platform::FS::InstallFileSystems()
  618. {
  619. #ifndef TORQUE_SECURE_VFS
  620. WCHAR buffer[1024];
  621. // [8/24/2009 tomb] This stops Windows from complaining about drives that have no disks in
  622. SetErrorMode(SEM_FAILCRITICALERRORS);
  623. // Load all the Win32 logical drives.
  624. DWORD mask = ::GetLogicalDrives();
  625. char drive[] = "A";
  626. char volume[] = "A:/";
  627. while (mask)
  628. {
  629. if (mask & 1)
  630. {
  631. volume[0] = drive[0];
  632. Platform::FS::Mount(drive, Platform::FS::createNativeFS(volume));
  633. }
  634. mask >>= 1;
  635. drive[0]++;
  636. }
  637. // Set the current working dir. Windows normally returns
  638. // upper case driver letters, but the cygwin bash shell
  639. // seems to make it return lower case drives. Force upper
  640. // to be consistent with the mounts.
  641. ::GetCurrentDirectory(sizeof(buffer), buffer);
  642. if (buffer[1] == ':')
  643. buffer[0] = dToupper(buffer[0]);
  644. String wd = buffer;
  645. wd += '/';
  646. Platform::FS::SetCwd(wd);
  647. #endif
  648. return true;
  649. }