Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

416 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // FILEIO.CPP
  4. //
  5. // File I/O Service Routines
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. //-----------------------------------------------------------------------------
  9. // SystemTimeToString
  10. //
  11. // mm/dd/yyyy hh:mm:ss am
  12. //-----------------------------------------------------------------------------
  13. char *SystemTimeToString( SYSTEMTIME *systemTime, char *buffer, int bufferSize )
  14. {
  15. char timeString[256];
  16. char dateString[256];
  17. int length;
  18. GetDateFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "MM'/'dd'/'yyyy", dateString, sizeof( dateString ) );
  19. GetTimeFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "hh':'mm':'ss tt", timeString, sizeof( timeString ) );
  20. length = _snprintf( buffer, bufferSize, "%s %s", dateString, timeString );
  21. if ( length == -1 )
  22. buffer[bufferSize-1] = '\0';
  23. return buffer;
  24. }
  25. //-----------------------------------------------------------------------------
  26. // CompareFileTimes_NTFStoFATX
  27. //
  28. //-----------------------------------------------------------------------------
  29. int CompareFileTimes_NTFStoFATX( FILETIME* ntfsFileTime, char *ntfsTimeString, int ntfsStringSize, FILETIME* fatxFileTime, char *fatxTimeString, int fatxStringSize )
  30. {
  31. SYSTEMTIME ntfsSystemTime;
  32. SYSTEMTIME fatxSystemTime;
  33. int diff;
  34. int ntfsSeconds;
  35. int fatxSeconds;
  36. TIME_ZONE_INFORMATION tzInfo;
  37. GetTimeZoneInformation( &tzInfo );
  38. // cannot compare UTC file times directly
  39. // disjoint filesystems - xbox has a +/- 2s error
  40. // daylight savings time handling on each file system may cause problems
  41. FileTimeToSystemTime( ntfsFileTime, &ntfsSystemTime );
  42. FileTimeToSystemTime( fatxFileTime, &fatxSystemTime );
  43. // operate on local times, assumes xbox and pc are both set for same time zone and daylight saving
  44. SYSTEMTIME ntfsLocalTime;
  45. SYSTEMTIME fatxLocalTime;
  46. SystemTimeToTzSpecificLocalTime( &tzInfo, &ntfsSystemTime, &ntfsLocalTime );
  47. SystemTimeToTzSpecificLocalTime( &tzInfo, &fatxSystemTime, &fatxLocalTime );
  48. if ( ntfsTimeString )
  49. {
  50. SystemTimeToString( &ntfsLocalTime, ntfsTimeString, ntfsStringSize );
  51. }
  52. if ( fatxTimeString )
  53. {
  54. SystemTimeToString( &fatxLocalTime, fatxTimeString, fatxStringSize );
  55. }
  56. diff = ntfsLocalTime.wYear-fatxLocalTime.wYear;
  57. if ( diff )
  58. return diff;
  59. diff = ntfsLocalTime.wMonth-fatxLocalTime.wMonth;
  60. if ( diff )
  61. return diff;
  62. diff = ntfsLocalTime.wDay-fatxLocalTime.wDay;
  63. if ( diff )
  64. return diff;
  65. diff = ntfsLocalTime.wHour-fatxLocalTime.wHour;
  66. if ( diff )
  67. return diff;
  68. // allow for +/- 3s error
  69. ntfsSeconds = ntfsLocalTime.wHour*60*60 + ntfsLocalTime.wMinute*60 + ntfsLocalTime.wSecond;
  70. fatxSeconds = fatxLocalTime.wHour*60*60 + fatxLocalTime.wMinute*60 + fatxLocalTime.wSecond;
  71. diff = ntfsSeconds-fatxSeconds;
  72. if ( diff > 3 || diff < -3 )
  73. return diff;
  74. // times are considered equal
  75. return 0;
  76. }
  77. //-----------------------------------------------------------------------------
  78. // FreeTargetFileList
  79. //
  80. //-----------------------------------------------------------------------------
  81. void FreeTargetFileList( fileNode_t* pFileList )
  82. {
  83. fileNode_t *nodePtr;
  84. fileNode_t *nextPtr;
  85. if ( !pFileList )
  86. return;
  87. nodePtr = pFileList;
  88. while ( nodePtr )
  89. {
  90. nextPtr = nodePtr->nextPtr;
  91. Sys_Free( nodePtr->filename );
  92. Sys_Free( nodePtr );
  93. nodePtr = nextPtr;
  94. }
  95. }
  96. //-----------------------------------------------------------------------------
  97. // GetTargetFileList_r
  98. //
  99. //-----------------------------------------------------------------------------
  100. bool GetTargetFileList_r( char* targetPath, bool recurse, int attributes, int level, fileNode_t** pFileList )
  101. {
  102. HRESULT hr;
  103. PDM_WALK_DIR pWalkDir = NULL;
  104. DM_FILE_ATTRIBUTES fileAttr;
  105. bool valid;
  106. char filename[MAX_PATH];
  107. fileNode_t* nodePtr;
  108. bool bGetNormal;
  109. int fixedAttributes;
  110. if ( !level )
  111. *pFileList = NULL;
  112. fixedAttributes = attributes;
  113. if ( fixedAttributes & FILE_ATTRIBUTE_NORMAL )
  114. {
  115. fixedAttributes &= ~FILE_ATTRIBUTE_NORMAL;
  116. bGetNormal = true;
  117. }
  118. else
  119. bGetNormal = false;
  120. while ( 1 )
  121. {
  122. hr = DmWalkDir( &pWalkDir, targetPath, &fileAttr );
  123. if ( hr != XBDM_NOERR )
  124. break;
  125. strcpy( filename, targetPath );
  126. Sys_AddFileSeperator( filename, sizeof( filename ) );
  127. strcat( filename, fileAttr.Name );
  128. // restrict to desired attributes
  129. if ( ( bGetNormal && !fileAttr.Attributes ) || ( fileAttr.Attributes & fixedAttributes ) )
  130. {
  131. Sys_NormalizePath( filename, false );
  132. // create a new file node
  133. nodePtr = ( fileNode_t* )Sys_Alloc( sizeof( fileNode_t ) );
  134. // link it in
  135. nodePtr->filename = Sys_CopyString( filename );
  136. nodePtr->changeTime = fileAttr.ChangeTime;
  137. nodePtr->creationTime = fileAttr.CreationTime;
  138. nodePtr->sizeHigh = fileAttr.SizeHigh;
  139. nodePtr->sizeLow = fileAttr.SizeLow;
  140. nodePtr->attributes = fileAttr.Attributes;
  141. nodePtr->level = level;
  142. nodePtr->nextPtr = *pFileList;
  143. *pFileList = nodePtr;
  144. }
  145. if ( fileAttr.Attributes & FILE_ATTRIBUTE_DIRECTORY )
  146. {
  147. if ( recurse )
  148. {
  149. // descend into directory
  150. valid = GetTargetFileList_r( filename, recurse, attributes, level+1, pFileList );
  151. if ( !valid )
  152. return false;
  153. }
  154. }
  155. }
  156. DmCloseDir( pWalkDir );
  157. if ( hr != XBDM_ENDOFLIST )
  158. {
  159. // failure
  160. return false;
  161. }
  162. // ok
  163. return true;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // FileSyncEx
  167. //
  168. // -1: failure, 0: nothing, 1: synced
  169. //-----------------------------------------------------------------------------
  170. int FileSyncEx( const char* localFilename, const char* targetFilename, int fileSyncMode, bool bVerbose, bool bNoWrite )
  171. {
  172. bool copy;
  173. bool pathExist;
  174. WIN32_FILE_ATTRIBUTE_DATA localAttributes;
  175. DM_FILE_ATTRIBUTES targetAttributes;
  176. HRESULT hr;
  177. int errCode;
  178. int deltaTime;
  179. char localTimeString[256];
  180. char targetTimeString[256];
  181. if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_OFF )
  182. {
  183. return 0;
  184. }
  185. if ( !GetFileAttributesEx( localFilename, GetFileExInfoStandard, &localAttributes ) )
  186. {
  187. // failed to get the local file's attributes
  188. if ( bVerbose )
  189. {
  190. ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failure: Local file %s not available\n", localFilename );
  191. }
  192. return -1;
  193. }
  194. if ( localAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  195. {
  196. // ignore directory
  197. return 0;
  198. }
  199. if ( fileSyncMode & FSYNC_ANDEXISTSONTARGET )
  200. {
  201. hr = DmGetFileAttributes( targetFilename, &targetAttributes );
  202. if ( hr != XBDM_NOERR )
  203. {
  204. // target doesn't exist, no sync operation should commence
  205. if ( bVerbose )
  206. {
  207. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, Target file %s not available\n", targetFilename );
  208. }
  209. return 0;
  210. }
  211. }
  212. // default success, no operation
  213. errCode = 0;
  214. // default, create path and copy
  215. copy = true;
  216. pathExist = false;
  217. if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_IFNEWER )
  218. {
  219. hr = DmGetFileAttributes( targetFilename, &targetAttributes );
  220. if ( hr == XBDM_NOERR )
  221. {
  222. // target path to file exists
  223. pathExist = true;
  224. // compare times
  225. deltaTime = CompareFileTimes_NTFStoFATX( &localAttributes.ftLastWriteTime, localTimeString, sizeof( localTimeString), &targetAttributes.ChangeTime, targetTimeString, sizeof( targetTimeString ) );
  226. if ( deltaTime < 0 )
  227. {
  228. // ntfs is older, fatx is newer, no update
  229. if ( bVerbose )
  230. {
  231. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, %s [%s] is newer than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString );
  232. }
  233. copy = false;
  234. }
  235. else if ( !deltaTime )
  236. {
  237. // equal times, compare sizes
  238. if ( localAttributes.nFileSizeLow == targetAttributes.SizeLow &&
  239. localAttributes.nFileSizeHigh == targetAttributes.SizeHigh )
  240. {
  241. // file appears synced
  242. copy = false;
  243. }
  244. if ( bVerbose )
  245. {
  246. if ( copy )
  247. {
  248. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] [%d] has different size than %s [%s] [%d]\n", targetFilename, targetTimeString, targetAttributes.SizeLow, localFilename, localTimeString, localAttributes.nFileSizeLow );
  249. }
  250. else
  251. {
  252. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, %s [%s] [%d] has same time and file size as %s [%s] [%d]\n", targetFilename, targetTimeString, targetAttributes.SizeLow, localFilename, localTimeString, localAttributes.nFileSizeLow );
  253. }
  254. }
  255. }
  256. else
  257. {
  258. // ntfs is newer, fatx is older, update
  259. if ( bVerbose )
  260. {
  261. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] is older than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString );
  262. }
  263. }
  264. }
  265. }
  266. else if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_ALWAYS )
  267. {
  268. if ( bVerbose )
  269. {
  270. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Force Update, %s\n", targetFilename );
  271. }
  272. }
  273. if ( copy && !bNoWrite )
  274. {
  275. if ( !pathExist )
  276. {
  277. CreateTargetPath( targetFilename );
  278. }
  279. hr = DmSendFile( localFilename, targetFilename );
  280. if ( hr == XBDM_NOERR )
  281. {
  282. // force the target to match the local attributes
  283. // to ensure sync
  284. memset( &targetAttributes, 0, sizeof( targetAttributes ) );
  285. targetAttributes.SizeHigh = localAttributes.nFileSizeHigh;
  286. targetAttributes.SizeLow = localAttributes.nFileSizeLow;
  287. targetAttributes.CreationTime = localAttributes.ftCreationTime;
  288. targetAttributes.ChangeTime = localAttributes.ftLastWriteTime;
  289. DmSetFileAttributes( targetFilename, &targetAttributes );
  290. // success, file copied
  291. errCode = 1;
  292. }
  293. else
  294. {
  295. // failure
  296. if ( bVerbose )
  297. {
  298. ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failed!\n" );
  299. }
  300. errCode = -1;
  301. }
  302. DebugCommand( "0x%8.8x = FileSyncEx( %s, %s )\n", hr, localFilename, targetFilename );
  303. }
  304. return errCode;
  305. }
  306. //-----------------------------------------------------------------------------
  307. // LoadTargetFile
  308. //
  309. //-----------------------------------------------------------------------------
  310. bool LoadTargetFile( const char *pTargetPath, int *pFileSize, void **pData )
  311. {
  312. DM_FILE_ATTRIBUTES fileAttributes;
  313. HRESULT hr;
  314. DWORD bytesRead;
  315. char *pBuffer;
  316. *pFileSize = 0;
  317. *pData = (void *)NULL;
  318. hr = DmGetFileAttributes( pTargetPath, &fileAttributes );
  319. if ( hr != XBDM_NOERR || !fileAttributes.SizeLow )
  320. return false;
  321. // allocate for size and terminating null
  322. pBuffer = (char *)Sys_Alloc( fileAttributes.SizeLow+1 );
  323. hr = DmReadFilePartial( pTargetPath, 0, (LPBYTE)pBuffer, fileAttributes.SizeLow, &bytesRead );
  324. if ( hr != XBDM_NOERR || ( bytesRead != fileAttributes.SizeLow ) )
  325. {
  326. Sys_Free( pBuffer );
  327. return false;
  328. }
  329. // add a terminating null
  330. pBuffer[fileAttributes.SizeLow] = '\0';
  331. *pFileSize = fileAttributes.SizeLow;
  332. *pData = pBuffer;
  333. // success
  334. return true;
  335. }
  336. //-----------------------------------------------------------------------------
  337. // CreateTargetPath
  338. //
  339. //-----------------------------------------------------------------------------
  340. bool CreateTargetPath( const char *pTargetFilename )
  341. {
  342. // create path chain
  343. char *pPath;
  344. char dirPath[MAX_PATH];
  345. // prime and skip to first seperator
  346. strcpy( dirPath, pTargetFilename );
  347. pPath = strchr( dirPath, '\\' );
  348. while ( pPath )
  349. {
  350. pPath = strchr( pPath+1, '\\' );
  351. if ( pPath )
  352. {
  353. *pPath = '\0';
  354. DmMkdir( dirPath );
  355. *pPath = '\\';
  356. }
  357. }
  358. return true;
  359. }