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
416 lines
11 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// FILEIO.CPP |
|
// |
|
// File I/O Service Routines |
|
//=====================================================================================// |
|
#include "vxconsole.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// SystemTimeToString |
|
// |
|
// mm/dd/yyyy hh:mm:ss am |
|
//----------------------------------------------------------------------------- |
|
char *SystemTimeToString( SYSTEMTIME *systemTime, char *buffer, int bufferSize ) |
|
{ |
|
char timeString[256]; |
|
char dateString[256]; |
|
int length; |
|
|
|
GetDateFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "MM'/'dd'/'yyyy", dateString, sizeof( dateString ) ); |
|
GetTimeFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "hh':'mm':'ss tt", timeString, sizeof( timeString ) ); |
|
length = _snprintf( buffer, bufferSize, "%s %s", dateString, timeString ); |
|
if ( length == -1 ) |
|
buffer[bufferSize-1] = '\0'; |
|
|
|
return buffer; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// CompareFileTimes_NTFStoFATX |
|
// |
|
//----------------------------------------------------------------------------- |
|
int CompareFileTimes_NTFStoFATX( FILETIME* ntfsFileTime, char *ntfsTimeString, int ntfsStringSize, FILETIME* fatxFileTime, char *fatxTimeString, int fatxStringSize ) |
|
{ |
|
SYSTEMTIME ntfsSystemTime; |
|
SYSTEMTIME fatxSystemTime; |
|
int diff; |
|
int ntfsSeconds; |
|
int fatxSeconds; |
|
|
|
TIME_ZONE_INFORMATION tzInfo; |
|
GetTimeZoneInformation( &tzInfo ); |
|
|
|
// cannot compare UTC file times directly |
|
// disjoint filesystems - xbox has a +/- 2s error |
|
// daylight savings time handling on each file system may cause problems |
|
FileTimeToSystemTime( ntfsFileTime, &ntfsSystemTime ); |
|
FileTimeToSystemTime( fatxFileTime, &fatxSystemTime ); |
|
|
|
// operate on local times, assumes xbox and pc are both set for same time zone and daylight saving |
|
SYSTEMTIME ntfsLocalTime; |
|
SYSTEMTIME fatxLocalTime; |
|
SystemTimeToTzSpecificLocalTime( &tzInfo, &ntfsSystemTime, &ntfsLocalTime ); |
|
SystemTimeToTzSpecificLocalTime( &tzInfo, &fatxSystemTime, &fatxLocalTime ); |
|
|
|
if ( ntfsTimeString ) |
|
{ |
|
SystemTimeToString( &ntfsLocalTime, ntfsTimeString, ntfsStringSize ); |
|
} |
|
|
|
if ( fatxTimeString ) |
|
{ |
|
SystemTimeToString( &fatxLocalTime, fatxTimeString, fatxStringSize ); |
|
} |
|
|
|
diff = ntfsLocalTime.wYear-fatxLocalTime.wYear; |
|
if ( diff ) |
|
return diff; |
|
|
|
diff = ntfsLocalTime.wMonth-fatxLocalTime.wMonth; |
|
if ( diff ) |
|
return diff; |
|
|
|
diff = ntfsLocalTime.wDay-fatxLocalTime.wDay; |
|
if ( diff ) |
|
return diff; |
|
|
|
diff = ntfsLocalTime.wHour-fatxLocalTime.wHour; |
|
if ( diff ) |
|
return diff; |
|
|
|
// allow for +/- 3s error |
|
ntfsSeconds = ntfsLocalTime.wHour*60*60 + ntfsLocalTime.wMinute*60 + ntfsLocalTime.wSecond; |
|
fatxSeconds = fatxLocalTime.wHour*60*60 + fatxLocalTime.wMinute*60 + fatxLocalTime.wSecond; |
|
|
|
diff = ntfsSeconds-fatxSeconds; |
|
if ( diff > 3 || diff < -3 ) |
|
return diff; |
|
|
|
// times are considered equal |
|
return 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// FreeTargetFileList |
|
// |
|
//----------------------------------------------------------------------------- |
|
void FreeTargetFileList( fileNode_t* pFileList ) |
|
{ |
|
fileNode_t *nodePtr; |
|
fileNode_t *nextPtr; |
|
|
|
if ( !pFileList ) |
|
return; |
|
|
|
nodePtr = pFileList; |
|
while ( nodePtr ) |
|
{ |
|
nextPtr = nodePtr->nextPtr; |
|
|
|
Sys_Free( nodePtr->filename ); |
|
Sys_Free( nodePtr ); |
|
|
|
nodePtr = nextPtr; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// GetTargetFileList_r |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool GetTargetFileList_r( char* targetPath, bool recurse, int attributes, int level, fileNode_t** pFileList ) |
|
{ |
|
HRESULT hr; |
|
PDM_WALK_DIR pWalkDir = NULL; |
|
DM_FILE_ATTRIBUTES fileAttr; |
|
bool valid; |
|
char filename[MAX_PATH]; |
|
fileNode_t* nodePtr; |
|
bool bGetNormal; |
|
int fixedAttributes; |
|
|
|
if ( !level ) |
|
*pFileList = NULL; |
|
|
|
fixedAttributes = attributes; |
|
if ( fixedAttributes & FILE_ATTRIBUTE_NORMAL ) |
|
{ |
|
fixedAttributes &= ~FILE_ATTRIBUTE_NORMAL; |
|
bGetNormal = true; |
|
} |
|
else |
|
bGetNormal = false; |
|
|
|
while ( 1 ) |
|
{ |
|
hr = DmWalkDir( &pWalkDir, targetPath, &fileAttr ); |
|
if ( hr != XBDM_NOERR ) |
|
break; |
|
|
|
strcpy( filename, targetPath ); |
|
Sys_AddFileSeperator( filename, sizeof( filename ) ); |
|
strcat( filename, fileAttr.Name ); |
|
|
|
// restrict to desired attributes |
|
if ( ( bGetNormal && !fileAttr.Attributes ) || ( fileAttr.Attributes & fixedAttributes ) ) |
|
{ |
|
Sys_NormalizePath( filename, false ); |
|
|
|
// create a new file node |
|
nodePtr = ( fileNode_t* )Sys_Alloc( sizeof( fileNode_t ) ); |
|
|
|
// link it in |
|
nodePtr->filename = Sys_CopyString( filename ); |
|
nodePtr->changeTime = fileAttr.ChangeTime; |
|
nodePtr->creationTime = fileAttr.CreationTime; |
|
nodePtr->sizeHigh = fileAttr.SizeHigh; |
|
nodePtr->sizeLow = fileAttr.SizeLow; |
|
nodePtr->attributes = fileAttr.Attributes; |
|
nodePtr->level = level; |
|
nodePtr->nextPtr = *pFileList; |
|
*pFileList = nodePtr; |
|
} |
|
|
|
if ( fileAttr.Attributes & FILE_ATTRIBUTE_DIRECTORY ) |
|
{ |
|
if ( recurse ) |
|
{ |
|
// descend into directory |
|
valid = GetTargetFileList_r( filename, recurse, attributes, level+1, pFileList ); |
|
if ( !valid ) |
|
return false; |
|
} |
|
} |
|
} |
|
DmCloseDir( pWalkDir ); |
|
|
|
if ( hr != XBDM_ENDOFLIST ) |
|
{ |
|
// failure |
|
return false; |
|
} |
|
|
|
// ok |
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// FileSyncEx |
|
// |
|
// -1: failure, 0: nothing, 1: synced |
|
//----------------------------------------------------------------------------- |
|
int FileSyncEx( const char* localFilename, const char* targetFilename, int fileSyncMode, bool bVerbose, bool bNoWrite ) |
|
{ |
|
bool copy; |
|
bool pathExist; |
|
WIN32_FILE_ATTRIBUTE_DATA localAttributes; |
|
DM_FILE_ATTRIBUTES targetAttributes; |
|
HRESULT hr; |
|
int errCode; |
|
int deltaTime; |
|
char localTimeString[256]; |
|
char targetTimeString[256]; |
|
|
|
if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_OFF ) |
|
{ |
|
return 0; |
|
} |
|
|
|
if ( !GetFileAttributesEx( localFilename, GetFileExInfoStandard, &localAttributes ) ) |
|
{ |
|
// failed to get the local file's attributes |
|
if ( bVerbose ) |
|
{ |
|
ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failure: Local file %s not available\n", localFilename ); |
|
} |
|
return -1; |
|
} |
|
|
|
if ( localAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) |
|
{ |
|
// ignore directory |
|
return 0; |
|
} |
|
|
|
if ( fileSyncMode & FSYNC_ANDEXISTSONTARGET ) |
|
{ |
|
hr = DmGetFileAttributes( targetFilename, &targetAttributes ); |
|
if ( hr != XBDM_NOERR ) |
|
{ |
|
// target doesn't exist, no sync operation should commence |
|
if ( bVerbose ) |
|
{ |
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, Target file %s not available\n", targetFilename ); |
|
} |
|
return 0; |
|
} |
|
} |
|
|
|
// default success, no operation |
|
errCode = 0; |
|
|
|
// default, create path and copy |
|
copy = true; |
|
pathExist = false; |
|
|
|
if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_IFNEWER ) |
|
{ |
|
hr = DmGetFileAttributes( targetFilename, &targetAttributes ); |
|
if ( hr == XBDM_NOERR ) |
|
{ |
|
// target path to file exists |
|
pathExist = true; |
|
|
|
// compare times |
|
deltaTime = CompareFileTimes_NTFStoFATX( &localAttributes.ftLastWriteTime, localTimeString, sizeof( localTimeString), &targetAttributes.ChangeTime, targetTimeString, sizeof( targetTimeString ) ); |
|
if ( deltaTime < 0 ) |
|
{ |
|
// ntfs is older, fatx is newer, no update |
|
if ( bVerbose ) |
|
{ |
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, %s [%s] is newer than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString ); |
|
} |
|
copy = false; |
|
} |
|
else if ( !deltaTime ) |
|
{ |
|
// equal times, compare sizes |
|
if ( localAttributes.nFileSizeLow == targetAttributes.SizeLow && |
|
localAttributes.nFileSizeHigh == targetAttributes.SizeHigh ) |
|
{ |
|
// file appears synced |
|
copy = false; |
|
} |
|
if ( bVerbose ) |
|
{ |
|
if ( copy ) |
|
{ |
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] [%d] has different size than %s [%s] [%d]\n", targetFilename, targetTimeString, targetAttributes.SizeLow, localFilename, localTimeString, localAttributes.nFileSizeLow ); |
|
} |
|
else |
|
{ |
|
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 ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// ntfs is newer, fatx is older, update |
|
if ( bVerbose ) |
|
{ |
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] is older than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString ); |
|
} |
|
} |
|
} |
|
} |
|
else if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_ALWAYS ) |
|
{ |
|
if ( bVerbose ) |
|
{ |
|
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Force Update, %s\n", targetFilename ); |
|
} |
|
} |
|
|
|
if ( copy && !bNoWrite ) |
|
{ |
|
if ( !pathExist ) |
|
{ |
|
CreateTargetPath( targetFilename ); |
|
} |
|
|
|
hr = DmSendFile( localFilename, targetFilename ); |
|
if ( hr == XBDM_NOERR ) |
|
{ |
|
// force the target to match the local attributes |
|
// to ensure sync |
|
memset( &targetAttributes, 0, sizeof( targetAttributes ) ); |
|
targetAttributes.SizeHigh = localAttributes.nFileSizeHigh; |
|
targetAttributes.SizeLow = localAttributes.nFileSizeLow; |
|
targetAttributes.CreationTime = localAttributes.ftCreationTime; |
|
targetAttributes.ChangeTime = localAttributes.ftLastWriteTime; |
|
DmSetFileAttributes( targetFilename, &targetAttributes ); |
|
|
|
// success, file copied |
|
errCode = 1; |
|
} |
|
else |
|
{ |
|
// failure |
|
if ( bVerbose ) |
|
{ |
|
ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failed!\n" ); |
|
} |
|
errCode = -1; |
|
} |
|
|
|
DebugCommand( "0x%8.8x = FileSyncEx( %s, %s )\n", hr, localFilename, targetFilename ); |
|
} |
|
|
|
return errCode; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// LoadTargetFile |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool LoadTargetFile( const char *pTargetPath, int *pFileSize, void **pData ) |
|
{ |
|
DM_FILE_ATTRIBUTES fileAttributes; |
|
HRESULT hr; |
|
DWORD bytesRead; |
|
char *pBuffer; |
|
|
|
*pFileSize = 0; |
|
*pData = (void *)NULL; |
|
|
|
hr = DmGetFileAttributes( pTargetPath, &fileAttributes ); |
|
if ( hr != XBDM_NOERR || !fileAttributes.SizeLow ) |
|
return false; |
|
|
|
// allocate for size and terminating null |
|
pBuffer = (char *)Sys_Alloc( fileAttributes.SizeLow+1 ); |
|
|
|
hr = DmReadFilePartial( pTargetPath, 0, (LPBYTE)pBuffer, fileAttributes.SizeLow, &bytesRead ); |
|
if ( hr != XBDM_NOERR || ( bytesRead != fileAttributes.SizeLow ) ) |
|
{ |
|
Sys_Free( pBuffer ); |
|
return false; |
|
} |
|
|
|
// add a terminating null |
|
pBuffer[fileAttributes.SizeLow] = '\0'; |
|
|
|
*pFileSize = fileAttributes.SizeLow; |
|
*pData = pBuffer; |
|
|
|
// success |
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// CreateTargetPath |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool CreateTargetPath( const char *pTargetFilename ) |
|
{ |
|
// create path chain |
|
char *pPath; |
|
char dirPath[MAX_PATH]; |
|
|
|
// prime and skip to first seperator |
|
strcpy( dirPath, pTargetFilename ); |
|
pPath = strchr( dirPath, '\\' ); |
|
while ( pPath ) |
|
{ |
|
pPath = strchr( pPath+1, '\\' ); |
|
if ( pPath ) |
|
{ |
|
*pPath = '\0'; |
|
DmMkdir( dirPath ); |
|
*pPath = '\\'; |
|
} |
|
} |
|
|
|
return true; |
|
}
|
|
|