mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-12-18 16:01:58 +01:00
* remove little unused code
* code cleanup
This commit is contained in:
parent
e1a36e8988
commit
9e79c9d99b
@ -2,8 +2,8 @@
|
||||
<app version="1">
|
||||
<name> USB Loader GX</name>
|
||||
<coder>USB Loader GX Team</coder>
|
||||
<version>1.0 r950</version>
|
||||
<release_date>201009182245</release_date>
|
||||
<version>1.0 r951</version>
|
||||
<release_date>201009182308</release_date>
|
||||
<short_description>Loads games from USB-devices</short_description>
|
||||
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
||||
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||
|
BIN
data/magic_patcher.o
Normal file
BIN
data/magic_patcher.o
Normal file
Binary file not shown.
@ -27,55 +27,55 @@
|
||||
#include "filelist.h"
|
||||
|
||||
FreeTypeGX * fontSystem = NULL;
|
||||
static FT_Byte * MainFont = (FT_Byte *) font_ttf;
|
||||
static FT_Byte * MainFont = ( FT_Byte * ) font_ttf;
|
||||
static u32 MainFontSize = font_ttf_size;
|
||||
|
||||
void ClearFontData()
|
||||
{
|
||||
if(fontSystem)
|
||||
if ( fontSystem )
|
||||
delete fontSystem;
|
||||
fontSystem = NULL;
|
||||
|
||||
if(MainFont != (FT_Byte *) font_ttf)
|
||||
if ( MainFont != ( FT_Byte * ) font_ttf )
|
||||
{
|
||||
if(MainFont != NULL)
|
||||
if ( MainFont != NULL )
|
||||
delete [] MainFont;
|
||||
MainFont = (FT_Byte *) font_ttf;
|
||||
MainFont = ( FT_Byte * ) font_ttf;
|
||||
MainFontSize = font_ttf_size;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetupDefaultFont(const char *path)
|
||||
bool SetupDefaultFont( const char *path )
|
||||
{
|
||||
bool result = false;
|
||||
FILE *pfile = NULL;
|
||||
|
||||
ClearFontData();
|
||||
|
||||
if(path)
|
||||
pfile = fopen(path, "rb");
|
||||
if ( path )
|
||||
pfile = fopen( path, "rb" );
|
||||
|
||||
if(pfile)
|
||||
if ( pfile )
|
||||
{
|
||||
fseek(pfile, 0, SEEK_END);
|
||||
MainFontSize = ftell(pfile);
|
||||
rewind(pfile);
|
||||
fseek( pfile, 0, SEEK_END );
|
||||
MainFontSize = ftell( pfile );
|
||||
rewind( pfile );
|
||||
|
||||
MainFont = new (std::nothrow) FT_Byte[MainFontSize];
|
||||
if(!MainFont)
|
||||
MainFont = new ( std::nothrow ) FT_Byte[MainFontSize];
|
||||
if ( !MainFont )
|
||||
{
|
||||
MainFont = (FT_Byte *) font_ttf;
|
||||
MainFont = ( FT_Byte * ) font_ttf;
|
||||
MainFontSize = font_ttf_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
fread(MainFont, 1, MainFontSize, pfile);
|
||||
fread( MainFont, 1, MainFontSize, pfile );
|
||||
result = true;
|
||||
}
|
||||
fclose(pfile);
|
||||
fclose( pfile );
|
||||
}
|
||||
|
||||
fontSystem = new FreeTypeGX(MainFont, MainFontSize);
|
||||
fontSystem = new FreeTypeGX( MainFont, MainFontSize );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#ifndef FONTSYSTEM_H_
|
||||
#define FONTSYSTEM_H_
|
||||
|
||||
bool SetupDefaultFont(const char *path);
|
||||
bool SetupDefaultFont( const char *path );
|
||||
void ClearFontData();
|
||||
|
||||
#endif
|
||||
|
@ -30,44 +30,44 @@ using namespace std;
|
||||
* This routine converts a supplied short character string into a wide character string.
|
||||
* Note that it is the user's responsibility to clear the returned buffer once it is no longer needed.
|
||||
*
|
||||
* @param strChar Character string to be converted.
|
||||
* @param strChar Character string to be converted.
|
||||
* @return Wide character representation of supplied character string.
|
||||
*/
|
||||
|
||||
wchar_t* charToWideChar(const char* strChar)
|
||||
wchar_t* charToWideChar( const char* strChar )
|
||||
{
|
||||
if(!strChar)
|
||||
if ( !strChar )
|
||||
return NULL;
|
||||
|
||||
wchar_t *strWChar = new (std::nothrow) wchar_t[strlen(strChar) + 1];
|
||||
if(!strWChar)
|
||||
return NULL;
|
||||
wchar_t *strWChar = new ( std::nothrow ) wchar_t[strlen( strChar ) + 1];
|
||||
if ( !strWChar )
|
||||
return NULL;
|
||||
|
||||
int bt = mbstowcs(strWChar, strChar, strlen(strChar));
|
||||
if (bt > 0)
|
||||
{
|
||||
strWChar[bt] = 0;
|
||||
return strWChar;
|
||||
}
|
||||
int bt = mbstowcs( strWChar, strChar, strlen( strChar ) );
|
||||
if ( bt > 0 )
|
||||
{
|
||||
strWChar[bt] = 0;
|
||||
return strWChar;
|
||||
}
|
||||
|
||||
wchar_t *tempDest = strWChar;
|
||||
while((*tempDest++ = *strChar++));
|
||||
wchar_t *tempDest = strWChar;
|
||||
while ( ( *tempDest++ = *strChar++ ) );
|
||||
|
||||
return strWChar;
|
||||
return strWChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for the FreeTypeGX class for WiiXplorer.
|
||||
*/
|
||||
FreeTypeGX::FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize)
|
||||
FreeTypeGX::FreeTypeGX( const uint8_t* fontBuffer, FT_Long bufferSize )
|
||||
{
|
||||
ftPointSize = 0;
|
||||
|
||||
FT_Init_FreeType(&ftLibrary);
|
||||
FT_New_Memory_Face(ftLibrary, (FT_Byte *)fontBuffer, bufferSize, 0, &ftFace);
|
||||
FT_Init_FreeType( &ftLibrary );
|
||||
FT_New_Memory_Face( ftLibrary, ( FT_Byte * )fontBuffer, bufferSize, 0, &ftFace );
|
||||
|
||||
setVertexFormat(GX_VTXFMT1);
|
||||
ftKerningEnabled = FT_HAS_KERNING(ftFace);
|
||||
setVertexFormat( GX_VTXFMT1 );
|
||||
ftKerningEnabled = FT_HAS_KERNING( ftFace );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,9 +75,9 @@ FreeTypeGX::FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize)
|
||||
*/
|
||||
FreeTypeGX::~FreeTypeGX()
|
||||
{
|
||||
unloadFont();
|
||||
FT_Done_Face(ftFace);
|
||||
FT_Done_FreeType(ftLibrary);
|
||||
unloadFont();
|
||||
FT_Done_Face( ftFace );
|
||||
FT_Done_FreeType( ftLibrary );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,14 +87,14 @@ FreeTypeGX::~FreeTypeGX()
|
||||
* Note that this function should not need to be called except if the vertex formats are cleared or the specified
|
||||
* vertex format index is modified.
|
||||
*
|
||||
* @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file.
|
||||
* @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file.
|
||||
*/
|
||||
void FreeTypeGX::setVertexFormat(uint8_t vertexInd)
|
||||
void FreeTypeGX::setVertexFormat( uint8_t vertexInd )
|
||||
{
|
||||
vertexIndex = vertexInd;
|
||||
GX_SetVtxAttrFmt(vertexIndex, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
|
||||
GX_SetVtxAttrFmt(vertexIndex, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
||||
GX_SetVtxAttrFmt(vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
vertexIndex = vertexInd;
|
||||
GX_SetVtxAttrFmt( vertexIndex, GX_VA_POS, GX_POS_XYZ, GX_S16, 0 );
|
||||
GX_SetVtxAttrFmt( vertexIndex, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0 );
|
||||
GX_SetVtxAttrFmt( vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,22 +104,22 @@ void FreeTypeGX::setVertexFormat(uint8_t vertexInd)
|
||||
*/
|
||||
void FreeTypeGX::unloadFont()
|
||||
{
|
||||
if(this->fontData.size() == 0)
|
||||
return;
|
||||
if ( this->fontData.size() == 0 )
|
||||
return;
|
||||
|
||||
map<int16_t, map<wchar_t, ftgxCharData> >::iterator itr;
|
||||
map<wchar_t, ftgxCharData>::iterator itr2;
|
||||
|
||||
for(itr = fontData.begin(); itr != fontData.end(); itr++)
|
||||
{
|
||||
for(itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)
|
||||
free(itr2->second.glyphDataTexture);
|
||||
for ( itr = fontData.begin(); itr != fontData.end(); itr++ )
|
||||
{
|
||||
for ( itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++ )
|
||||
free( itr2->second.glyphDataTexture );
|
||||
|
||||
itr->second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
fontData.clear();
|
||||
ftgxAlign.clear();
|
||||
fontData.clear();
|
||||
ftgxAlign.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,70 +128,70 @@ void FreeTypeGX::unloadFont()
|
||||
* This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible
|
||||
* structure within an instance-specific map.
|
||||
*
|
||||
* @param charCode The requested glyph's character code.
|
||||
* @param charCode The requested glyph's character code.
|
||||
* @return A pointer to the allocated font structure.
|
||||
*/
|
||||
ftgxCharData * FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize)
|
||||
ftgxCharData * FreeTypeGX::cacheGlyphData( wchar_t charCode, int16_t pixelSize )
|
||||
{
|
||||
map<int16_t, map<wchar_t, ftgxCharData> >::iterator itr;
|
||||
map<wchar_t, ftgxCharData>::iterator itr2;
|
||||
|
||||
itr = fontData.find(pixelSize);
|
||||
if(itr != fontData.end())
|
||||
itr = fontData.find( pixelSize );
|
||||
if ( itr != fontData.end() )
|
||||
{
|
||||
itr2 = itr->second.find(charCode);
|
||||
itr2 = itr->second.find( charCode );
|
||||
|
||||
if(itr2 != itr->second.end())
|
||||
if ( itr2 != itr->second.end() )
|
||||
{
|
||||
return &itr2->second;
|
||||
}
|
||||
}
|
||||
|
||||
FT_UInt gIndex;
|
||||
uint16_t textureWidth = 0, textureHeight = 0;
|
||||
FT_UInt gIndex;
|
||||
uint16_t textureWidth = 0, textureHeight = 0;
|
||||
|
||||
if(ftPointSize != pixelSize)
|
||||
{
|
||||
ftPointSize = pixelSize;
|
||||
FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize);
|
||||
if ( ftPointSize != pixelSize )
|
||||
{
|
||||
ftPointSize = pixelSize;
|
||||
FT_Set_Pixel_Sizes( ftFace, 0, ftPointSize );
|
||||
|
||||
//!Cache ascender and decender as well
|
||||
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find(ftPointSize);
|
||||
if(itrAlign == ftgxAlign.end())
|
||||
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find( ftPointSize );
|
||||
if ( itrAlign == ftgxAlign.end() )
|
||||
{
|
||||
ftgxAlign[ftPointSize].ascender = (int16_t) ftFace->size->metrics.ascender>>6;
|
||||
ftgxAlign[ftPointSize].descender = (int16_t) ftFace->size->metrics.descender>>6;
|
||||
ftgxAlign[ftPointSize].ascender = ( int16_t ) ftFace->size->metrics.ascender >> 6;
|
||||
ftgxAlign[ftPointSize].descender = ( int16_t ) ftFace->size->metrics.descender >> 6;
|
||||
ftgxAlign[ftPointSize].max = 0;
|
||||
ftgxAlign[ftPointSize].min = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gIndex = FT_Get_Char_Index(ftFace, (FT_ULong) charCode);
|
||||
if (gIndex != 0 && FT_Load_Glyph(ftFace, gIndex, FT_LOAD_DEFAULT | FT_LOAD_RENDER) == 0)
|
||||
{
|
||||
if(ftFace->glyph->format == FT_GLYPH_FORMAT_BITMAP)
|
||||
{
|
||||
FT_Bitmap *glyphBitmap = &ftFace->glyph->bitmap;
|
||||
gIndex = FT_Get_Char_Index( ftFace, ( FT_ULong ) charCode );
|
||||
if ( gIndex != 0 && FT_Load_Glyph( ftFace, gIndex, FT_LOAD_DEFAULT | FT_LOAD_RENDER ) == 0 )
|
||||
{
|
||||
if ( ftFace->glyph->format == FT_GLYPH_FORMAT_BITMAP )
|
||||
{
|
||||
FT_Bitmap *glyphBitmap = &ftFace->glyph->bitmap;
|
||||
|
||||
textureWidth = glyphBitmap->width + (4 - glyphBitmap->width % 4) % 4;
|
||||
textureHeight = glyphBitmap->rows + (4 - glyphBitmap->rows % 4) % 4;
|
||||
textureWidth = glyphBitmap->width + ( 4 - glyphBitmap->width % 4 ) % 4;
|
||||
textureHeight = glyphBitmap->rows + ( 4 - glyphBitmap->rows % 4 ) % 4;
|
||||
|
||||
fontData[pixelSize][charCode].renderOffsetX = (int16_t) ftFace->glyph->bitmap_left;
|
||||
fontData[pixelSize][charCode].glyphAdvanceX = (uint16_t) (ftFace->glyph->advance.x >> 6);
|
||||
fontData[pixelSize][charCode].glyphIndex = (uint32_t) gIndex;
|
||||
fontData[pixelSize][charCode].textureWidth = (uint16_t) textureWidth;
|
||||
fontData[pixelSize][charCode].textureHeight = (uint16_t) textureHeight;
|
||||
fontData[pixelSize][charCode].renderOffsetY = (int16_t) ftFace->glyph->bitmap_top;
|
||||
fontData[pixelSize][charCode].renderOffsetMax = (int16_t) ftFace->glyph->bitmap_top;
|
||||
fontData[pixelSize][charCode].renderOffsetMin = (int16_t) glyphBitmap->rows - ftFace->glyph->bitmap_top;
|
||||
fontData[pixelSize][charCode].glyphDataTexture = NULL;
|
||||
fontData[pixelSize][charCode].renderOffsetX = ( int16_t ) ftFace->glyph->bitmap_left;
|
||||
fontData[pixelSize][charCode].glyphAdvanceX = ( uint16_t ) ( ftFace->glyph->advance.x >> 6 );
|
||||
fontData[pixelSize][charCode].glyphIndex = ( uint32_t ) gIndex;
|
||||
fontData[pixelSize][charCode].textureWidth = ( uint16_t ) textureWidth;
|
||||
fontData[pixelSize][charCode].textureHeight = ( uint16_t ) textureHeight;
|
||||
fontData[pixelSize][charCode].renderOffsetY = ( int16_t ) ftFace->glyph->bitmap_top;
|
||||
fontData[pixelSize][charCode].renderOffsetMax = ( int16_t ) ftFace->glyph->bitmap_top;
|
||||
fontData[pixelSize][charCode].renderOffsetMin = ( int16_t ) glyphBitmap->rows - ftFace->glyph->bitmap_top;
|
||||
fontData[pixelSize][charCode].glyphDataTexture = NULL;
|
||||
|
||||
loadGlyphData(glyphBitmap, &fontData[pixelSize][charCode]);
|
||||
loadGlyphData( glyphBitmap, &fontData[pixelSize][charCode] );
|
||||
|
||||
return &fontData[pixelSize][charCode];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return &fontData[pixelSize][charCode];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,19 +200,19 @@ ftgxCharData * FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize)
|
||||
* This routine locates each character in the configured font face and renders the glyph's bitmap.
|
||||
* Each bitmap and relevant information is loaded into its own quickly addressible structure within an instance-specific map.
|
||||
*/
|
||||
uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize)
|
||||
uint16_t FreeTypeGX::cacheGlyphDataComplete( int16_t pixelSize )
|
||||
{
|
||||
uint32_t i = 0;
|
||||
FT_UInt gIndex;
|
||||
uint32_t i = 0;
|
||||
FT_UInt gIndex;
|
||||
|
||||
FT_ULong charCode = FT_Get_First_Char( ftFace, &gIndex );
|
||||
while ( gIndex != 0 )
|
||||
{
|
||||
if(cacheGlyphData(charCode, pixelSize) != NULL)
|
||||
++i;
|
||||
charCode = FT_Get_Next_Char( ftFace, charCode, &gIndex );
|
||||
}
|
||||
return (uint16_t)(i);
|
||||
FT_ULong charCode = FT_Get_First_Char( ftFace, &gIndex );
|
||||
while ( gIndex != 0 )
|
||||
{
|
||||
if ( cacheGlyphData( charCode, pixelSize ) != NULL )
|
||||
++i;
|
||||
charCode = FT_Get_Next_Char( ftFace, charCode, &gIndex );
|
||||
}
|
||||
return ( uint16_t )( i );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,40 +221,40 @@ uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize)
|
||||
* This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer.
|
||||
* Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value.
|
||||
*
|
||||
* @param bmp A pointer to the most recently rendered glyph's bitmap.
|
||||
* @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph.
|
||||
* @param bmp A pointer to the most recently rendered glyph's bitmap.
|
||||
* @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph.
|
||||
*
|
||||
*
|
||||
* Optimized for RGBA8 use by Dimok.
|
||||
*/
|
||||
void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData)
|
||||
void FreeTypeGX::loadGlyphData( FT_Bitmap *bmp, ftgxCharData *charData )
|
||||
{
|
||||
int length = ((((charData->textureWidth+3)>>2)*((charData->textureHeight+3)>>2)*32*2 + 31) & ~31);
|
||||
int length = ( ( ( ( charData->textureWidth + 3 ) >> 2 ) * ( ( charData->textureHeight + 3 ) >> 2 ) * 32 * 2 + 31 ) & ~31 );
|
||||
|
||||
uint8_t * glyphData = (uint8_t *) memalign(32, length);
|
||||
if(!glyphData)
|
||||
uint8_t * glyphData = ( uint8_t * ) memalign( 32, length );
|
||||
if ( !glyphData )
|
||||
return;
|
||||
|
||||
memset(glyphData, 0x00, length);
|
||||
memset( glyphData, 0x00, length );
|
||||
|
||||
uint8_t *src = (uint8_t *)bmp->buffer;
|
||||
uint32_t offset;
|
||||
uint8_t *src = ( uint8_t * )bmp->buffer;
|
||||
uint32_t offset;
|
||||
|
||||
for (int imagePosY = 0; imagePosY < bmp->rows; ++imagePosY)
|
||||
{
|
||||
for (int imagePosX = 0; imagePosX < bmp->width; ++imagePosX)
|
||||
{
|
||||
offset = ((((imagePosY >> 2) * (charData->textureWidth >> 2) + (imagePosX >> 2)) << 5) + ((imagePosY & 3) << 2) + (imagePosX & 3)) << 1;
|
||||
glyphData[offset] = *src;
|
||||
glyphData[offset+1] = *src;
|
||||
glyphData[offset+32] = *src;
|
||||
glyphData[offset+33] = *src;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
DCFlushRange(glyphData, length);
|
||||
for ( int imagePosY = 0; imagePosY < bmp->rows; ++imagePosY )
|
||||
{
|
||||
for ( int imagePosX = 0; imagePosX < bmp->width; ++imagePosX )
|
||||
{
|
||||
offset = ( ( ( ( imagePosY >> 2 ) * ( charData->textureWidth >> 2 ) + ( imagePosX >> 2 ) ) << 5 ) + ( ( imagePosY & 3 ) << 2 ) + ( imagePosX & 3 ) ) << 1;
|
||||
glyphData[offset] = *src;
|
||||
glyphData[offset+1] = *src;
|
||||
glyphData[offset+32] = *src;
|
||||
glyphData[offset+33] = *src;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
DCFlushRange( glyphData, length );
|
||||
|
||||
charData->glyphDataTexture = glyphData;
|
||||
charData->glyphDataTexture = glyphData;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,18 +262,18 @@ void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData)
|
||||
*
|
||||
* This routine calculates the x offset of the rendered string based off of a supplied positional format parameter.
|
||||
*
|
||||
* @param width Current pixel width of the string.
|
||||
* @param format Positional format of the string.
|
||||
* @param width Current pixel width of the string.
|
||||
* @param format Positional format of the string.
|
||||
*/
|
||||
int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format)
|
||||
int16_t FreeTypeGX::getStyleOffsetWidth( uint16_t width, uint16_t format )
|
||||
{
|
||||
if (format & FTGX_JUSTIFY_LEFT)
|
||||
return 0;
|
||||
else if (format & FTGX_JUSTIFY_CENTER)
|
||||
return -(width >> 1);
|
||||
else if (format & FTGX_JUSTIFY_RIGHT)
|
||||
return -width;
|
||||
return 0;
|
||||
if ( format & FTGX_JUSTIFY_LEFT )
|
||||
return 0;
|
||||
else if ( format & FTGX_JUSTIFY_CENTER )
|
||||
return -( width >> 1 );
|
||||
else if ( format & FTGX_JUSTIFY_RIGHT )
|
||||
return -width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,40 +281,40 @@ int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format)
|
||||
*
|
||||
* This routine calculates the y offset of the rendered string based off of a supplied positional format parameter.
|
||||
*
|
||||
* @param offset Current pixel offset data of the string.
|
||||
* @param format Positional format of the string.
|
||||
* @param offset Current pixel offset data of the string.
|
||||
* @param format Positional format of the string.
|
||||
*/
|
||||
int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize)
|
||||
int16_t FreeTypeGX::getStyleOffsetHeight( int16_t format, uint16_t pixelSize )
|
||||
{
|
||||
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find(pixelSize);
|
||||
if(itrAlign == ftgxAlign.end())
|
||||
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find( pixelSize );
|
||||
if ( itrAlign == ftgxAlign.end() )
|
||||
return 0;
|
||||
|
||||
switch(format & FTGX_ALIGN_MASK)
|
||||
{
|
||||
case FTGX_ALIGN_TOP:
|
||||
return itrAlign->second.ascender;
|
||||
switch ( format & FTGX_ALIGN_MASK )
|
||||
{
|
||||
case FTGX_ALIGN_TOP:
|
||||
return itrAlign->second.ascender;
|
||||
|
||||
case FTGX_ALIGN_MIDDLE:
|
||||
default:
|
||||
return (itrAlign->second.ascender + itrAlign->second.descender + 1) >> 1;
|
||||
case FTGX_ALIGN_MIDDLE:
|
||||
default:
|
||||
return ( itrAlign->second.ascender + itrAlign->second.descender + 1 ) >> 1;
|
||||
|
||||
case FTGX_ALIGN_BOTTOM:
|
||||
return itrAlign->second.descender;
|
||||
case FTGX_ALIGN_BOTTOM:
|
||||
return itrAlign->second.descender;
|
||||
|
||||
case FTGX_ALIGN_BASELINE:
|
||||
return 0;
|
||||
case FTGX_ALIGN_BASELINE:
|
||||
return 0;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_TOP:
|
||||
return itrAlign->second.max;
|
||||
case FTGX_ALIGN_GLYPH_TOP:
|
||||
return itrAlign->second.max;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_MIDDLE:
|
||||
return (itrAlign->second.max + itrAlign->second.min + 1) >> 1;
|
||||
case FTGX_ALIGN_GLYPH_MIDDLE:
|
||||
return ( itrAlign->second.max + itrAlign->second.min + 1 ) >> 1;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_BOTTOM:
|
||||
return itrAlign->second.min;
|
||||
}
|
||||
return 0;
|
||||
case FTGX_ALIGN_GLYPH_BOTTOM:
|
||||
return itrAlign->second.min;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -323,77 +323,77 @@ int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize)
|
||||
* This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer,
|
||||
* a texture from said buffer, and loads the resultant texture into the EFB.
|
||||
*
|
||||
* @param x Screen X coordinate at which to output the text.
|
||||
* @param x Screen X coordinate at which to output the text.
|
||||
* @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs.
|
||||
* @param text NULL terminated string to output.
|
||||
* @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff}
|
||||
* @param textStyle Flags which specify any styling which should be applied to the rendered string.
|
||||
* @param text NULL terminated string to output.
|
||||
* @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff}
|
||||
* @param textStyle Flags which specify any styling which should be applied to the rendered string.
|
||||
* @return The number of characters printed.
|
||||
*/
|
||||
uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color, uint16_t textStyle, uint16_t textWidth, uint16_t widthLimit)
|
||||
uint16_t FreeTypeGX::drawText( int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color, uint16_t textStyle, uint16_t textWidth, uint16_t widthLimit )
|
||||
{
|
||||
if(!text)
|
||||
if ( !text )
|
||||
return 0;
|
||||
|
||||
uint16_t fullTextWidth = textWidth > 0 ? textWidth : getWidth(text, pixelSize);
|
||||
uint16_t x_pos = x, printed = 0;
|
||||
uint16_t x_offset = 0, y_offset = 0;
|
||||
GXTexObj glyphTexture;
|
||||
FT_Vector pairDelta;
|
||||
uint16_t fullTextWidth = textWidth > 0 ? textWidth : getWidth( text, pixelSize );
|
||||
uint16_t x_pos = x, printed = 0;
|
||||
uint16_t x_offset = 0, y_offset = 0;
|
||||
GXTexObj glyphTexture;
|
||||
FT_Vector pairDelta;
|
||||
|
||||
if(textStyle & FTGX_JUSTIFY_MASK)
|
||||
{
|
||||
x_offset = getStyleOffsetWidth(fullTextWidth, textStyle);
|
||||
}
|
||||
if(textStyle & FTGX_ALIGN_MASK)
|
||||
{
|
||||
y_offset = getStyleOffsetHeight(textStyle, pixelSize);
|
||||
}
|
||||
if ( textStyle & FTGX_JUSTIFY_MASK )
|
||||
{
|
||||
x_offset = getStyleOffsetWidth( fullTextWidth, textStyle );
|
||||
}
|
||||
if ( textStyle & FTGX_ALIGN_MASK )
|
||||
{
|
||||
y_offset = getStyleOffsetHeight( textStyle, pixelSize );
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
|
||||
while (text[i])
|
||||
{
|
||||
if(widthLimit > 0 && (x_pos-x) > widthLimit)
|
||||
while ( text[i] )
|
||||
{
|
||||
if ( widthLimit > 0 && ( x_pos - x ) > widthLimit )
|
||||
break;
|
||||
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
ftgxCharData* glyphData = cacheGlyphData( text[i], pixelSize );
|
||||
|
||||
if (glyphData != NULL)
|
||||
{
|
||||
if (ftKerningEnabled && i > 0)
|
||||
{
|
||||
FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
|
||||
x_pos += pairDelta.x >> 6;
|
||||
}
|
||||
if ( glyphData != NULL )
|
||||
{
|
||||
if ( ftKerningEnabled && i > 0 )
|
||||
{
|
||||
FT_Get_Kerning( ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
|
||||
x_pos += pairDelta.x >> 6;
|
||||
}
|
||||
|
||||
GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
copyTextureToFramebuffer(&glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, z, color);
|
||||
GX_InitTexObj( &glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE );
|
||||
copyTextureToFramebuffer( &glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, z, color );
|
||||
|
||||
x_pos += glyphData->glyphAdvanceX;
|
||||
++printed;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
x_pos += glyphData->glyphAdvanceX;
|
||||
++printed;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if(textStyle & FTGX_STYLE_MASK)
|
||||
{
|
||||
getOffset(text, pixelSize, widthLimit);
|
||||
drawTextFeature(x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle, color);
|
||||
}
|
||||
if ( textStyle & FTGX_STYLE_MASK )
|
||||
{
|
||||
getOffset( text, pixelSize, widthLimit );
|
||||
drawTextFeature( x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle, color );
|
||||
}
|
||||
|
||||
return printed;
|
||||
return printed;
|
||||
}
|
||||
|
||||
void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color)
|
||||
void FreeTypeGX::drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color )
|
||||
{
|
||||
uint16_t featureHeight = pixelSize >> 4 > 0 ? pixelSize >> 4 : 1;
|
||||
uint16_t featureHeight = pixelSize >> 4 > 0 ? pixelSize >> 4 : 1;
|
||||
|
||||
if (format & FTGX_STYLE_UNDERLINE)
|
||||
this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, z, color);
|
||||
if ( format & FTGX_STYLE_UNDERLINE )
|
||||
this->copyFeatureToFramebuffer( width, featureHeight, x, y + 1, z, color );
|
||||
|
||||
if (format & FTGX_STYLE_STRIKE)
|
||||
this->copyFeatureToFramebuffer(width, featureHeight, x, y - ((offsetData->max) >> 1), z, color);
|
||||
if ( format & FTGX_STYLE_STRIKE )
|
||||
this->copyFeatureToFramebuffer( width, featureHeight, x, y - ( ( offsetData->max ) >> 1 ), z, color );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -402,57 +402,57 @@ void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelS
|
||||
* This routine processes each character of the supplied text string and calculates the width of the entire string.
|
||||
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
|
||||
*
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @return The width of the text string in pixels.
|
||||
*/
|
||||
uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize)
|
||||
uint16_t FreeTypeGX::getWidth( const wchar_t *text, int16_t pixelSize )
|
||||
{
|
||||
if(!text)
|
||||
if ( !text )
|
||||
return 0;
|
||||
|
||||
uint16_t strWidth = 0;
|
||||
FT_Vector pairDelta;
|
||||
uint16_t strWidth = 0;
|
||||
FT_Vector pairDelta;
|
||||
|
||||
int i = 0;
|
||||
while (text[i])
|
||||
{
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
int i = 0;
|
||||
while ( text[i] )
|
||||
{
|
||||
ftgxCharData* glyphData = cacheGlyphData( text[i], pixelSize );
|
||||
|
||||
if (glyphData != NULL)
|
||||
{
|
||||
if (ftKerningEnabled && (i > 0))
|
||||
{
|
||||
FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
|
||||
strWidth += pairDelta.x >> 6;
|
||||
}
|
||||
if ( glyphData != NULL )
|
||||
{
|
||||
if ( ftKerningEnabled && ( i > 0 ) )
|
||||
{
|
||||
FT_Get_Kerning( ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
|
||||
strWidth += pairDelta.x >> 6;
|
||||
}
|
||||
|
||||
strWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return strWidth;
|
||||
strWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return strWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single char width
|
||||
*/
|
||||
uint16_t FreeTypeGX::getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar)
|
||||
uint16_t FreeTypeGX::getCharWidth( const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar )
|
||||
{
|
||||
uint16_t strWidth = 0;
|
||||
ftgxCharData * glyphData = cacheGlyphData(wChar, pixelSize);
|
||||
ftgxCharData * glyphData = cacheGlyphData( wChar, pixelSize );
|
||||
|
||||
if(glyphData != NULL)
|
||||
if ( glyphData != NULL )
|
||||
{
|
||||
if (ftKerningEnabled && prevChar != 0x0000)
|
||||
if ( ftKerningEnabled && prevChar != 0x0000 )
|
||||
{
|
||||
FT_Vector pairDelta;
|
||||
FT_Get_Kerning(ftFace, fontData[pixelSize][prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
|
||||
FT_Get_Kerning( ftFace, fontData[pixelSize][prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
|
||||
strWidth += pairDelta.x >> 6;
|
||||
}
|
||||
strWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
|
||||
return strWidth;
|
||||
return strWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -461,14 +461,14 @@ uint16_t FreeTypeGX::getCharWidth(const wchar_t wChar, int16_t pixelSize, const
|
||||
* This routine processes each character of the supplied text string and calculates the height of the entire string.
|
||||
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
|
||||
*
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @return The height of the text string in pixels.
|
||||
*/
|
||||
uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize)
|
||||
uint16_t FreeTypeGX::getHeight( const wchar_t *text, int16_t pixelSize )
|
||||
{
|
||||
getOffset(text, pixelSize);
|
||||
getOffset( text, pixelSize );
|
||||
|
||||
return ftgxAlign[pixelSize].max - ftgxAlign[pixelSize].min;
|
||||
return ftgxAlign[pixelSize].max - ftgxAlign[pixelSize].min;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -477,47 +477,47 @@ uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize)
|
||||
* This function calculates the maximum pixel height above the font origin line and the minimum
|
||||
* pixel height below the font origin line and returns the values in an addressible structure.
|
||||
*
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @param offset returns the max and min values above and below the font origin line
|
||||
*
|
||||
*/
|
||||
void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit)
|
||||
void FreeTypeGX::getOffset( const wchar_t *text, int16_t pixelSize, uint16_t widthLimit )
|
||||
{
|
||||
if(ftgxAlign.find(pixelSize) != ftgxAlign.end())
|
||||
if ( ftgxAlign.find( pixelSize ) != ftgxAlign.end() )
|
||||
return;
|
||||
|
||||
int16_t strMax = 0, strMin = 9999;
|
||||
uint16_t currWidth = 0;
|
||||
int16_t strMax = 0, strMin = 9999;
|
||||
uint16_t currWidth = 0;
|
||||
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
|
||||
while (text[i])
|
||||
{
|
||||
if(widthLimit > 0 && currWidth >= widthLimit)
|
||||
while ( text[i] )
|
||||
{
|
||||
if ( widthLimit > 0 && currWidth >= widthLimit )
|
||||
break;
|
||||
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
ftgxCharData* glyphData = cacheGlyphData( text[i], pixelSize );
|
||||
|
||||
if(glyphData != NULL)
|
||||
{
|
||||
strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
|
||||
strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
|
||||
currWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
if ( glyphData != NULL )
|
||||
{
|
||||
strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
|
||||
strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
|
||||
currWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if(ftPointSize != pixelSize)
|
||||
{
|
||||
ftPointSize = pixelSize;
|
||||
FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize);
|
||||
}
|
||||
if ( ftPointSize != pixelSize )
|
||||
{
|
||||
ftPointSize = pixelSize;
|
||||
FT_Set_Pixel_Sizes( ftFace, 0, ftPointSize );
|
||||
}
|
||||
|
||||
ftgxAlign[pixelSize].ascender = ftFace->size->metrics.ascender>>6;
|
||||
ftgxAlign[pixelSize].descender = ftFace->size->metrics.descender>>6;
|
||||
ftgxAlign[pixelSize].max = strMax;
|
||||
ftgxAlign[pixelSize].min = strMin;
|
||||
ftgxAlign[pixelSize].ascender = ftFace->size->metrics.ascender >> 6;
|
||||
ftgxAlign[pixelSize].descender = ftFace->size->metrics.descender >> 6;
|
||||
ftgxAlign[pixelSize].max = strMax;
|
||||
ftgxAlign[pixelSize].min = strMin;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -525,41 +525,41 @@ void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widt
|
||||
*
|
||||
* This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target.
|
||||
*
|
||||
* @param texObj A pointer to the glyph's initialized texture object.
|
||||
* @param texWidth The pixel width of the texture object.
|
||||
* @param texHeight The pixel height of the texture object.
|
||||
* @param screenX The screen X coordinate at which to output the rendered texture.
|
||||
* @param screenY The screen Y coordinate at which to output the rendered texture.
|
||||
* @param color Color to apply to the texture.
|
||||
* @param texObj A pointer to the glyph's initialized texture object.
|
||||
* @param texWidth The pixel width of the texture object.
|
||||
* @param texHeight The pixel height of the texture object.
|
||||
* @param screenX The screen X coordinate at which to output the rendered texture.
|
||||
* @param screenY The screen Y coordinate at which to output the rendered texture.
|
||||
* @param color Color to apply to the texture.
|
||||
*/
|
||||
void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color)
|
||||
void FreeTypeGX::copyTextureToFramebuffer( GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color )
|
||||
{
|
||||
GX_LoadTexObj(texObj, GX_TEXMAP0);
|
||||
GX_InvalidateTexAll();
|
||||
GX_LoadTexObj( texObj, GX_TEXMAP0 );
|
||||
GX_InvalidateTexAll();
|
||||
|
||||
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
|
||||
GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
|
||||
GX_SetTevOp ( GX_TEVSTAGE0, GX_MODULATE );
|
||||
GX_SetVtxDesc ( GX_VA_TEX0, GX_DIRECT );
|
||||
|
||||
GX_Begin(GX_QUADS, this->vertexIndex, 4);
|
||||
GX_Position3s16(screenX, screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_TexCoord2f32(0.0f, 0.0f);
|
||||
GX_Begin( GX_QUADS, this->vertexIndex, 4 );
|
||||
GX_Position3s16( screenX, screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
GX_TexCoord2f32( 0.0f, 0.0f );
|
||||
|
||||
GX_Position3s16(texWidth + screenX, screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_TexCoord2f32(1.0f, 0.0f);
|
||||
GX_Position3s16( texWidth + screenX, screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
GX_TexCoord2f32( 1.0f, 0.0f );
|
||||
|
||||
GX_Position3s16(texWidth + screenX, texHeight + screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_TexCoord2f32(1.0f, 1.0f);
|
||||
GX_Position3s16( texWidth + screenX, texHeight + screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
GX_TexCoord2f32( 1.0f, 1.0f );
|
||||
|
||||
GX_Position3s16(screenX, texHeight + screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_TexCoord2f32(0.0f, 1.0f);
|
||||
GX_End();
|
||||
GX_Position3s16( screenX, texHeight + screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
GX_TexCoord2f32( 0.0f, 1.0f );
|
||||
GX_End();
|
||||
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
||||
GX_SetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
|
||||
GX_SetVtxDesc( GX_VA_TEX0, GX_NONE );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -567,31 +567,31 @@ void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 te
|
||||
*
|
||||
* This function creates a simple quad for displaying underline or strikeout text styling.
|
||||
*
|
||||
* @param featureWidth The pixel width of the quad.
|
||||
* @param featureHeight The pixel height of the quad.
|
||||
* @param screenX The screen X coordinate at which to output the quad.
|
||||
* @param screenY The screen Y coordinate at which to output the quad.
|
||||
* @param color Color to apply to the texture.
|
||||
* @param featureWidth The pixel width of the quad.
|
||||
* @param featureHeight The pixel height of the quad.
|
||||
* @param screenX The screen X coordinate at which to output the quad.
|
||||
* @param screenY The screen Y coordinate at which to output the quad.
|
||||
* @param color Color to apply to the texture.
|
||||
*/
|
||||
void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color)
|
||||
void FreeTypeGX::copyFeatureToFramebuffer( f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color )
|
||||
{
|
||||
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
||||
GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);
|
||||
GX_SetTevOp ( GX_TEVSTAGE0, GX_PASSCLR );
|
||||
GX_SetVtxDesc ( GX_VA_TEX0, GX_NONE );
|
||||
|
||||
GX_Begin(GX_QUADS, this->vertexIndex, 4);
|
||||
GX_Position3s16(screenX, screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_Begin( GX_QUADS, this->vertexIndex, 4 );
|
||||
GX_Position3s16( screenX, screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
|
||||
GX_Position3s16(featureWidth + screenX, screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_Position3s16( featureWidth + screenX, screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
|
||||
GX_Position3s16(featureWidth + screenX, featureHeight + screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_Position3s16( featureWidth + screenX, featureHeight + screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
|
||||
GX_Position3s16(screenX, featureHeight + screenY, screenZ);
|
||||
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||
GX_End();
|
||||
GX_Position3s16( screenX, featureHeight + screenY, screenZ );
|
||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
||||
GX_End();
|
||||
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
||||
GX_SetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
|
||||
GX_SetVtxDesc( GX_VA_TEX0, GX_NONE );
|
||||
}
|
||||
|
@ -37,30 +37,32 @@
|
||||
*
|
||||
* Font face character glyph relevant data structure.
|
||||
*/
|
||||
typedef struct ftgxCharData_ {
|
||||
int16_t renderOffsetX; /**< Texture X axis bearing offset. */
|
||||
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
|
||||
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
|
||||
typedef struct ftgxCharData_
|
||||
{
|
||||
int16_t renderOffsetX; /**< Texture X axis bearing offset. */
|
||||
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
|
||||
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
|
||||
|
||||
uint16_t textureWidth; /**< Texture width in pixels/bytes. */
|
||||
uint16_t textureHeight; /**< Texture glyph height in pixels/bytes. */
|
||||
uint16_t textureWidth; /**< Texture width in pixels/bytes. */
|
||||
uint16_t textureHeight; /**< Texture glyph height in pixels/bytes. */
|
||||
|
||||
int16_t renderOffsetY; /**< Texture Y axis bearing offset. */
|
||||
int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */
|
||||
int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */
|
||||
int16_t renderOffsetY; /**< Texture Y axis bearing offset. */
|
||||
int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */
|
||||
int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */
|
||||
|
||||
uint8_t* glyphDataTexture; /**< Glyph texture bitmap data buffer. */
|
||||
uint8_t* glyphDataTexture; /**< Glyph texture bitmap data buffer. */
|
||||
} ftgxCharData;
|
||||
|
||||
/*! \struct ftgxDataOffset_
|
||||
*
|
||||
* Offset structure which hold both a maximum and minimum value.
|
||||
*/
|
||||
typedef struct ftgxDataOffset_ {
|
||||
int16_t ascender; /**< Maximum data offset. */
|
||||
int16_t descender; /**< Minimum data offset. */
|
||||
int16_t max; /**< Maximum data offset. */
|
||||
int16_t min; /**< Minimum data offset. */
|
||||
typedef struct ftgxDataOffset_
|
||||
{
|
||||
int16_t ascender; /**< Maximum data offset. */
|
||||
int16_t descender; /**< Minimum data offset. */
|
||||
int16_t max; /**< Maximum data offset. */
|
||||
int16_t min; /**< Minimum data offset. */
|
||||
} ftgxDataOffset;
|
||||
|
||||
typedef struct ftgxCharData_ ftgxCharData;
|
||||
@ -68,28 +70,28 @@ typedef struct ftgxDataOffset_ ftgxDataOffset;
|
||||
|
||||
#define _TEXT(t) L ## t /**< Unicode helper macro. */
|
||||
|
||||
#define FTGX_NULL 0x0000
|
||||
#define FTGX_JUSTIFY_LEFT 0x0001
|
||||
#define FTGX_JUSTIFY_CENTER 0x0002
|
||||
#define FTGX_JUSTIFY_RIGHT 0x0004
|
||||
#define FTGX_JUSTIFY_MASK 0x000f
|
||||
#define FTGX_NULL 0x0000
|
||||
#define FTGX_JUSTIFY_LEFT 0x0001
|
||||
#define FTGX_JUSTIFY_CENTER 0x0002
|
||||
#define FTGX_JUSTIFY_RIGHT 0x0004
|
||||
#define FTGX_JUSTIFY_MASK 0x000f
|
||||
|
||||
#define FTGX_ALIGN_TOP 0x0010
|
||||
#define FTGX_ALIGN_MIDDLE 0x0020
|
||||
#define FTGX_ALIGN_BOTTOM 0x0040
|
||||
#define FTGX_ALIGN_BASELINE 0x0080
|
||||
#define FTGX_ALIGN_GLYPH_TOP 0x0100
|
||||
#define FTGX_ALIGN_GLYPH_MIDDLE 0x0200
|
||||
#define FTGX_ALIGN_GLYPH_BOTTOM 0x0400
|
||||
#define FTGX_ALIGN_MASK 0x0ff0
|
||||
#define FTGX_ALIGN_TOP 0x0010
|
||||
#define FTGX_ALIGN_MIDDLE 0x0020
|
||||
#define FTGX_ALIGN_BOTTOM 0x0040
|
||||
#define FTGX_ALIGN_BASELINE 0x0080
|
||||
#define FTGX_ALIGN_GLYPH_TOP 0x0100
|
||||
#define FTGX_ALIGN_GLYPH_MIDDLE 0x0200
|
||||
#define FTGX_ALIGN_GLYPH_BOTTOM 0x0400
|
||||
#define FTGX_ALIGN_MASK 0x0ff0
|
||||
|
||||
#define FTGX_STYLE_UNDERLINE 0x1000
|
||||
#define FTGX_STYLE_STRIKE 0x2000
|
||||
#define FTGX_STYLE_MASK 0xf000
|
||||
#define FTGX_STYLE_UNDERLINE 0x1000
|
||||
#define FTGX_STYLE_STRIKE 0x2000
|
||||
#define FTGX_STYLE_MASK 0xf000
|
||||
|
||||
const GXColor ftgxWhite = (GXColor){0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */
|
||||
const GXColor ftgxWhite = ( GXColor ) {0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */
|
||||
|
||||
wchar_t* charToWideChar(const char* p);
|
||||
wchar_t* charToWideChar( const char* p );
|
||||
|
||||
/*! \class FreeTypeGX
|
||||
* \brief Wrapper class for the libFreeType library with GX rendering.
|
||||
@ -102,41 +104,41 @@ wchar_t* charToWideChar(const char* p);
|
||||
*/
|
||||
class FreeTypeGX
|
||||
{
|
||||
private:
|
||||
private:
|
||||
FT_Library ftLibrary; /**< FreeType FT_Library instance. */
|
||||
FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */
|
||||
int16_t ftPointSize; /**< Current set size of the rendered font. */
|
||||
bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */
|
||||
uint8_t vertexIndex; /**< Vertex format descriptor index. */
|
||||
std::map<int16_t, std::map<wchar_t, ftgxCharData> > fontData; /**< Map which holds the glyph data structures for the corresponding characters in one size. */
|
||||
int16_t ftPointSize; /**< Current set size of the rendered font. */
|
||||
bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */
|
||||
uint8_t vertexIndex; /**< Vertex format descriptor index. */
|
||||
std::map<int16_t, std::map<wchar_t, ftgxCharData> > fontData; /**< Map which holds the glyph data structures for the corresponding characters in one size. */
|
||||
std::map<int16_t, ftgxDataOffset> ftgxAlign; /**< Map which holds the ascender and decender for different sizes. */
|
||||
|
||||
int16_t getStyleOffsetWidth(uint16_t width, uint16_t format);
|
||||
int16_t getStyleOffsetHeight(int16_t format, uint16_t pixelSize);
|
||||
int16_t getStyleOffsetWidth( uint16_t width, uint16_t format );
|
||||
int16_t getStyleOffsetHeight( int16_t format, uint16_t pixelSize );
|
||||
|
||||
void unloadFont();
|
||||
ftgxCharData *cacheGlyphData(wchar_t charCode, int16_t pixelSize);
|
||||
uint16_t cacheGlyphDataComplete(int16_t pixelSize);
|
||||
void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData);
|
||||
void unloadFont();
|
||||
ftgxCharData *cacheGlyphData( wchar_t charCode, int16_t pixelSize );
|
||||
uint16_t cacheGlyphDataComplete( int16_t pixelSize );
|
||||
void loadGlyphData( FT_Bitmap *bmp, ftgxCharData *charData );
|
||||
|
||||
void setDefaultMode();
|
||||
void setDefaultMode();
|
||||
|
||||
void drawTextFeature(int16_t x, int16_t y,int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color);
|
||||
void copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color);
|
||||
void copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color);
|
||||
void drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color );
|
||||
void copyTextureToFramebuffer( GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color );
|
||||
void copyFeatureToFramebuffer( f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color );
|
||||
|
||||
public:
|
||||
FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize);
|
||||
~FreeTypeGX();
|
||||
public:
|
||||
FreeTypeGX( const uint8_t* fontBuffer, FT_Long bufferSize );
|
||||
~FreeTypeGX();
|
||||
|
||||
void setVertexFormat(uint8_t vertexIndex);
|
||||
void setVertexFormat( uint8_t vertexIndex );
|
||||
|
||||
uint16_t drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL, uint16_t textWidth = 0, uint16_t widthLimit = 0);
|
||||
uint16_t drawText( int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL, uint16_t textWidth = 0, uint16_t widthLimit = 0 );
|
||||
|
||||
uint16_t getWidth(const wchar_t *text, int16_t pixelSize);
|
||||
uint16_t getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000);
|
||||
uint16_t getHeight(const wchar_t *text, int16_t pixelSize);
|
||||
void getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0);
|
||||
uint16_t getWidth( const wchar_t *text, int16_t pixelSize );
|
||||
uint16_t getCharWidth( const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000 );
|
||||
uint16_t getHeight( const wchar_t *text, int16_t pixelSize );
|
||||
void getOffset( const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0 );
|
||||
};
|
||||
|
||||
#endif /* FREETYPEGX_H_ */
|
||||
|
@ -39,16 +39,16 @@
|
||||
#include "ZipFile.h"
|
||||
#include "language/gettext.h"
|
||||
|
||||
ZipFile::ZipFile(const char *filepath)
|
||||
ZipFile::ZipFile( const char *filepath )
|
||||
{
|
||||
File = unzOpen(filepath);
|
||||
if(File)
|
||||
File = unzOpen( filepath );
|
||||
if ( File )
|
||||
this->LoadList();
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile()
|
||||
{
|
||||
unzClose(File);
|
||||
unzClose( File );
|
||||
}
|
||||
|
||||
bool ZipFile::LoadList()
|
||||
@ -56,78 +56,79 @@ bool ZipFile::LoadList()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZipFile::ExtractAll(const char *dest)
|
||||
bool ZipFile::ExtractAll( const char *dest )
|
||||
{
|
||||
if(!File)
|
||||
if ( !File )
|
||||
return false;
|
||||
|
||||
bool Stop = false;
|
||||
|
||||
u32 blocksize = 1024*50;
|
||||
u32 blocksize = 1024 * 50;
|
||||
u8 *buffer = new u8[blocksize];
|
||||
|
||||
if(!buffer)
|
||||
if ( !buffer )
|
||||
return false;
|
||||
|
||||
char writepath[MAXPATHLEN];
|
||||
char filename[MAXPATHLEN];
|
||||
memset(filename, 0, sizeof(filename));
|
||||
memset( filename, 0, sizeof( filename ) );
|
||||
|
||||
int ret = unzGoToFirstFile(File);
|
||||
if(ret != UNZ_OK)
|
||||
int ret = unzGoToFirstFile( File );
|
||||
if ( ret != UNZ_OK )
|
||||
Stop = true;
|
||||
|
||||
while(!Stop)
|
||||
while ( !Stop )
|
||||
{
|
||||
if(unzGetCurrentFileInfo(File, &cur_file_info, filename, sizeof(filename), NULL, NULL, NULL, NULL) != UNZ_OK)
|
||||
if ( unzGetCurrentFileInfo( File, &cur_file_info, filename, sizeof( filename ), NULL, NULL, NULL, NULL ) != UNZ_OK )
|
||||
Stop = true;
|
||||
|
||||
if(!Stop && filename[strlen(filename)-1] != '/')
|
||||
if ( !Stop && filename[strlen( filename )-1] != '/' )
|
||||
{
|
||||
u32 uncompressed_size = cur_file_info.uncompressed_size;
|
||||
|
||||
u32 done = 0;
|
||||
char *pointer = NULL;
|
||||
|
||||
ret = unzOpenCurrentFile(File);
|
||||
ret = unzOpenCurrentFile( File );
|
||||
|
||||
snprintf(writepath, sizeof(writepath), "%s/%s", dest, filename);
|
||||
snprintf( writepath, sizeof( writepath ), "%s/%s", dest, filename );
|
||||
|
||||
pointer = strrchr(writepath, '/');
|
||||
int position = pointer-writepath+2;
|
||||
pointer = strrchr( writepath, '/' );
|
||||
int position = pointer - writepath + 2;
|
||||
|
||||
char temppath[strlen(writepath)];
|
||||
snprintf(temppath, position, "%s", writepath);
|
||||
char temppath[strlen( writepath )];
|
||||
snprintf( temppath, position, "%s", writepath );
|
||||
|
||||
subfoldercreate(temppath);
|
||||
subfoldercreate( temppath );
|
||||
|
||||
if(ret == UNZ_OK)
|
||||
if ( ret == UNZ_OK )
|
||||
{
|
||||
FILE *pfile = fopen(writepath, "wb");
|
||||
FILE *pfile = fopen( writepath, "wb" );
|
||||
|
||||
do
|
||||
{
|
||||
ShowProgress(tr("Extracting files..."), 0, pointer+1, done, uncompressed_size);
|
||||
ShowProgress( tr( "Extracting files..." ), 0, pointer + 1, done, uncompressed_size );
|
||||
|
||||
if(uncompressed_size - done < blocksize)
|
||||
if ( uncompressed_size - done < blocksize )
|
||||
blocksize = uncompressed_size - done;
|
||||
|
||||
ret = unzReadCurrentFile(File, buffer, blocksize);
|
||||
ret = unzReadCurrentFile( File, buffer, blocksize );
|
||||
|
||||
if(ret == 0)
|
||||
if ( ret == 0 )
|
||||
break;
|
||||
|
||||
fwrite(buffer, 1, blocksize, pfile);
|
||||
fwrite( buffer, 1, blocksize, pfile );
|
||||
|
||||
done += ret;
|
||||
|
||||
} while(done < uncompressed_size);
|
||||
}
|
||||
while ( done < uncompressed_size );
|
||||
|
||||
fclose(pfile);
|
||||
unzCloseCurrentFile(File);
|
||||
fclose( pfile );
|
||||
unzCloseCurrentFile( File );
|
||||
}
|
||||
}
|
||||
if(unzGoToNextFile(File) != UNZ_OK)
|
||||
if ( unzGoToNextFile( File ) != UNZ_OK )
|
||||
Stop = true;
|
||||
}
|
||||
|
||||
|
@ -32,22 +32,22 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 offset; // ZipFile offset
|
||||
u64 length; // uncompressed file length in 64 bytes for sizes higher than 4GB
|
||||
bool isdir; // 0 - file, 1 - directory
|
||||
char filename[256]; // full filename
|
||||
u64 offset; // ZipFile offset
|
||||
u64 length; // uncompressed file length in 64 bytes for sizes higher than 4GB
|
||||
bool isdir; // 0 - file, 1 - directory
|
||||
char filename[256]; // full filename
|
||||
} FileStructure;
|
||||
|
||||
class ZipFile
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
ZipFile(const char *filepath);
|
||||
//!Destructor
|
||||
~ZipFile();
|
||||
//!Extract all files from a zip file to a directory
|
||||
//!\param dest Destination path to where to extract
|
||||
bool ExtractAll(const char *dest);
|
||||
//!Constructor
|
||||
ZipFile( const char *filepath );
|
||||
//!Destructor
|
||||
~ZipFile();
|
||||
//!Extract all files from a zip file to a directory
|
||||
//!\param dest Destination path to where to extract
|
||||
bool ExtractAll( const char *dest );
|
||||
protected:
|
||||
bool LoadList();
|
||||
unzFile File;
|
||||
|
@ -15,10 +15,11 @@
|
||||
*
|
||||
* Initializes the Wii's audio subsystem
|
||||
***************************************************************************/
|
||||
void InitAudio() {
|
||||
AUDIO_Init(NULL);
|
||||
void InitAudio()
|
||||
{
|
||||
AUDIO_Init( NULL );
|
||||
ASND_Init();
|
||||
ASND_Pause(0);
|
||||
ASND_Pause( 0 );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -27,7 +28,8 @@ void InitAudio() {
|
||||
* Shuts down audio subsystem. Useful to avoid unpleasant sounds if a
|
||||
* crash occurs during shutdown.
|
||||
***************************************************************************/
|
||||
void ShutdownAudio() {
|
||||
ASND_Pause(1);
|
||||
void ShutdownAudio()
|
||||
{
|
||||
ASND_Pause( 1 );
|
||||
ASND_End();
|
||||
}
|
||||
|
@ -111,28 +111,28 @@
|
||||
*/
|
||||
|
||||
static const uint8_t K[3][16] =
|
||||
{
|
||||
{
|
||||
/* Round 1: skipped (since it is simply sequential). */
|
||||
{ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, /* R2 */
|
||||
{ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, /* R3 */
|
||||
{ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 } /* R4 */
|
||||
};
|
||||
};
|
||||
|
||||
static const uint8_t S[4][4] =
|
||||
{
|
||||
{
|
||||
{ 7, 12, 17, 22 }, /* Round 1 */
|
||||
{ 5, 9, 14, 20 }, /* Round 2 */
|
||||
{ 4, 11, 16, 23 }, /* Round 3 */
|
||||
{ 6, 10, 15, 21 } /* Round 4 */
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
static const uint32_t T[4][16] =
|
||||
{
|
||||
{
|
||||
{ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 },
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 },
|
||||
|
||||
{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
@ -148,7 +148,7 @@ static const uint32_t T[4][16] =
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 },
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
@ -178,122 +178,122 @@ static const uint32_t T[4][16] =
|
||||
*/
|
||||
|
||||
static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
|
||||
*
|
||||
* Input: ABCD - Pointer to an array of four unsigned longwords.
|
||||
* block - An array of bytes, 64 bytes in size.
|
||||
*
|
||||
* Output: none.
|
||||
*
|
||||
* Notes: The MD5 algorithm operates on a set of four longwords stored
|
||||
* (conceptually) in four "registers". It is easy to imagine a
|
||||
* simple MD4/5 chip that would operate this way. In any case,
|
||||
* the mangling of the contents of those registers is driven by
|
||||
* the input message. The message is chopped and finally padded
|
||||
* into 64-byte chunks and each chunk is used to manipulate the
|
||||
* contents of the registers.
|
||||
*
|
||||
* The MD5 Algorithm calls for padding the input to ensure that
|
||||
* it is a multiple of 64 bytes in length. The last 16 bytes
|
||||
* of the padding space are used to store the message length
|
||||
* (the length of the original message, before padding, expressed
|
||||
* in terms of bits). If there is not enough room for 16 bytes
|
||||
* worth of bitcount (eg., if the original message was 122 bytes
|
||||
* long) then the block is padded to the end with zeros and
|
||||
* passed to this function. Then *another* block is filled with
|
||||
* zeros except for the last 16 bytes which contain the length.
|
||||
*
|
||||
* Oh... and the algorithm requires that there be at least one
|
||||
* padding byte. The first padding byte has a value of 0x80,
|
||||
* and any others are 0x00.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int round;
|
||||
int i, j;
|
||||
uint8_t s;
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t KeepABCD[4];
|
||||
uint32_t X[16];
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
|
||||
*
|
||||
* Input: ABCD - Pointer to an array of four unsigned longwords.
|
||||
* block - An array of bytes, 64 bytes in size.
|
||||
*
|
||||
* Output: none.
|
||||
*
|
||||
* Notes: The MD5 algorithm operates on a set of four longwords stored
|
||||
* (conceptually) in four "registers". It is easy to imagine a
|
||||
* simple MD4/5 chip that would operate this way. In any case,
|
||||
* the mangling of the contents of those registers is driven by
|
||||
* the input message. The message is chopped and finally padded
|
||||
* into 64-byte chunks and each chunk is used to manipulate the
|
||||
* contents of the registers.
|
||||
*
|
||||
* The MD5 Algorithm calls for padding the input to ensure that
|
||||
* it is a multiple of 64 bytes in length. The last 16 bytes
|
||||
* of the padding space are used to store the message length
|
||||
* (the length of the original message, before padding, expressed
|
||||
* in terms of bits). If there is not enough room for 16 bytes
|
||||
* worth of bitcount (eg., if the original message was 122 bytes
|
||||
* long) then the block is padded to the end with zeros and
|
||||
* passed to this function. Then *another* block is filled with
|
||||
* zeros except for the last 16 bytes which contain the length.
|
||||
*
|
||||
* Oh... and the algorithm requires that there be at least one
|
||||
* padding byte. The first padding byte has a value of 0x80,
|
||||
* and any others are 0x00.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int round;
|
||||
int i, j;
|
||||
uint8_t s;
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t KeepABCD[4];
|
||||
uint32_t X[16];
|
||||
|
||||
/* Store the current ABCD values for later re-use.
|
||||
*/
|
||||
for( i = 0; i < 4; i++ )
|
||||
KeepABCD[i] = ABCD[i];
|
||||
/* Store the current ABCD values for later re-use.
|
||||
*/
|
||||
for ( i = 0; i < 4; i++ )
|
||||
KeepABCD[i] = ABCD[i];
|
||||
|
||||
/* Convert the input block into an array of unsigned longs, taking care
|
||||
* to read the block in Little Endian order (the algorithm assumes this).
|
||||
* The uint32_t values are then handled in host order.
|
||||
*/
|
||||
for( i = 0, j = 0; i < 16; i++ )
|
||||
/* Convert the input block into an array of unsigned longs, taking care
|
||||
* to read the block in Little Endian order (the algorithm assumes this).
|
||||
* The uint32_t values are then handled in host order.
|
||||
*/
|
||||
for ( i = 0, j = 0; i < 16; i++ )
|
||||
{
|
||||
X[i] = (uint32_t)block[j++];
|
||||
X[i] |= ((uint32_t)block[j++] << 8);
|
||||
X[i] |= ((uint32_t)block[j++] << 16);
|
||||
X[i] |= ((uint32_t)block[j++] << 24);
|
||||
X[i] = ( uint32_t )block[j++];
|
||||
X[i] |= ( ( uint32_t )block[j++] << 8 );
|
||||
X[i] |= ( ( uint32_t )block[j++] << 16 );
|
||||
X[i] |= ( ( uint32_t )block[j++] << 24 );
|
||||
}
|
||||
|
||||
/* This loop performs the four rounds of permutations.
|
||||
* The rounds are each very similar. The differences are in three areas:
|
||||
* - The function (F, G, H, or I) used to perform bitwise permutations
|
||||
* on the registers,
|
||||
* - The order in which values from X[] are chosen.
|
||||
* - Changes to the number of bits by which the registers are rotated.
|
||||
* This implementation uses a switch statement to deal with some of the
|
||||
* differences between rounds. Other differences are handled by storing
|
||||
* values in arrays and using the round number to select the correct set
|
||||
* of values.
|
||||
*
|
||||
* (My implementation appears to be a poor compromise between speed, size,
|
||||
* and clarity. Ugh. [crh])
|
||||
*/
|
||||
for( round = 0; round < 4; round++ )
|
||||
/* This loop performs the four rounds of permutations.
|
||||
* The rounds are each very similar. The differences are in three areas:
|
||||
* - The function (F, G, H, or I) used to perform bitwise permutations
|
||||
* on the registers,
|
||||
* - The order in which values from X[] are chosen.
|
||||
* - Changes to the number of bits by which the registers are rotated.
|
||||
* This implementation uses a switch statement to deal with some of the
|
||||
* differences between rounds. Other differences are handled by storing
|
||||
* values in arrays and using the round number to select the correct set
|
||||
* of values.
|
||||
*
|
||||
* (My implementation appears to be a poor compromise between speed, size,
|
||||
* and clarity. Ugh. [crh])
|
||||
*/
|
||||
for ( round = 0; round < 4; round++ )
|
||||
{
|
||||
for( i = 0; i < 16; i++ )
|
||||
{
|
||||
j = (4 - (i % 4)) & 0x3; /* <j> handles the rotation of ABCD. */
|
||||
s = S[round][i%4]; /* <s> is the bit shift for this iteration. */
|
||||
|
||||
b = ABCD[(j+1) & 0x3]; /* Copy the b,c,d values per ABCD rotation. */
|
||||
c = ABCD[(j+2) & 0x3]; /* This isn't really necessary, it just looks */
|
||||
d = ABCD[(j+3) & 0x3]; /* clean & will hopefully be optimized away. */
|
||||
|
||||
/* The actual perumation function.
|
||||
* This is broken out to minimize the code within the switch().
|
||||
*/
|
||||
switch( round )
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
case 0:
|
||||
/* round 1 */
|
||||
a = md5F( b, c, d ) + X[i];
|
||||
break;
|
||||
case 1:
|
||||
/* round 2 */
|
||||
a = md5G( b, c, d ) + X[ K[0][i] ];
|
||||
break;
|
||||
case 2:
|
||||
/* round 3 */
|
||||
a = md5H( b, c, d ) + X[ K[1][i] ];
|
||||
break;
|
||||
default:
|
||||
/* round 4 */
|
||||
a = md5I( b, c, d ) + X[ K[2][i] ];
|
||||
break;
|
||||
j = ( 4 - ( i % 4 ) ) & 0x3; /* <j> handles the rotation of ABCD. */
|
||||
s = S[round][i%4]; /* <s> is the bit shift for this iteration. */
|
||||
|
||||
b = ABCD[( j+1 ) & 0x3]; /* Copy the b,c,d values per ABCD rotation. */
|
||||
c = ABCD[( j+2 ) & 0x3]; /* This isn't really necessary, it just looks */
|
||||
d = ABCD[( j+3 ) & 0x3]; /* clean & will hopefully be optimized away. */
|
||||
|
||||
/* The actual perumation function.
|
||||
* This is broken out to minimize the code within the switch().
|
||||
*/
|
||||
switch ( round )
|
||||
{
|
||||
case 0:
|
||||
/* round 1 */
|
||||
a = md5F( b, c, d ) + X[i];
|
||||
break;
|
||||
case 1:
|
||||
/* round 2 */
|
||||
a = md5G( b, c, d ) + X[ K[0][i] ];
|
||||
break;
|
||||
case 2:
|
||||
/* round 3 */
|
||||
a = md5H( b, c, d ) + X[ K[1][i] ];
|
||||
break;
|
||||
default:
|
||||
/* round 4 */
|
||||
a = md5I( b, c, d ) + X[ K[2][i] ];
|
||||
break;
|
||||
}
|
||||
a = 0xFFFFFFFF & ( ABCD[j] + a + T[round][i] );
|
||||
ABCD[j] = b + ( 0xFFFFFFFF & ( ( a << s ) | ( a >> ( 32 - s ) ) ) );
|
||||
}
|
||||
a = 0xFFFFFFFF & ( ABCD[j] + a + T[round][i] );
|
||||
ABCD[j] = b + (0xFFFFFFFF & (( a << s ) | ( a >> (32 - s) )));
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the stored original A, B, C, D values to perform
|
||||
* one last convolution.
|
||||
*/
|
||||
for( i = 0; i < 4; i++ )
|
||||
ABCD[i] = 0xFFFFFFFF & ( ABCD[i] + KeepABCD[i] );
|
||||
/* Use the stored original A, B, C, D values to perform
|
||||
* one last convolution.
|
||||
*/
|
||||
for ( i = 0; i < 4; i++ )
|
||||
ABCD[i] = 0xFFFFFFFF & ( ABCD[i] + KeepABCD[i] );
|
||||
|
||||
} /* Permute */
|
||||
} /* Permute */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
@ -301,304 +301,307 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
*/
|
||||
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
ctx->len = 0;
|
||||
ctx->b_used = 0;
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
ctx->len = 0;
|
||||
ctx->b_used = 0;
|
||||
|
||||
ctx->ABCD[0] = 0x67452301; /* The array ABCD[] contains the four 4-byte */
|
||||
ctx->ABCD[1] = 0xefcdab89; /* "registers" that are manipulated to */
|
||||
ctx->ABCD[2] = 0x98badcfe; /* produce the MD5 digest. The input acts */
|
||||
ctx->ABCD[3] = 0x10325476; /* upon the registers, not the other way */
|
||||
/* 'round. The initial values are those */
|
||||
/* given in RFC 1321 (pg. 4). Note, however, that RFC 1321 */
|
||||
/* provides these values as bytes, not as longwords, and the */
|
||||
/* bytes are arranged in little-endian order as if they were */
|
||||
/* the bytes of (little endian) 32-bit ints. That's */
|
||||
/* confusing as all getout (to me, anyway). The values given */
|
||||
/* here are provided as 32-bit values in C language format, */
|
||||
/* so they are endian-agnostic. */
|
||||
return( ctx );
|
||||
} /* auth_md5InitCtx */
|
||||
ctx->ABCD[0] = 0x67452301; /* The array ABCD[] contains the four 4-byte */
|
||||
ctx->ABCD[1] = 0xefcdab89; /* "registers" that are manipulated to */
|
||||
ctx->ABCD[2] = 0x98badcfe; /* produce the MD5 digest. The input acts */
|
||||
ctx->ABCD[3] = 0x10325476; /* upon the registers, not the other way */
|
||||
/* 'round. The initial values are those */
|
||||
/* given in RFC 1321 (pg. 4). Note, however, that RFC 1321 */
|
||||
/* provides these values as bytes, not as longwords, and the */
|
||||
/* bytes are arranged in little-endian order as if they were */
|
||||
/* the bytes of (little endian) 32-bit ints. That's */
|
||||
/* confusing as all getout (to me, anyway). The values given */
|
||||
/* here are provided as 32-bit values in C language format, */
|
||||
/* so they are endian-agnostic. */
|
||||
return( ctx );
|
||||
} /* auth_md5InitCtx */
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
const unsigned char *src,
|
||||
const int len )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Add the new block's length to the total length.
|
||||
*/
|
||||
ctx->len += (uint32_t)len;
|
||||
/* Add the new block's length to the total length.
|
||||
*/
|
||||
ctx->len += ( uint32_t )len;
|
||||
|
||||
/* Copy the new block's data into the context block.
|
||||
* Call the Permute() function whenever the context block is full.
|
||||
*/
|
||||
for( i = 0; i < len; i++ )
|
||||
/* Copy the new block's data into the context block.
|
||||
* Call the Permute() function whenever the context block is full.
|
||||
*/
|
||||
for ( i = 0; i < len; i++ )
|
||||
{
|
||||
ctx->block[ ctx->b_used ] = src[i];
|
||||
(ctx->b_used)++;
|
||||
if( 64 == ctx->b_used )
|
||||
{
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
ctx->b_used = 0;
|
||||
}
|
||||
ctx->block[ ctx->b_used ] = src[i];
|
||||
( ctx->b_used )++;
|
||||
if ( 64 == ctx->b_used )
|
||||
{
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
ctx->b_used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the updated context.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5SumCtx */
|
||||
/* Return the updated context.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5SumCtx */
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
uint32_t l;
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
uint32_t l;
|
||||
|
||||
/* Add the required 0x80 padding initiator byte.
|
||||
* The auth_md5SumCtx() function always permutes and resets the context
|
||||
* block when it gets full, so we know that there must be at least one
|
||||
* free byte in the context block.
|
||||
*/
|
||||
ctx->block[ctx->b_used] = 0x80;
|
||||
(ctx->b_used)++;
|
||||
/* Add the required 0x80 padding initiator byte.
|
||||
* The auth_md5SumCtx() function always permutes and resets the context
|
||||
* block when it gets full, so we know that there must be at least one
|
||||
* free byte in the context block.
|
||||
*/
|
||||
ctx->block[ctx->b_used] = 0x80;
|
||||
( ctx->b_used )++;
|
||||
|
||||
/* Zero out any remaining free bytes in the context block.
|
||||
*/
|
||||
for( i = ctx->b_used; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
/* Zero out any remaining free bytes in the context block.
|
||||
*/
|
||||
for ( i = ctx->b_used; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
|
||||
/* We need 8 bytes to store the length field.
|
||||
* If we don't have 8, call Permute() and reset the context block.
|
||||
*/
|
||||
if( 56 < ctx->b_used )
|
||||
/* We need 8 bytes to store the length field.
|
||||
* If we don't have 8, call Permute() and reset the context block.
|
||||
*/
|
||||
if ( 56 < ctx->b_used )
|
||||
{
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
for ( i = 0; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
}
|
||||
|
||||
/* Add the total length and perform the final perumation.
|
||||
* Note: The 60'th byte is read from the *original* <ctx->len> value
|
||||
* and shifted to the correct position. This neatly avoids
|
||||
* any MAXINT numeric overflow issues.
|
||||
*/
|
||||
l = ctx->len << 3;
|
||||
for ( i = 0; i < 4; i++ )
|
||||
ctx->block[56+i] |= GetLongByte( l, i );
|
||||
ctx->block[60] = ( ( GetLongByte( ctx->len, 3 ) & 0xE0 ) >> 5 ); /* See Above! */
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
for( i = 0; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
}
|
||||
|
||||
/* Add the total length and perform the final perumation.
|
||||
* Note: The 60'th byte is read from the *original* <ctx->len> value
|
||||
* and shifted to the correct position. This neatly avoids
|
||||
* any MAXINT numeric overflow issues.
|
||||
*/
|
||||
l = ctx->len << 3;
|
||||
for( i = 0; i < 4; i++ )
|
||||
ctx->block[56+i] |= GetLongByte( l, i );
|
||||
ctx->block[60] = ((GetLongByte( ctx->len, 3 ) & 0xE0) >> 5); /* See Above! */
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
|
||||
/* Now copy the result into the output buffer and we're done.
|
||||
*/
|
||||
for( i = 0; i < 4; i++ )
|
||||
/* Now copy the result into the output buffer and we're done.
|
||||
*/
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
dst[ 0+i] = GetLongByte( ctx->ABCD[0], i );
|
||||
dst[ 4+i] = GetLongByte( ctx->ABCD[1], i );
|
||||
dst[ 8+i] = GetLongByte( ctx->ABCD[2], i );
|
||||
dst[12+i] = GetLongByte( ctx->ABCD[3], i );
|
||||
dst[ 0+i] = GetLongByte( ctx->ABCD[0], i );
|
||||
dst[ 4+i] = GetLongByte( ctx->ABCD[1], i );
|
||||
dst[ 8+i] = GetLongByte( ctx->ABCD[2], i );
|
||||
dst[12+i] = GetLongByte( ctx->ABCD[3], i );
|
||||
}
|
||||
|
||||
/* Return the context.
|
||||
* This is done for compatibility with the other auth_md5*Ctx() functions.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5CloseCtx */
|
||||
/* Return the context.
|
||||
* This is done for compatibility with the other auth_md5*Ctx() functions.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5CloseCtx */
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
unsigned char * MD5( unsigned char *dst, const unsigned char *src, const int len )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
|
||||
(void)auth_md5InitCtx( ctx ); /* Open a context. */
|
||||
(void)auth_md5SumCtx( ctx, src, len ); /* Pass only one block. */
|
||||
(void)auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
||||
( void )auth_md5InitCtx( ctx ); /* Open a context. */
|
||||
( void )auth_md5SumCtx( ctx, src, len ); /* Pass only one block. */
|
||||
( void )auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
||||
|
||||
return( dst ); /* Makes life easy. */
|
||||
} /* auth_md5Sum */
|
||||
return( dst ); /* Makes life easy. */
|
||||
} /* auth_md5Sum */
|
||||
|
||||
|
||||
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath of the file to be checked
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
unsigned char * MD5fromFile( unsigned char *dst, const char *src )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath of the file to be checked
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
auth_md5Ctx ctx[1];
|
||||
|
||||
FILE * file;
|
||||
unsigned int blksize = 0;
|
||||
unsigned int read = 0;
|
||||
|
||||
file = fopen(src, "rb");
|
||||
file = fopen( src, "rb" );
|
||||
|
||||
if (file==NULL){
|
||||
if ( file == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)auth_md5InitCtx( ctx ); /* Open a context. */
|
||||
( void )auth_md5InitCtx( ctx ); /* Open a context. */
|
||||
|
||||
fseek (file , 0 , SEEK_END);
|
||||
unsigned long long filesize = ftell(file);
|
||||
rewind (file);
|
||||
fseek ( file , 0 , SEEK_END );
|
||||
unsigned long long filesize = ftell( file );
|
||||
rewind ( file );
|
||||
|
||||
if(filesize < 1048576) //1MB cache for files bigger than 1 MB
|
||||
if ( filesize < 1048576 ) //1MB cache for files bigger than 1 MB
|
||||
blksize = filesize;
|
||||
else
|
||||
blksize = 1048576;
|
||||
|
||||
unsigned char * buffer = malloc(blksize);
|
||||
unsigned char * buffer = malloc( blksize );
|
||||
|
||||
if(buffer == NULL){
|
||||
//no memory
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
if ( buffer == NULL )
|
||||
{
|
||||
//no memory
|
||||
fclose( file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
read = fread(buffer, 1, blksize, file);
|
||||
(void)auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
|
||||
do
|
||||
{
|
||||
read = fread( buffer, 1, blksize, file );
|
||||
( void )auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
|
||||
|
||||
} while(read > 0);
|
||||
}
|
||||
while ( read > 0 );
|
||||
|
||||
fclose(file);
|
||||
free(buffer);
|
||||
fclose( file );
|
||||
free( buffer );
|
||||
|
||||
(void)auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
||||
( void )auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
||||
|
||||
return( dst ); /* Makes life easy. */
|
||||
} /* auth_md5Sum */
|
||||
} /* auth_md5Sum */
|
||||
|
||||
|
||||
const char * MD5ToString(const unsigned char * hash, char * dst)
|
||||
const char * MD5ToString( const unsigned char * hash, char * dst )
|
||||
{
|
||||
char hexchar[3];
|
||||
short i = 0, n = 0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
sprintf(hexchar, "%02X", hash[i]);
|
||||
sprintf( hexchar, "%02X", hash[i] );
|
||||
|
||||
dst[n++] = hexchar[0];
|
||||
dst[n++] = hexchar[1];
|
||||
@ -609,19 +612,19 @@ const char * MD5ToString(const unsigned char * hash, char * dst)
|
||||
return dst;
|
||||
}
|
||||
|
||||
unsigned char * StringToMD5(const char * hash, unsigned char * dst)
|
||||
unsigned char * StringToMD5( const char * hash, unsigned char * dst )
|
||||
{
|
||||
char hexchar[2];
|
||||
short i = 0, n = 0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
hexchar[0] = hash[n++];
|
||||
hexchar[1] = hash[n++];
|
||||
|
||||
dst[i] = STR2HEX(hexchar[0]);
|
||||
dst[i] = STR2HEX( hexchar[0] );
|
||||
dst[i] <<= 4;
|
||||
dst[i] += STR2HEX(hexchar[1]);
|
||||
dst[i] += STR2HEX( hexchar[1] );
|
||||
}
|
||||
|
||||
return dst;
|
||||
|
@ -5,240 +5,240 @@
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/* ========================================================================== **
|
||||
*
|
||||
* MD5.h
|
||||
*
|
||||
* Copyright:
|
||||
* Copyright (C) 2003-2005 by Christopher R. Hertel
|
||||
*
|
||||
* Email: crh@ubiqx.mn.org
|
||||
*
|
||||
* $Id: MD5.h,v 0.6 2005/06/08 18:35:59 crh Exp $
|
||||
*
|
||||
* Modifications and additions by dimok
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* Description:
|
||||
* Implements the MD5 hash algorithm, as described in RFC 1321.
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* License:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* None of this will make any sense unless you're studying RFC 1321 as you
|
||||
* read the code.
|
||||
*
|
||||
* MD5 is described in RFC 1321.
|
||||
* The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1).
|
||||
* MD5 is very similar to MD4, but not quite similar enough to justify
|
||||
* putting the two into a single module. Besides, I wanted to add a few
|
||||
* extra functions to this one to expand its usability.
|
||||
*
|
||||
* There are three primary motivations for this particular implementation.
|
||||
* 1) Programmer's pride. I wanted to be able to say I'd done it, and I
|
||||
* wanted to learn from the experience.
|
||||
* 2) Portability. I wanted an implementation that I knew to be portable
|
||||
* to a reasonable number of platforms. In particular, the algorithm is
|
||||
* designed with little-endian platforms in mind, but I wanted an
|
||||
* endian-agnostic implementation.
|
||||
* 3) Compactness. While not an overriding goal, I thought it worth-while
|
||||
* to see if I could reduce the overall size of the result. This is in
|
||||
* keeping with my hopes that this library will be suitable for use in
|
||||
* some embedded environments.
|
||||
* Beyond that, cleanliness and clarity are always worth pursuing.
|
||||
*
|
||||
* As mentioned above, the code really only makes sense if you are familiar
|
||||
* with the MD5 algorithm or are using RFC 1321 as a guide. This code is
|
||||
* quirky, however, so you'll want to be reading carefully.
|
||||
*
|
||||
* Yeah...most of the comments are cut-and-paste from my MD4 implementation.
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* References:
|
||||
* IETF RFC 1321: The MD5 Message-Digest Algorithm
|
||||
* Ron Rivest. IETF, April, 1992
|
||||
*
|
||||
* ========================================================================== **
|
||||
*/
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Typedefs:
|
||||
*/
|
||||
/* ========================================================================== **
|
||||
*
|
||||
* MD5.h
|
||||
*
|
||||
* Copyright:
|
||||
* Copyright (C) 2003-2005 by Christopher R. Hertel
|
||||
*
|
||||
* Email: crh@ubiqx.mn.org
|
||||
*
|
||||
* $Id: MD5.h,v 0.6 2005/06/08 18:35:59 crh Exp $
|
||||
*
|
||||
* Modifications and additions by dimok
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* Description:
|
||||
* Implements the MD5 hash algorithm, as described in RFC 1321.
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* License:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* None of this will make any sense unless you're studying RFC 1321 as you
|
||||
* read the code.
|
||||
*
|
||||
* MD5 is described in RFC 1321.
|
||||
* The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1).
|
||||
* MD5 is very similar to MD4, but not quite similar enough to justify
|
||||
* putting the two into a single module. Besides, I wanted to add a few
|
||||
* extra functions to this one to expand its usability.
|
||||
*
|
||||
* There are three primary motivations for this particular implementation.
|
||||
* 1) Programmer's pride. I wanted to be able to say I'd done it, and I
|
||||
* wanted to learn from the experience.
|
||||
* 2) Portability. I wanted an implementation that I knew to be portable
|
||||
* to a reasonable number of platforms. In particular, the algorithm is
|
||||
* designed with little-endian platforms in mind, but I wanted an
|
||||
* endian-agnostic implementation.
|
||||
* 3) Compactness. While not an overriding goal, I thought it worth-while
|
||||
* to see if I could reduce the overall size of the result. This is in
|
||||
* keeping with my hopes that this library will be suitable for use in
|
||||
* some embedded environments.
|
||||
* Beyond that, cleanliness and clarity are always worth pursuing.
|
||||
*
|
||||
* As mentioned above, the code really only makes sense if you are familiar
|
||||
* with the MD5 algorithm or are using RFC 1321 as a guide. This code is
|
||||
* quirky, however, so you'll want to be reading carefully.
|
||||
*
|
||||
* Yeah...most of the comments are cut-and-paste from my MD4 implementation.
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* References:
|
||||
* IETF RFC 1321: The MD5 Message-Digest Algorithm
|
||||
* Ron Rivest. IETF, April, 1992
|
||||
*
|
||||
* ========================================================================== **
|
||||
*/
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Typedefs:
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int ABCD[4];
|
||||
int b_used;
|
||||
unsigned char block[64];
|
||||
} auth_md5Ctx;
|
||||
typedef struct
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int ABCD[4];
|
||||
int b_used;
|
||||
unsigned char block[64];
|
||||
} auth_md5Ctx;
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions:
|
||||
*/
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions:
|
||||
*/
|
||||
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
* Input: ctx - A pointer to the MD5 context structure to be initialized.
|
||||
* Contexts are typically created thusly:
|
||||
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
|
||||
*
|
||||
* Output: A pointer to the initialized context (same as <ctx>).
|
||||
*
|
||||
* Notes: The purpose of the context is to make it possible to generate
|
||||
* an MD5 Message Digest in stages, rather than having to pass a
|
||||
* single large block to a single MD5 function. The context
|
||||
* structure keeps track of various bits of state information.
|
||||
*
|
||||
* Once the context is initialized, the blocks of message data
|
||||
* are passed to the <auth_md5SumCtx()> function. Once the
|
||||
* final bit of data has been handed to <auth_md5SumCtx()> the
|
||||
* context can be closed out by calling <auth_md5CloseCtx()>,
|
||||
* which also calculates the final MD5 result.
|
||||
*
|
||||
* Don't forget to free an allocated context structure when
|
||||
* you've finished using it.
|
||||
*
|
||||
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
const unsigned char *src,
|
||||
const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
const unsigned char *src,
|
||||
const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Build an MD5 Message Digest within the given context.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* src - A chunk of source data. This will be used to drive
|
||||
* the MD5 algorithm.
|
||||
* len - The number of bytes in <src>.
|
||||
*
|
||||
* Output: A pointer to the updated context (same as <ctx>).
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
* Input: ctx - Pointer to the context in which the MD5 sum is being
|
||||
* built.
|
||||
* dst - A pointer to at least 16 bytes of memory, which will
|
||||
* receive the finished MD5 sum.
|
||||
*
|
||||
* Output: A pointer to the closed context (same as <ctx>).
|
||||
* You might use this to free a malloc'd context structure. :)
|
||||
*
|
||||
* Notes: The context (<ctx>) is returned in an undefined state.
|
||||
* It must be re-initialized before re-use.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
unsigned char * MD5( unsigned char * hash, const unsigned char *src, const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - Source data block to be MD5'd.
|
||||
* len - The length, in bytes, of the source block.
|
||||
* (Note that the length is given in bytes, not bits.)
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src);
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath to the file to be MD5'd.
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
unsigned char * MD5fromFile( unsigned char *dst, const char *src );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
* Input: dst - Destination buffer into which the result will be written.
|
||||
* Must be 16 bytes, minimum.
|
||||
* src - filepath to the file to be MD5'd.
|
||||
*
|
||||
* Output: A pointer to <dst>, which will contain the calculated 16-byte
|
||||
* MD5 message digest.
|
||||
*
|
||||
* Notes: This function is a shortcut. It takes a single input block.
|
||||
* For more drawn-out operations, see <auth_md5InitCtx()>.
|
||||
*
|
||||
* This function is interface-compatible with the
|
||||
* <auth_md4Sum()> function in the MD4 module.
|
||||
*
|
||||
* The MD5 algorithm is designed to work on data with an
|
||||
* arbitrary *bit* length. Most implementations, this one
|
||||
* included, handle the input data in byte-sized chunks.
|
||||
*
|
||||
* The MD5 algorithm does much of its work using four-byte
|
||||
* words, and so can be tuned for speed based on the endian-ness
|
||||
* of the host. This implementation is intended to be
|
||||
* endian-neutral, which may make it a teeny bit slower than
|
||||
* others. ...maybe.
|
||||
*
|
||||
* See Also: <auth_md5InitCtx()>
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
const char * MD5ToString(const unsigned char *hash, char *dst);
|
||||
unsigned char * StringToMD5(const char * hash, unsigned char * dst);
|
||||
const char * MD5ToString( const unsigned char *hash, char *dst );
|
||||
unsigned char * StringToMD5( const char * hash, unsigned char * dst );
|
||||
|
||||
/* ========================================================================== */
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -22,106 +22,107 @@
|
||||
#include "patches/fst.h"
|
||||
#include "usbloader/fstfile.h"
|
||||
|
||||
s32 dump_banner(const u8* discid,const char * dest)
|
||||
s32 dump_banner( const u8* discid, const char * dest )
|
||||
{
|
||||
// Mount the disc
|
||||
//Disc_SetWBFS(1, (u8*)discid);
|
||||
Disc_SetUSB(discid);
|
||||
// Mount the disc
|
||||
//Disc_SetWBFS(1, (u8*)discid);
|
||||
Disc_SetUSB( discid );
|
||||
|
||||
Disc_Open();
|
||||
Disc_Open();
|
||||
|
||||
u64 offset;
|
||||
s32 ret;
|
||||
u64 offset;
|
||||
s32 ret;
|
||||
|
||||
ret = __Disc_FindPartition(&offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = __Disc_FindPartition( &offset );
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
|
||||
ret = WDVD_OpenPartition(offset);
|
||||
ret = WDVD_OpenPartition( offset );
|
||||
|
||||
if (ret < 0) {
|
||||
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
if ( ret < 0 )
|
||||
{
|
||||
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read where to find the fst.bin
|
||||
u32 *buffer = memalign(32, 0x20);
|
||||
// Read where to find the fst.bin
|
||||
u32 *buffer = memalign( 32, 0x20 );
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
//Out of memory
|
||||
return -1;
|
||||
}
|
||||
if ( buffer == NULL )
|
||||
{
|
||||
//Out of memory
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read(buffer, 0x20, 0x420);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = WDVD_Read( buffer, 0x20, 0x420 );
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
|
||||
// Read fst.bin
|
||||
void *fstbuffer = memalign(32, buffer[2]*4);
|
||||
FST_ENTRY *fst = (FST_ENTRY *)fstbuffer;
|
||||
// Read fst.bin
|
||||
void *fstbuffer = memalign( 32, buffer[2] * 4 );
|
||||
FST_ENTRY *fst = ( FST_ENTRY * )fstbuffer;
|
||||
|
||||
if (fst == NULL)
|
||||
{
|
||||
//Out of memory
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
if ( fst == NULL )
|
||||
{
|
||||
//Out of memory
|
||||
free( buffer );
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read(fstbuffer, buffer[2]*4, buffer[1]*4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = WDVD_Read( fstbuffer, buffer[2] * 4, buffer[1] * 4 );
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
|
||||
free(buffer);
|
||||
free( buffer );
|
||||
|
||||
// Search the fst.bin
|
||||
u32 count = fst[0].filelen;
|
||||
int i;
|
||||
u32 index = 0;
|
||||
// Search the fst.bin
|
||||
u32 count = fst[0].filelen;
|
||||
int i;
|
||||
u32 index = 0;
|
||||
|
||||
for (i=1;i<count;i++)
|
||||
{
|
||||
if (strstr(fstfiles(fst, i), "opening.bnr") != NULL)
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
for ( i = 1; i < count; i++ )
|
||||
{
|
||||
if ( strstr( fstfiles( fst, i ), "opening.bnr" ) != NULL )
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
//opening.bnr not found
|
||||
free(fstbuffer);
|
||||
return -1;
|
||||
}
|
||||
if ( index == 0 )
|
||||
{
|
||||
//opening.bnr not found
|
||||
free( fstbuffer );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Load the .bnr
|
||||
u8 *banner = memalign(32, fst[index].filelen);
|
||||
// Load the .bnr
|
||||
u8 *banner = memalign( 32, fst[index].filelen );
|
||||
|
||||
if (banner == NULL)
|
||||
{
|
||||
//Out of memory
|
||||
free(fstbuffer);
|
||||
return -1;
|
||||
}
|
||||
if ( banner == NULL )
|
||||
{
|
||||
//Out of memory
|
||||
free( fstbuffer );
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read((void *)banner, fst[index].filelen, fst[index].fileoffset * 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = WDVD_Read( ( void * )banner, fst[index].filelen, fst[index].fileoffset * 4 );
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
|
||||
WDVD_Reset();
|
||||
WDVD_ClosePartition();
|
||||
//fatInitDefault();
|
||||
//SDCard_Init();
|
||||
WDVD_SetUSBMode(NULL, 0);
|
||||
FILE *fp = fopen(dest, "wb");
|
||||
if(fp)
|
||||
{
|
||||
fwrite(banner, 1, fst[index].filelen, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
free(fstbuffer);
|
||||
free(banner);
|
||||
//fatInitDefault();
|
||||
//SDCard_Init();
|
||||
WDVD_SetUSBMode( NULL, 0 );
|
||||
FILE *fp = fopen( dest, "wb" );
|
||||
if ( fp )
|
||||
{
|
||||
fwrite( banner, 1, fst[index].filelen, fp );
|
||||
fclose( fp );
|
||||
}
|
||||
free( fstbuffer );
|
||||
free( banner );
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
s32 dump_banner(const u8 *discid,const char * dest);
|
||||
s32 dump_banner( const u8 *discid, const char * dest );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -6,65 +6,71 @@
|
||||
***************************************************************************/
|
||||
#include "gui_banner.h"
|
||||
|
||||
GuiBanner::GuiBanner(const char *tplfilepath)
|
||||
GuiBanner::GuiBanner( const char *tplfilepath )
|
||||
{
|
||||
memory = NULL;
|
||||
tplfilesize = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
FILE *tplfp = fopen(tplfilepath,"rb");
|
||||
FILE *tplfp = fopen( tplfilepath, "rb" );
|
||||
|
||||
if(tplfp !=NULL) {
|
||||
if ( tplfp != NULL )
|
||||
{
|
||||
|
||||
unsigned short heighttemp = 0;
|
||||
unsigned short widthtemp = 0;
|
||||
unsigned short heighttemp = 0;
|
||||
unsigned short widthtemp = 0;
|
||||
|
||||
fseek(tplfp , 0x14, SEEK_SET);
|
||||
fread((void*)&heighttemp,1,2,tplfp);
|
||||
fread((void*)&widthtemp,1,2,tplfp);
|
||||
fseek (tplfp , 0 , SEEK_END);
|
||||
tplfilesize = ftell (tplfp);
|
||||
rewind (tplfp);
|
||||
memory = memalign(32, tplfilesize);
|
||||
if(!memory) {
|
||||
fclose(tplfp);
|
||||
fseek( tplfp , 0x14, SEEK_SET );
|
||||
fread( ( void* )&heighttemp, 1, 2, tplfp );
|
||||
fread( ( void* )&widthtemp, 1, 2, tplfp );
|
||||
fseek ( tplfp , 0 , SEEK_END );
|
||||
tplfilesize = ftell ( tplfp );
|
||||
rewind ( tplfp );
|
||||
memory = memalign( 32, tplfilesize );
|
||||
if ( !memory )
|
||||
{
|
||||
fclose( tplfp );
|
||||
return;
|
||||
}
|
||||
fread(memory, 1, tplfilesize, tplfp);
|
||||
fclose(tplfp);
|
||||
fread( memory, 1, tplfilesize, tplfp );
|
||||
fclose( tplfp );
|
||||
|
||||
TPLFile tplfile;
|
||||
int ret;
|
||||
|
||||
ret = TPL_OpenTPLFromMemory(&tplfile, memory, tplfilesize);
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
ret = TPL_GetTexture(&tplfile,0,&texObj);
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
TPL_CloseTPLFile(&tplfile);
|
||||
TPL_CloseTPLFile( &tplfile );
|
||||
|
||||
width = widthtemp;
|
||||
height = heighttemp;
|
||||
widescreen = 0;
|
||||
filecheck = true;
|
||||
width = widthtemp;
|
||||
height = heighttemp;
|
||||
widescreen = 0;
|
||||
filecheck = true;
|
||||
|
||||
} else {
|
||||
filecheck = false;
|
||||
fclose(tplfp);
|
||||
}
|
||||
else
|
||||
{
|
||||
filecheck = false;
|
||||
fclose( tplfp );
|
||||
}
|
||||
}
|
||||
|
||||
GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
||||
GuiBanner::GuiBanner( void *mem, u32 len, int w, int h )
|
||||
{
|
||||
if(!mem || !len)
|
||||
if ( !mem || !len )
|
||||
return;
|
||||
memory = mem;
|
||||
tplfilesize = len;
|
||||
@ -75,40 +81,43 @@ GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
||||
|
||||
int ret;
|
||||
|
||||
ret = TPL_OpenTPLFromMemory(&tplfile, memory, tplfilesize);
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
ret = TPL_GetTexture(&tplfile,0,&texObj);
|
||||
if(ret < 0) {
|
||||
free(memory);
|
||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
||||
if ( ret < 0 )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
return;
|
||||
}
|
||||
TPL_CloseTPLFile(&tplfile);
|
||||
TPL_CloseTPLFile( &tplfile );
|
||||
|
||||
filecheck = true;
|
||||
}
|
||||
|
||||
GuiBanner::~GuiBanner()
|
||||
{
|
||||
if(memory != NULL) {
|
||||
free(memory);
|
||||
if ( memory != NULL )
|
||||
{
|
||||
free( memory );
|
||||
memory = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiBanner::Draw()
|
||||
{
|
||||
LOCK(this);
|
||||
if(!filecheck ||!this->IsVisible())
|
||||
return;
|
||||
LOCK( this );
|
||||
if ( !filecheck || !this->IsVisible() )
|
||||
return;
|
||||
|
||||
float currScale = this->GetScale();
|
||||
float currScale = this->GetScale();
|
||||
|
||||
Menu_DrawTPLImg(this->GetLeft(), this->GetTop(), 0, width, height, &texObj, imageangle, widescreen ? currScale*0.80 : currScale, currScale, this->GetAlpha(), xx1,yy1,xx2,yy2,xx3,yy3,xx4,yy4);
|
||||
Menu_DrawTPLImg( this->GetLeft(), this->GetTop(), 0, width, height, &texObj, imageangle, widescreen ? currScale*0.80 : currScale, currScale, this->GetAlpha(), xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4 );
|
||||
|
||||
this->UpdateEffects();
|
||||
this->UpdateEffects();
|
||||
}
|
||||
|
@ -12,24 +12,24 @@
|
||||
|
||||
class GuiBanner : public GuiImage
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param tplfilepath Path of the tpl file
|
||||
GuiBanner(const char *tplfilepath);
|
||||
//!Constructor
|
||||
//!\param mem Memory of the loaded tpl
|
||||
//!\param len Filesize of the tpl
|
||||
//!\param w Width of the tpl
|
||||
//!\param h Height of the tpl
|
||||
GuiBanner(void *mem, u32 len, int w, int h);
|
||||
//!Destructor
|
||||
~GuiBanner();
|
||||
void Draw();
|
||||
protected:
|
||||
void * memory;
|
||||
bool filecheck;
|
||||
u32 tplfilesize;
|
||||
GXTexObj texObj;
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param tplfilepath Path of the tpl file
|
||||
GuiBanner( const char *tplfilepath );
|
||||
//!Constructor
|
||||
//!\param mem Memory of the loaded tpl
|
||||
//!\param len Filesize of the tpl
|
||||
//!\param w Width of the tpl
|
||||
//!\param h Height of the tpl
|
||||
GuiBanner( void *mem, u32 len, int w, int h );
|
||||
//!Destructor
|
||||
~GuiBanner();
|
||||
void Draw();
|
||||
protected:
|
||||
void * memory;
|
||||
bool filecheck;
|
||||
u32 tplfilesize;
|
||||
GXTexObj texObj;
|
||||
};
|
||||
|
||||
#endif /* _GUIBANNER_H_ */
|
||||
|
@ -28,51 +28,52 @@
|
||||
#include "../ramdisk/ramdisk.h"
|
||||
#include "../listfiles.h"
|
||||
|
||||
u16 be16(const u8 *p)
|
||||
u16 be16( const u8 *p )
|
||||
{
|
||||
return (p[0] << 8) | p[1];
|
||||
return ( p[0] << 8 ) | p[1];
|
||||
}
|
||||
|
||||
u32 be32(const u8 *p)
|
||||
u32 be32( const u8 *p )
|
||||
{
|
||||
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
return ( p[0] << 24 ) | ( p[1] << 16 ) | ( p[2] << 8 ) | p[3];
|
||||
}
|
||||
|
||||
u64 be64(const u8 *p)
|
||||
u64 be64( const u8 *p )
|
||||
{
|
||||
return ((u64)be32(p) << 32) | be32(p + 4);
|
||||
return ( ( u64 )be32( p ) << 32 ) | be32( p + 4 );
|
||||
}
|
||||
|
||||
u64 be34(const u8 *p)
|
||||
u64 be34( const u8 *p )
|
||||
{
|
||||
return 4 * (u64)be32(p);
|
||||
return 4 * ( u64 )be32( p );
|
||||
}
|
||||
|
||||
void wbe16(u8 *p, u16 x)
|
||||
void wbe16( u8 *p, u16 x )
|
||||
{
|
||||
p[0] = x >> 8;
|
||||
p[1] = x;
|
||||
p[0] = x >> 8;
|
||||
p[1] = x;
|
||||
}
|
||||
|
||||
void wbe32(u8 *p, u32 x)
|
||||
void wbe32( u8 *p, u32 x )
|
||||
{
|
||||
wbe16(p, x >> 16);
|
||||
wbe16(p + 2, x);
|
||||
wbe16( p, x >> 16 );
|
||||
wbe16( p + 2, x );
|
||||
}
|
||||
|
||||
void wbe64(u8 *p, u64 x)
|
||||
void wbe64( u8 *p, u64 x )
|
||||
{
|
||||
wbe32(p, x >> 32);
|
||||
wbe32(p + 4, x);
|
||||
wbe32( p, x >> 32 );
|
||||
wbe32( p + 4, x );
|
||||
}
|
||||
|
||||
void md5(u8 *data, u32 len, u8 *hash)
|
||||
void md5( u8 *data, u32 len, u8 *hash )
|
||||
{
|
||||
MD5(hash, data, len);
|
||||
MD5( hash, data, len );
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u8 zeroes[0x40];
|
||||
u32 imet; // "IMET"
|
||||
u8 zero_six_zero_three[8]; // fixed, unknown purpose
|
||||
@ -89,441 +90,474 @@ typedef struct {
|
||||
u8 crypto[0x10];
|
||||
} imet_data_t;
|
||||
|
||||
typedef struct {
|
||||
u32 imd5_tag; // 0x494D4435 "IMD5";
|
||||
u32 size; // size of the rest of part B, starting from next field.
|
||||
u8 zeroes[8];
|
||||
u8 md5[16];
|
||||
u32 payload_tag; // 0x4C5A3737 "LZ77" if this is lz77
|
||||
u32 payload_data;
|
||||
typedef struct
|
||||
{
|
||||
u32 imd5_tag; // 0x494D4435 "IMD5";
|
||||
u32 size; // size of the rest of part B, starting from next field.
|
||||
u8 zeroes[8];
|
||||
u8 md5[16];
|
||||
u32 payload_tag; // 0x4C5A3737 "LZ77" if this is lz77
|
||||
u32 payload_data;
|
||||
} imd5_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 type;
|
||||
u16 name_offset;
|
||||
u32 data_offset; // == absolut offset från U.8- headerns början
|
||||
u32 size; // last included file num for directories
|
||||
u16 type;
|
||||
u16 name_offset;
|
||||
u32 data_offset; // == absolut offset från U.8- headerns början
|
||||
u32 size; // last included file num for directories
|
||||
} U8_node;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 tag; // 0x55AA382D "U.8-"
|
||||
u32 rootnode_offset; // offset to root_node, always 0x20.
|
||||
u32 header_size; // size of header from root_node to end of string table.
|
||||
u32 data_offset; // offset to data -- this is rootnode_offset + header_size, aligned to 0x40.
|
||||
u8 zeroes[16];
|
||||
u32 tag; // 0x55AA382D "U.8-"
|
||||
u32 rootnode_offset; // offset to root_node, always 0x20.
|
||||
u32 header_size; // size of header from root_node to end of string table.
|
||||
u32 data_offset; // offset to data -- this is rootnode_offset + header_size, aligned to 0x40.
|
||||
u8 zeroes[16];
|
||||
} U8_archive_header;
|
||||
|
||||
static int write_file(void* data, size_t size, char* name)
|
||||
static int write_file( void* data, size_t size, char* name )
|
||||
{
|
||||
size_t written=0;
|
||||
FILE *out;
|
||||
out = fopen(name, "wb");
|
||||
if(out)
|
||||
{
|
||||
written = fwrite(data, 1, size, out);
|
||||
fclose(out);
|
||||
}
|
||||
return (written == size) ? 1 : -1;
|
||||
size_t written = 0;
|
||||
FILE *out;
|
||||
out = fopen( name, "wb" );
|
||||
if ( out )
|
||||
{
|
||||
written = fwrite( data, 1, size, out );
|
||||
fclose( out );
|
||||
}
|
||||
return ( written == size ) ? 1 : -1;
|
||||
}
|
||||
|
||||
u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
||||
u8* decompress_lz77( u8 *data, size_t data_size, size_t* decompressed_size )
|
||||
{
|
||||
u8 *data_end;
|
||||
u8 *decompressed_data;
|
||||
size_t unpacked_size;
|
||||
u8 *in_ptr;
|
||||
u8 *out_ptr;
|
||||
u8 *out_end;
|
||||
u8 *data_end;
|
||||
u8 *decompressed_data;
|
||||
size_t unpacked_size;
|
||||
u8 *in_ptr;
|
||||
u8 *out_ptr;
|
||||
u8 *out_end;
|
||||
|
||||
in_ptr = data;
|
||||
data_end = data + data_size;
|
||||
in_ptr = data;
|
||||
data_end = data + data_size;
|
||||
|
||||
// Assume this for now and grow when needed
|
||||
unpacked_size = data_size;
|
||||
// Assume this for now and grow when needed
|
||||
unpacked_size = data_size;
|
||||
|
||||
decompressed_data = malloc(unpacked_size);
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
decompressed_data = malloc( unpacked_size );
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
|
||||
out_ptr = decompressed_data;
|
||||
out_ptr = decompressed_data;
|
||||
|
||||
while (in_ptr < data_end) {
|
||||
int bit;
|
||||
u8 bitmask = *in_ptr;
|
||||
while ( in_ptr < data_end )
|
||||
{
|
||||
int bit;
|
||||
u8 bitmask = *in_ptr;
|
||||
|
||||
in_ptr++;
|
||||
for (bit = 0x80; bit != 0; bit >>= 1) {
|
||||
if (bitmask & bit) {
|
||||
// Next section is compressed
|
||||
u8 rep_length;
|
||||
u16 rep_offset;
|
||||
in_ptr++;
|
||||
for ( bit = 0x80; bit != 0; bit >>= 1 )
|
||||
{
|
||||
if ( bitmask & bit )
|
||||
{
|
||||
// Next section is compressed
|
||||
u8 rep_length;
|
||||
u16 rep_offset;
|
||||
|
||||
rep_length = (*in_ptr >> 4) + 3;
|
||||
rep_offset = *in_ptr & 0x0f;
|
||||
in_ptr++;
|
||||
rep_offset = *in_ptr | (rep_offset << 8);
|
||||
in_ptr++;
|
||||
if (out_ptr-decompressed_data < rep_offset) {
|
||||
return NULL;
|
||||
}
|
||||
rep_length = ( *in_ptr >> 4 ) + 3;
|
||||
rep_offset = *in_ptr & 0x0f;
|
||||
in_ptr++;
|
||||
rep_offset = *in_ptr | ( rep_offset << 8 );
|
||||
in_ptr++;
|
||||
if ( out_ptr - decompressed_data < rep_offset )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ; rep_length > 0; rep_length--) {
|
||||
*out_ptr = out_ptr[-rep_offset-1];
|
||||
out_ptr++;
|
||||
if (out_ptr >= out_end) {
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc(decompressed_data, unpacked_size*2);
|
||||
out_ptr = decompressed_data + unpacked_size;
|
||||
unpacked_size *= 2;
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
}
|
||||
for ( ; rep_length > 0; rep_length-- )
|
||||
{
|
||||
*out_ptr = out_ptr[-rep_offset-1];
|
||||
out_ptr++;
|
||||
if ( out_ptr >= out_end )
|
||||
{
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||
out_ptr = decompressed_data + unpacked_size;
|
||||
unpacked_size *= 2;
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just copy byte
|
||||
*out_ptr = *in_ptr;
|
||||
out_ptr++;
|
||||
if ( out_ptr >= out_end )
|
||||
{
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||
out_ptr = decompressed_data + unpacked_size;
|
||||
unpacked_size *= 2;
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
}
|
||||
in_ptr++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Just copy byte
|
||||
*out_ptr = *in_ptr;
|
||||
out_ptr++;
|
||||
if (out_ptr >= out_end) {
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc(decompressed_data, unpacked_size*2);
|
||||
out_ptr = decompressed_data + unpacked_size;
|
||||
unpacked_size *= 2;
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
}
|
||||
in_ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*decompressed_size = (out_ptr - decompressed_data);
|
||||
return decompressed_data;
|
||||
*decompressed_size = ( out_ptr - decompressed_data );
|
||||
return decompressed_data;
|
||||
}
|
||||
|
||||
static int write_imd5_lz77(u8* data, size_t size, char* outname)
|
||||
static int write_imd5_lz77( u8* data, size_t size, char* outname )
|
||||
{
|
||||
imd5_header_t* header = (imd5_header_t*) data;
|
||||
u32 tag;
|
||||
u32 size_in_imd5;
|
||||
imd5_header_t* header = ( imd5_header_t* ) data;
|
||||
u32 tag;
|
||||
u32 size_in_imd5;
|
||||
u8 md5_calc[16];
|
||||
u8 *decompressed_data;
|
||||
size_t decompressed_size;
|
||||
u8 *decompressed_data;
|
||||
size_t decompressed_size;
|
||||
|
||||
tag = be32((u8*) &header->imd5_tag);
|
||||
if (tag != 0x494D4435) {
|
||||
return -4;
|
||||
}
|
||||
tag = be32( ( u8* ) & header->imd5_tag );
|
||||
if ( tag != 0x494D4435 )
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
md5(data+32, size-32, md5_calc);
|
||||
if (memcmp(&header->md5, md5_calc, 0x10)) {
|
||||
return -5;
|
||||
}
|
||||
md5( data + 32, size - 32, md5_calc );
|
||||
if ( memcmp( &header->md5, md5_calc, 0x10 ) )
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
size_in_imd5 = be32((u8*) &header->size);
|
||||
if (size_in_imd5 != size - 32) {
|
||||
return -6;
|
||||
}
|
||||
size_in_imd5 = be32( ( u8* ) & header->size );
|
||||
if ( size_in_imd5 != size - 32 )
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
tag = be32((u8*) &header->payload_tag);
|
||||
if (tag == 0x4C5A3737) {
|
||||
// "LZ77" - uncompress
|
||||
decompressed_data = decompress_lz77(data + sizeof(imd5_header_t), size - sizeof(imd5_header_t), &decompressed_size);
|
||||
if(decompressed_data == NULL)
|
||||
return -7;
|
||||
write_file(decompressed_data, decompressed_size, outname);
|
||||
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
|
||||
tag = be32( ( u8* ) & header->payload_tag );
|
||||
if ( tag == 0x4C5A3737 )
|
||||
{
|
||||
// "LZ77" - uncompress
|
||||
decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size );
|
||||
if ( decompressed_data == NULL )
|
||||
return -7;
|
||||
write_file( decompressed_data, decompressed_size, outname );
|
||||
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
|
||||
|
||||
free(decompressed_data);
|
||||
} else {
|
||||
write_file(&header->payload_tag, size-32, outname);
|
||||
//printf(", md5 ok");
|
||||
}
|
||||
return 0;
|
||||
free( decompressed_data );
|
||||
}
|
||||
else
|
||||
{
|
||||
write_file( &header->payload_tag, size - 32, outname );
|
||||
//printf(", md5 ok");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_U8_archive(FILE *fp)
|
||||
static int do_U8_archive( FILE *fp )
|
||||
{
|
||||
U8_archive_header header;
|
||||
U8_node root_node;
|
||||
u32 tag;
|
||||
u32 num_nodes;
|
||||
U8_node* nodes;
|
||||
u8* string_table;
|
||||
size_t rest_size;
|
||||
unsigned int i;
|
||||
u32 data_offset;
|
||||
u32 current_offset;
|
||||
u16 dir_stack[16];
|
||||
int dir_index = 0;
|
||||
U8_archive_header header;
|
||||
U8_node root_node;
|
||||
u32 tag;
|
||||
u32 num_nodes;
|
||||
U8_node* nodes;
|
||||
u8* string_table;
|
||||
size_t rest_size;
|
||||
unsigned int i;
|
||||
u32 data_offset;
|
||||
u32 current_offset;
|
||||
u16 dir_stack[16];
|
||||
int dir_index = 0;
|
||||
|
||||
fread(&header, 1, sizeof header, fp);
|
||||
tag = be32((u8*) &header.tag);
|
||||
if (tag != 0x55AA382D) {
|
||||
return -1;
|
||||
}
|
||||
fread( &header, 1, sizeof header, fp );
|
||||
tag = be32( ( u8* ) & header.tag );
|
||||
if ( tag != 0x55AA382D )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
fread(&root_node, 1, sizeof(root_node), fp);
|
||||
num_nodes = be32((u8*) &root_node.size) - 1;
|
||||
//printf("Number of files: %d\n", num_nodes);
|
||||
fread( &root_node, 1, sizeof( root_node ), fp );
|
||||
num_nodes = be32( ( u8* ) & root_node.size ) - 1;
|
||||
//printf("Number of files: %d\n", num_nodes);
|
||||
|
||||
nodes = malloc(sizeof(U8_node) * (num_nodes));
|
||||
fread(nodes, 1, num_nodes * sizeof(U8_node), fp);
|
||||
nodes = malloc( sizeof( U8_node ) * ( num_nodes ) );
|
||||
fread( nodes, 1, num_nodes * sizeof( U8_node ), fp );
|
||||
|
||||
data_offset = be32((u8*) &header.data_offset);
|
||||
rest_size = data_offset - sizeof(header) - (num_nodes+1)*sizeof(U8_node);
|
||||
data_offset = be32( ( u8* ) & header.data_offset );
|
||||
rest_size = data_offset - sizeof( header ) - ( num_nodes + 1 ) * sizeof( U8_node );
|
||||
|
||||
string_table = malloc(rest_size);
|
||||
fread(string_table, 1, rest_size, fp);
|
||||
string_table = malloc( rest_size );
|
||||
fread( string_table, 1, rest_size, fp );
|
||||
current_offset = data_offset;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
U8_node* node = &nodes[i];
|
||||
u16 type = be16((u8*)&node->type);
|
||||
u16 name_offset = be16((u8*)&node->name_offset);
|
||||
u32 my_data_offset = be32((u8*)&node->data_offset);
|
||||
u32 size = be32((u8*)&node->size);
|
||||
char* name = (char*) &string_table[name_offset];
|
||||
u8* file_data;
|
||||
for ( i = 0; i < num_nodes; i++ )
|
||||
{
|
||||
U8_node* node = &nodes[i];
|
||||
u16 type = be16( ( u8* ) & node->type );
|
||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
||||
u32 my_data_offset = be32( ( u8* ) & node->data_offset );
|
||||
u32 size = be32( ( u8* ) & node->size );
|
||||
char* name = ( char* ) & string_table[name_offset];
|
||||
u8* file_data;
|
||||
|
||||
if (type == 0x0100) {
|
||||
// Directory
|
||||
mkdir(name, 0777);
|
||||
chdir(name);
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
} else {
|
||||
// Normal file
|
||||
u8 padding[32];
|
||||
|
||||
if (type != 0x0000) {
|
||||
free(string_table);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (current_offset < my_data_offset) {
|
||||
int diff = my_data_offset - current_offset;
|
||||
|
||||
if (diff > 32) {
|
||||
free(string_table);
|
||||
return -3;
|
||||
if ( type == 0x0100 )
|
||||
{
|
||||
// Directory
|
||||
mkdir( name, 0777 );
|
||||
chdir( name );
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
}
|
||||
fread(padding, 1, diff, fp);
|
||||
current_offset += diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal file
|
||||
u8 padding[32];
|
||||
|
||||
file_data = malloc(size);
|
||||
fread(file_data, 1, size, fp);
|
||||
//printf("%*s %s (%d bytes", dir_index, "", name, size);
|
||||
int result;
|
||||
result = write_imd5_lz77(file_data, size, name);
|
||||
if(result < 0)
|
||||
{free(string_table);
|
||||
return result;
|
||||
}
|
||||
//printf(")\n");
|
||||
current_offset += size;
|
||||
if ( type != 0x0000 )
|
||||
{
|
||||
free( string_table );
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ( current_offset < my_data_offset )
|
||||
{
|
||||
int diff = my_data_offset - current_offset;
|
||||
|
||||
if ( diff > 32 )
|
||||
{
|
||||
free( string_table );
|
||||
return -3;
|
||||
}
|
||||
fread( padding, 1, diff, fp );
|
||||
current_offset += diff;
|
||||
}
|
||||
|
||||
file_data = malloc( size );
|
||||
fread( file_data, 1, size, fp );
|
||||
//printf("%*s %s (%d bytes", dir_index, "", name, size);
|
||||
int result;
|
||||
result = write_imd5_lz77( file_data, size, name );
|
||||
if ( result < 0 )
|
||||
{
|
||||
free( string_table );
|
||||
return result;
|
||||
}
|
||||
//printf(")\n");
|
||||
current_offset += size;
|
||||
}
|
||||
|
||||
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
||||
{
|
||||
chdir( ".." );
|
||||
dir_index--;
|
||||
}
|
||||
}
|
||||
free( string_table );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_imet_header( FILE *fp )
|
||||
{
|
||||
imet_data_t header;
|
||||
|
||||
fread( &header, 1, sizeof header, fp );
|
||||
|
||||
write_file( &header, sizeof( header ), "header.imet" );
|
||||
}
|
||||
|
||||
void do_U8_archivebanner( FILE *fp )
|
||||
{
|
||||
U8_archive_header header;
|
||||
U8_node root_node;
|
||||
u32 tag;
|
||||
u32 num_nodes;
|
||||
U8_node* nodes;
|
||||
u8* string_table;
|
||||
size_t rest_size;
|
||||
unsigned int i;
|
||||
u32 data_offset;
|
||||
u16 dir_stack[16];
|
||||
int dir_index = 0;
|
||||
|
||||
fread( &header, 1, sizeof header, fp );
|
||||
tag = be32( ( u8* ) & header.tag );
|
||||
if ( tag != 0x55AA382D )
|
||||
{
|
||||
//printf("No U8 tag");
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
while (dir_stack[dir_index] == i+2 && dir_index > 0) {
|
||||
chdir("..");
|
||||
dir_index--;
|
||||
fread( &root_node, 1, sizeof( root_node ), fp );
|
||||
num_nodes = be32( ( u8* ) & root_node.size ) - 1;
|
||||
printf( "Number of files: %d\n", num_nodes );
|
||||
|
||||
nodes = malloc( sizeof( U8_node ) * ( num_nodes ) );
|
||||
fread( nodes, 1, num_nodes * sizeof( U8_node ), fp );
|
||||
|
||||
data_offset = be32( ( u8* ) & header.data_offset );
|
||||
rest_size = data_offset - sizeof( header ) - ( num_nodes + 1 ) * sizeof( U8_node );
|
||||
|
||||
string_table = malloc( rest_size );
|
||||
fread( string_table, 1, rest_size, fp );
|
||||
|
||||
for ( i = 0; i < num_nodes; i++ )
|
||||
{
|
||||
U8_node* node = &nodes[i];
|
||||
u16 type = be16( ( u8* ) & node->type );
|
||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
||||
u32 my_data_offset = be32( ( u8* ) & node->data_offset );
|
||||
u32 size = be32( ( u8* ) & node->size );
|
||||
char* name = ( char* ) & string_table[name_offset];
|
||||
u8* file_data;
|
||||
|
||||
if ( type == 0x0100 )
|
||||
{
|
||||
// Directory
|
||||
mkdir( name, 0777 );
|
||||
chdir( name );
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal file
|
||||
|
||||
if ( type != 0x0000 )
|
||||
{
|
||||
printf( "Unknown type" );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
fseek( fp, my_data_offset, SEEK_SET );
|
||||
file_data = malloc( size );
|
||||
fread( file_data, 1, size, fp );
|
||||
write_file( file_data, size, name );
|
||||
free( file_data );
|
||||
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
|
||||
}
|
||||
|
||||
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
||||
{
|
||||
chdir( ".." );
|
||||
dir_index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(string_table);
|
||||
return 0;
|
||||
free( string_table );
|
||||
}
|
||||
|
||||
static void do_imet_header(FILE *fp)
|
||||
{
|
||||
imet_data_t header;
|
||||
|
||||
fread(&header, 1, sizeof header, fp);
|
||||
|
||||
write_file(&header, sizeof(header), "header.imet");
|
||||
}
|
||||
|
||||
void do_U8_archivebanner(FILE *fp)
|
||||
{
|
||||
U8_archive_header header;
|
||||
U8_node root_node;
|
||||
u32 tag;
|
||||
u32 num_nodes;
|
||||
U8_node* nodes;
|
||||
u8* string_table;
|
||||
size_t rest_size;
|
||||
unsigned int i;
|
||||
u32 data_offset;
|
||||
u16 dir_stack[16];
|
||||
int dir_index = 0;
|
||||
|
||||
fread(&header, 1, sizeof header, fp);
|
||||
tag = be32((u8*) &header.tag);
|
||||
if (tag != 0x55AA382D) {
|
||||
//printf("No U8 tag");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fread(&root_node, 1, sizeof(root_node), fp);
|
||||
num_nodes = be32((u8*) &root_node.size) - 1;
|
||||
printf("Number of files: %d\n", num_nodes);
|
||||
|
||||
nodes = malloc(sizeof(U8_node) * (num_nodes));
|
||||
fread(nodes, 1, num_nodes * sizeof(U8_node), fp);
|
||||
|
||||
data_offset = be32((u8*) &header.data_offset);
|
||||
rest_size = data_offset - sizeof(header) - (num_nodes+1)*sizeof(U8_node);
|
||||
|
||||
string_table = malloc(rest_size);
|
||||
fread(string_table, 1, rest_size, fp);
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
U8_node* node = &nodes[i];
|
||||
u16 type = be16((u8*)&node->type);
|
||||
u16 name_offset = be16((u8*)&node->name_offset);
|
||||
u32 my_data_offset = be32((u8*)&node->data_offset);
|
||||
u32 size = be32((u8*)&node->size);
|
||||
char* name = (char*) &string_table[name_offset];
|
||||
u8* file_data;
|
||||
|
||||
if (type == 0x0100) {
|
||||
// Directory
|
||||
mkdir(name, 0777);
|
||||
chdir(name);
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
} else {
|
||||
// Normal file
|
||||
|
||||
if (type != 0x0000) {
|
||||
printf("Unknown type");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fseek(fp, my_data_offset, SEEK_SET);
|
||||
file_data = malloc(size);
|
||||
fread(file_data, 1, size, fp);
|
||||
write_file(file_data, size, name);
|
||||
free(file_data);
|
||||
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
|
||||
}
|
||||
|
||||
while (dir_stack[dir_index] == i+2 && dir_index > 0) {
|
||||
chdir("..");
|
||||
dir_index--;
|
||||
}
|
||||
}
|
||||
free(string_table);
|
||||
}
|
||||
|
||||
int extractbnrfile(const char * filepath, const char * destpath)
|
||||
int extractbnrfile( const char * filepath, const char * destpath )
|
||||
{
|
||||
int ret = -1;
|
||||
FILE *fp = fopen(filepath, "rb");
|
||||
if(fp)
|
||||
{
|
||||
subfoldercreate(destpath);
|
||||
chdir(destpath);
|
||||
FILE *fp = fopen( filepath, "rb" );
|
||||
if ( fp )
|
||||
{
|
||||
subfoldercreate( destpath );
|
||||
chdir( destpath );
|
||||
|
||||
do_imet_header(fp);
|
||||
ret = do_U8_archive(fp);
|
||||
do_imet_header( fp );
|
||||
ret = do_U8_archive( fp );
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
return ret;
|
||||
fclose( fp );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unpackBin(const char * filename,const char * outdir)
|
||||
int unpackBin( const char * filename, const char * outdir )
|
||||
{
|
||||
FILE *fp = fopen(filename,"rb");;
|
||||
if(fp)
|
||||
{
|
||||
subfoldercreate(outdir);
|
||||
chdir(outdir);
|
||||
FILE *fp = fopen( filename, "rb" );;
|
||||
if ( fp )
|
||||
{
|
||||
subfoldercreate( outdir );
|
||||
chdir( outdir );
|
||||
|
||||
do_U8_archivebanner(fp);
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
do_U8_archivebanner( fp );
|
||||
fclose( fp );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TMP_PATH(s) "BANNER:/dump"s
|
||||
//#define TMP_PATH(s) "SD:/dump"s
|
||||
|
||||
int unpackBanner(const u8 *gameid, int what, const char *outdir)
|
||||
int unpackBanner( const u8 *gameid, int what, const char *outdir )
|
||||
{
|
||||
|
||||
char path[256];
|
||||
if(!ramdiskMount("BANNER", NULL)) return -1;
|
||||
char path[256];
|
||||
if ( !ramdiskMount( "BANNER", NULL ) ) return -1;
|
||||
|
||||
subfoldercreate(TMP_PATH("/"));
|
||||
s32 ret = dump_banner(gameid, TMP_PATH("/opening.bnr"));
|
||||
if (ret != 1)
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
subfoldercreate( TMP_PATH( "/" ) );
|
||||
s32 ret = dump_banner( gameid, TMP_PATH( "/opening.bnr" ) );
|
||||
if ( ret != 1 )
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
ret = extractbnrfile(TMP_PATH("/opening.bnr"), TMP_PATH("/"));
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
ret = extractbnrfile( TMP_PATH( "/opening.bnr" ), TMP_PATH( "/" ) );
|
||||
if ( ret != 0 )
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if(what & UNPACK_BANNER_BIN)
|
||||
{
|
||||
snprintf(path, sizeof(path),"%sbanner/", outdir);
|
||||
ret = unpackBin(TMP_PATH("/meta/banner.bin"), path);
|
||||
if (ret != 1)
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
if(what & UNPACK_ICON_BIN)
|
||||
{
|
||||
snprintf(path, sizeof(path),"%sicon/", outdir);
|
||||
ret = unpackBin(TMP_PATH("/meta/icon.bin"), path);
|
||||
if (ret != 1)
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
if(what & UNPACK_SOUND_BIN)
|
||||
{
|
||||
snprintf(path, sizeof(path),"%ssound.bin", outdir);
|
||||
FILE *fp = fopen(TMP_PATH("/meta/sound.bin"), "rb");
|
||||
if(fp)
|
||||
{
|
||||
size_t size;
|
||||
u8 *data;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
if(!size)
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
data = (u8 *)malloc(size);
|
||||
if(!data)
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
if(fread(data, 1, size, fp) != size)
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
ret = write_file(data, size, path);
|
||||
}
|
||||
error: fclose(fp);
|
||||
}
|
||||
ramdiskUnmount("BANNER");
|
||||
if ( what & UNPACK_BANNER_BIN )
|
||||
{
|
||||
snprintf( path, sizeof( path ), "%sbanner/", outdir );
|
||||
ret = unpackBin( TMP_PATH( "/meta/banner.bin" ), path );
|
||||
if ( ret != 1 )
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
if ( what & UNPACK_ICON_BIN )
|
||||
{
|
||||
snprintf( path, sizeof( path ), "%sicon/", outdir );
|
||||
ret = unpackBin( TMP_PATH( "/meta/icon.bin" ), path );
|
||||
if ( ret != 1 )
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
if ( what & UNPACK_SOUND_BIN )
|
||||
{
|
||||
snprintf( path, sizeof( path ), "%ssound.bin", outdir );
|
||||
FILE *fp = fopen( TMP_PATH( "/meta/sound.bin" ), "rb" );
|
||||
if ( fp )
|
||||
{
|
||||
size_t size;
|
||||
u8 *data;
|
||||
fseek( fp, 0, SEEK_END );
|
||||
size = ftell( fp );
|
||||
if ( !size )
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
fseek( fp, 0, SEEK_SET );
|
||||
data = ( u8 * )malloc( size );
|
||||
if ( !data )
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
if ( fread( data, 1, size, fp ) != size )
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
ret = write_file( data, size, path );
|
||||
}
|
||||
error: fclose( fp );
|
||||
}
|
||||
ramdiskUnmount( "BANNER" );
|
||||
error2:
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return 1;
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
@ -13,32 +13,32 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/***********************************************************
|
||||
* Error description:
|
||||
* 0 Successfully extracted
|
||||
* -1 No U8 tag
|
||||
* -2 Unknown type
|
||||
* -3 Archive inconsistency, too much padding
|
||||
* -4 No IMD5 tag
|
||||
* -5 MD5 mismatch
|
||||
* -6 Size mismatch
|
||||
* -7 Inconsistency in LZ77 encoding
|
||||
************************************************************/
|
||||
/***********************************************************
|
||||
* Error description:
|
||||
* 0 Successfully extracted
|
||||
* -1 No U8 tag
|
||||
* -2 Unknown type
|
||||
* -3 Archive inconsistency, too much padding
|
||||
* -4 No IMD5 tag
|
||||
* -5 MD5 mismatch
|
||||
* -6 Size mismatch
|
||||
* -7 Inconsistency in LZ77 encoding
|
||||
************************************************************/
|
||||
|
||||
//! Extract opening.bnr from filepath to destpath
|
||||
//! Files extracted: banner.bin icon.bin and sound.bin
|
||||
int extractbnrfile(const char * filepath, const char * destpath);
|
||||
int unpackBin(const char * filename,const char * outdir);
|
||||
#define UNPACK_BANNER_BIN 1 /* extract banner.bin to outdir/banner/ */
|
||||
#define UNPACK_ICON_BIN 2 /* extract icon.bin to outdir/icon/ */
|
||||
#define UNPACK_SOUND_BIN 4 /* copies sound.bin to outdir/sound.bin */
|
||||
int extractbnrfile( const char * filepath, const char * destpath );
|
||||
int unpackBin( const char * filename, const char * outdir );
|
||||
#define UNPACK_BANNER_BIN 1 /* extract banner.bin to outdir/banner/ */
|
||||
#define UNPACK_ICON_BIN 2 /* extract icon.bin to outdir/icon/ */
|
||||
#define UNPACK_SOUND_BIN 4 /* copies sound.bin to outdir/sound.bin */
|
||||
#define UNPACK_ALL (UNPACK_SOUND_BIN | UNPACK_ICON_BIN | UNPACK_BANNER_BIN)
|
||||
int unpackBanner(const u8 * gameid, int what, const char *outdir);
|
||||
int unpackBanner( const u8 * gameid, int what, const char *outdir );
|
||||
//! Extract the lz77 compressed banner, icon and sound .bin
|
||||
u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size);
|
||||
u8* decompress_lz77( u8 *data, size_t data_size, size_t* decompressed_size );
|
||||
|
||||
u16 be16(const u8 *p);
|
||||
u32 be32(const u8 *p);
|
||||
u16 be16( const u8 *p );
|
||||
u32 be32( const u8 *p );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -13,197 +13,197 @@
|
||||
|
||||
struct IMD5Header
|
||||
{
|
||||
u32 fcc;
|
||||
u32 filesize;
|
||||
u8 zeroes[8];
|
||||
u8 crypto[16];
|
||||
} __attribute__((packed));
|
||||
u32 fcc;
|
||||
u32 filesize;
|
||||
u8 zeroes[8];
|
||||
u8 crypto[16];
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct IMETHeader
|
||||
{
|
||||
u8 zeroes[64];
|
||||
u32 fcc;
|
||||
u8 unk[8];
|
||||
u32 iconSize;
|
||||
u32 bannerSize;
|
||||
u32 soundSize;
|
||||
u32 flag1;
|
||||
u8 names[7][84];
|
||||
u8 zeroes_2[0x348];
|
||||
u8 crypto[16];
|
||||
} __attribute__((packed));
|
||||
u8 zeroes[64];
|
||||
u32 fcc;
|
||||
u8 unk[8];
|
||||
u32 iconSize;
|
||||
u32 bannerSize;
|
||||
u32 soundSize;
|
||||
u32 flag1;
|
||||
u8 names[7][84];
|
||||
u8 zeroes_2[0x348];
|
||||
u8 crypto[16];
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct U8Header
|
||||
{
|
||||
u32 fcc;
|
||||
u32 rootNodeOffset;
|
||||
u32 headerSize;
|
||||
u32 dataOffset;
|
||||
u8 zeroes[16];
|
||||
} __attribute__((packed));
|
||||
u32 fcc;
|
||||
u32 rootNodeOffset;
|
||||
u32 headerSize;
|
||||
u32 dataOffset;
|
||||
u8 zeroes[16];
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct U8Entry
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 fileType : 8;
|
||||
u32 nameOffset : 24;
|
||||
};
|
||||
u32 fileOffset;
|
||||
union
|
||||
{
|
||||
u32 fileLength;
|
||||
u32 numEntries;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
struct
|
||||
{
|
||||
u32 fileType : 8;
|
||||
u32 nameOffset : 24;
|
||||
};
|
||||
u32 fileOffset;
|
||||
union
|
||||
{
|
||||
u32 fileLength;
|
||||
u32 numEntries;
|
||||
};
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct LZ77Info
|
||||
{
|
||||
u16 length : 4;
|
||||
u16 offset : 12;
|
||||
} __attribute__((packed));
|
||||
u16 length : 4;
|
||||
u16 offset : 12;
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
static char *u8Filename(const U8Entry *fst, int i)
|
||||
static char *u8Filename( const U8Entry *fst, int i )
|
||||
{
|
||||
return (char *)(fst + fst[0].numEntries) + fst[i].nameOffset;
|
||||
return ( char * )( fst + fst[0].numEntries ) + fst[i].nameOffset;
|
||||
}
|
||||
|
||||
inline u32 le32(u32 i)
|
||||
inline u32 le32( u32 i )
|
||||
{
|
||||
return ((i & 0xFF) << 24) | ((i & 0xFF00) << 8) | ((i & 0xFF0000) >> 8) | ((i & 0xFF000000) >> 24);
|
||||
return ( ( i & 0xFF ) << 24 ) | ( ( i & 0xFF00 ) << 8 ) | ( ( i & 0xFF0000 ) >> 8 ) | ( ( i & 0xFF000000 ) >> 24 );
|
||||
}
|
||||
|
||||
inline u16 le16(u16 i)
|
||||
inline u16 le16( u16 i )
|
||||
{
|
||||
return ((i & 0xFF) << 8) | ((i & 0xFF00) >> 8);
|
||||
return ( ( i & 0xFF ) << 8 ) | ( ( i & 0xFF00 ) >> 8 );
|
||||
}
|
||||
|
||||
static u8 *uncompressLZ77(const u8 *inBuf, u32 inLength, u32 &size)
|
||||
static u8 *uncompressLZ77( const u8 *inBuf, u32 inLength, u32 &size )
|
||||
{
|
||||
u8 *buffer = NULL;
|
||||
if (inLength <= 0x8 || *((const u32 *)inBuf) != 0x4C5A3737 /*"LZ77"*/ || inBuf[4] != 0x10)
|
||||
return NULL;
|
||||
u32 uncSize = le32(((const u32 *)inBuf)[1] << 8);
|
||||
u8 *buffer = NULL;
|
||||
if ( inLength <= 0x8 || *( ( const u32 * )inBuf ) != 0x4C5A3737 /*"LZ77"*/ || inBuf[4] != 0x10 )
|
||||
return NULL;
|
||||
u32 uncSize = le32( ( ( const u32 * )inBuf )[1] << 8 );
|
||||
|
||||
const u8 *inBufEnd = inBuf + inLength;
|
||||
inBuf += 8;
|
||||
buffer = new(std::nothrow) u8[uncSize];
|
||||
if (!buffer)
|
||||
return buffer;
|
||||
const u8 *inBufEnd = inBuf + inLength;
|
||||
inBuf += 8;
|
||||
buffer = new( std::nothrow ) u8[uncSize];
|
||||
if ( !buffer )
|
||||
return buffer;
|
||||
|
||||
u8 *bufCur = buffer;
|
||||
u8 *bufEnd = buffer + uncSize;
|
||||
u8 *bufCur = buffer;
|
||||
u8 *bufEnd = buffer + uncSize;
|
||||
|
||||
while (bufCur < bufEnd && inBuf < inBufEnd)
|
||||
{
|
||||
u8 flags = *inBuf;
|
||||
++inBuf;
|
||||
for (int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i)
|
||||
{
|
||||
if ((flags & 0x80) != 0)
|
||||
{
|
||||
const LZ77Info &info = *(const LZ77Info *)inBuf;
|
||||
inBuf += sizeof (LZ77Info);
|
||||
int length = info.length + 3;
|
||||
if (bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd)
|
||||
return buffer;
|
||||
memcpy(bufCur, bufCur - info.offset - 1, length);
|
||||
bufCur += length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bufCur = *inBuf;
|
||||
++inBuf;
|
||||
++bufCur;
|
||||
}
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
size = uncSize;
|
||||
return buffer;
|
||||
while ( bufCur < bufEnd && inBuf < inBufEnd )
|
||||
{
|
||||
u8 flags = *inBuf;
|
||||
++inBuf;
|
||||
for ( int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i )
|
||||
{
|
||||
if ( ( flags & 0x80 ) != 0 )
|
||||
{
|
||||
const LZ77Info &info = *( const LZ77Info * )inBuf;
|
||||
inBuf += sizeof ( LZ77Info );
|
||||
int length = info.length + 3;
|
||||
if ( bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd )
|
||||
return buffer;
|
||||
memcpy( bufCur, bufCur - info.offset - 1, length );
|
||||
bufCur += length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bufCur = *inBuf;
|
||||
++inBuf;
|
||||
++bufCur;
|
||||
}
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
size = uncSize;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const u8 *LoadBannerSound(const u8 *discid, u32 *size)
|
||||
const u8 *LoadBannerSound( const u8 *discid, u32 *size )
|
||||
{
|
||||
if(!discid)
|
||||
if ( !discid )
|
||||
return NULL;
|
||||
|
||||
Disc_SetUSB(NULL);
|
||||
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) discid);
|
||||
if(!disc)
|
||||
{
|
||||
// WindowPrompt(tr("Can't find disc"), 0, tr("OK"));
|
||||
Disc_SetUSB( NULL );
|
||||
wbfs_disc_t *disc = WBFS_OpenDisc( ( u8 * ) discid );
|
||||
if ( !disc )
|
||||
{
|
||||
// WindowPrompt(tr("Can't find disc"), 0, tr("OK"));
|
||||
return NULL;
|
||||
}
|
||||
wiidisc_t *wdisc = wd_open_disc((int (*)(void *, u32, u32, void *))wbfs_disc_read, disc);
|
||||
if(!wdisc)
|
||||
{
|
||||
//WindowPrompt(tr("Could not open Disc"), 0, tr("OK"));
|
||||
}
|
||||
wiidisc_t *wdisc = wd_open_disc( ( int ( * )( void *, u32, u32, void * ) )wbfs_disc_read, disc );
|
||||
if ( !wdisc )
|
||||
{
|
||||
//WindowPrompt(tr("Could not open Disc"), 0, tr("OK"));
|
||||
return NULL;
|
||||
}
|
||||
u8 * opening_bnr = wd_extract_file(wdisc, ALL_PARTITIONS, (char *) "opening.bnr");
|
||||
if(!opening_bnr)
|
||||
{
|
||||
//WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK"));
|
||||
}
|
||||
u8 * opening_bnr = wd_extract_file( wdisc, ALL_PARTITIONS, ( char * ) "opening.bnr" );
|
||||
if ( !opening_bnr )
|
||||
{
|
||||
//WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wd_close_disc(wdisc);
|
||||
WBFS_CloseDisc(disc);
|
||||
wd_close_disc( wdisc );
|
||||
WBFS_CloseDisc( disc );
|
||||
|
||||
const U8Entry *fst;
|
||||
const U8Entry *fst;
|
||||
|
||||
const IMETHeader *imetHdr = (IMETHeader *)opening_bnr;
|
||||
if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ )
|
||||
{
|
||||
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
const IMETHeader *imetHdr = ( IMETHeader * )opening_bnr;
|
||||
if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ )
|
||||
{
|
||||
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
||||
free( opening_bnr );
|
||||
return NULL;
|
||||
}
|
||||
const U8Header *bnrArcHdr = (U8Header *)(imetHdr + 1);
|
||||
}
|
||||
const U8Header *bnrArcHdr = ( U8Header * )( imetHdr + 1 );
|
||||
|
||||
fst = (const U8Entry *)( ((const u8 *)bnrArcHdr) + bnrArcHdr->rootNodeOffset);
|
||||
u32 i;
|
||||
for (i = 1; i < fst[0].numEntries; ++i)
|
||||
if (fst[i].fileType == 0 && strcasecmp(u8Filename(fst, i), "sound.bin") == 0)
|
||||
break;
|
||||
if (i >= fst[0].numEntries)
|
||||
{
|
||||
/* Not all games have a sound.bin and this message is annoying **/
|
||||
//WindowPrompt(tr("sound.bin not found."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
fst = ( const U8Entry * )( ( ( const u8 * )bnrArcHdr ) + bnrArcHdr->rootNodeOffset );
|
||||
u32 i;
|
||||
for ( i = 1; i < fst[0].numEntries; ++i )
|
||||
if ( fst[i].fileType == 0 && strcasecmp( u8Filename( fst, i ), "sound.bin" ) == 0 )
|
||||
break;
|
||||
if ( i >= fst[0].numEntries )
|
||||
{
|
||||
/* Not all games have a sound.bin and this message is annoying **/
|
||||
//WindowPrompt(tr("sound.bin not found."), 0, tr("OK"));
|
||||
free( opening_bnr );
|
||||
return NULL;
|
||||
}
|
||||
const u8 *sound_bin = ((const u8 *)bnrArcHdr) + fst[i].fileOffset;
|
||||
if ( ((IMD5Header *)sound_bin)->fcc != 0x494D4435 /*"IMD5"*/ )
|
||||
{
|
||||
// WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
}
|
||||
const u8 *sound_bin = ( ( const u8 * )bnrArcHdr ) + fst[i].fileOffset;
|
||||
if ( ( ( IMD5Header * )sound_bin )->fcc != 0x494D4435 /*"IMD5"*/ )
|
||||
{
|
||||
// WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK"));
|
||||
free( opening_bnr );
|
||||
return NULL;
|
||||
}
|
||||
const u8 *soundChunk = sound_bin + sizeof (IMD5Header);;
|
||||
u32 soundChunkSize = fst[i].fileLength - sizeof (IMD5Header);
|
||||
}
|
||||
const u8 *soundChunk = sound_bin + sizeof ( IMD5Header );;
|
||||
u32 soundChunkSize = fst[i].fileLength - sizeof ( IMD5Header );
|
||||
|
||||
if ( *((u32*)soundChunk) == 0x4C5A3737 /*"LZ77"*/ )
|
||||
{
|
||||
u32 uncSize = NULL;
|
||||
u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, uncSize);
|
||||
if (!uncompressed_data)
|
||||
{
|
||||
// WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
return NULL;
|
||||
}
|
||||
if(size) *size=uncSize;
|
||||
free(opening_bnr);
|
||||
return uncompressed_data;
|
||||
}
|
||||
u8 *out = new(std::nothrow) u8[soundChunkSize];
|
||||
if(out)
|
||||
{
|
||||
memcpy(out, soundChunk, soundChunkSize);
|
||||
if(size) *size=soundChunkSize;
|
||||
}
|
||||
free(opening_bnr);
|
||||
return out;
|
||||
if ( *( ( u32* )soundChunk ) == 0x4C5A3737 /*"LZ77"*/ )
|
||||
{
|
||||
u32 uncSize = NULL;
|
||||
u8 * uncompressed_data = uncompressLZ77( soundChunk, soundChunkSize, uncSize );
|
||||
if ( !uncompressed_data )
|
||||
{
|
||||
// WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK"));
|
||||
free( opening_bnr );
|
||||
return NULL;
|
||||
}
|
||||
if ( size ) *size = uncSize;
|
||||
free( opening_bnr );
|
||||
return uncompressed_data;
|
||||
}
|
||||
u8 *out = new( std::nothrow ) u8[soundChunkSize];
|
||||
if ( out )
|
||||
{
|
||||
memcpy( out, soundChunk, soundChunkSize );
|
||||
if ( size ) *size = soundChunkSize;
|
||||
}
|
||||
free( opening_bnr );
|
||||
return out;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifndef BANNERSOUND_H
|
||||
#define BANNERSOUND_H
|
||||
|
||||
const u8 *LoadBannerSound(const u8 *discid, u32 *size);
|
||||
const u8 *LoadBannerSound( const u8 *discid, u32 *size );
|
||||
|
||||
#endif /* BANNERSOUND_H */
|
||||
|
@ -23,143 +23,160 @@ extern GuiWindow * mainWindow;
|
||||
/****************************************************************************
|
||||
* CheatMenu
|
||||
***************************************************************************/
|
||||
int CheatMenu(const char * gameID) {
|
||||
int choice = 0;
|
||||
bool exit = false;
|
||||
int ret = 1;
|
||||
int CheatMenu( const char * gameID )
|
||||
{
|
||||
int choice = 0;
|
||||
bool exit = false;
|
||||
int ret = 1;
|
||||
|
||||
// because destroy GuiSound must wait while sound playing is finished, we use a global sound
|
||||
if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
// because destroy GuiSound must wait while sound playing is finished, we use a global sound
|
||||
if ( !btnClick2 ) btnClick2 = new GuiSound( button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume );
|
||||
// GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||
|
||||
char imgPath[100];
|
||||
snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path);
|
||||
GuiImageData btnOutline(imgPath, button_dialogue_box_png);
|
||||
snprintf(imgPath, sizeof(imgPath), "%ssettings_background.png", CFG.theme_path);
|
||||
GuiImageData settingsbg(imgPath, settings_background_png);
|
||||
GuiImage settingsbackground(&settingsbg);
|
||||
char imgPath[100];
|
||||
snprintf( imgPath, sizeof( imgPath ), "%sbutton_dialogue_box.png", CFG.theme_path );
|
||||
GuiImageData btnOutline( imgPath, button_dialogue_box_png );
|
||||
snprintf( imgPath, sizeof( imgPath ), "%ssettings_background.png", CFG.theme_path );
|
||||
GuiImageData settingsbg( imgPath, settings_background_png );
|
||||
GuiImage settingsbackground( &settingsbg );
|
||||
|
||||
GuiTrigger trigA;
|
||||
trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
|
||||
GuiTrigger trigB;
|
||||
trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B);
|
||||
GuiTrigger trigA;
|
||||
trigA.SetSimpleTrigger( -1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A );
|
||||
GuiTrigger trigB;
|
||||
trigB.SetButtonOnlyTrigger( -1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B );
|
||||
|
||||
GuiText backBtnTxt(tr("Back") , 22, THEME.prompttext);
|
||||
backBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30);
|
||||
GuiImage backBtnImg(&btnOutline);
|
||||
GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -140, 400, &trigA, NULL, btnClick2,1);
|
||||
backBtn.SetLabel(&backBtnTxt);
|
||||
backBtn.SetTrigger(&trigB);
|
||||
GuiText backBtnTxt( tr( "Back" ) , 22, THEME.prompttext );
|
||||
backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
|
||||
GuiImage backBtnImg( &btnOutline );
|
||||
GuiButton backBtn( &backBtnImg, &backBtnImg, 2, 3, -140, 400, &trigA, NULL, btnClick2, 1 );
|
||||
backBtn.SetLabel( &backBtnTxt );
|
||||
backBtn.SetTrigger( &trigB );
|
||||
|
||||
GuiText createBtnTxt(tr("Create") , 22, THEME.prompttext);
|
||||
createBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30);
|
||||
GuiImage createBtnImg(&btnOutline);
|
||||
GuiButton createBtn(&createBtnImg,&createBtnImg, 2, 3, 160, 400, &trigA, NULL, btnClick2,1);
|
||||
createBtn.SetLabel(&createBtnTxt);
|
||||
GuiText createBtnTxt( tr( "Create" ) , 22, THEME.prompttext );
|
||||
createBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
|
||||
GuiImage createBtnImg( &btnOutline );
|
||||
GuiButton createBtn( &createBtnImg, &createBtnImg, 2, 3, 160, 400, &trigA, NULL, btnClick2, 1 );
|
||||
createBtn.SetLabel( &createBtnTxt );
|
||||
|
||||
char txtfilename[55];
|
||||
snprintf(txtfilename,sizeof(txtfilename),"%s%s.txt",Settings.TxtCheatcodespath,gameID);
|
||||
char txtfilename[55];
|
||||
snprintf( txtfilename, sizeof( txtfilename ), "%s%s.txt", Settings.TxtCheatcodespath, gameID );
|
||||
|
||||
GCTCheats c;
|
||||
int check = c.openTxtfile(txtfilename);
|
||||
GCTCheats c;
|
||||
int check = c.openTxtfile( txtfilename );
|
||||
|
||||
int download =0;
|
||||
int download = 0;
|
||||
|
||||
switch (check) {
|
||||
case -1:
|
||||
WindowPrompt(tr("Error"),tr("Cheatfile is blank"),tr("OK"));
|
||||
break;
|
||||
case 0:
|
||||
download = WindowPrompt(tr("Error"),tr("No Cheatfile found"),tr("Download Now"),tr("Cancel"));
|
||||
if (download==1)
|
||||
{
|
||||
download = CodeDownload(gameID);
|
||||
if(download < 0 || c.openTxtfile(txtfilename) != 1)
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
case 1:
|
||||
int cntcheats = c.getCnt();
|
||||
customOptionList cheatslst(cntcheats);
|
||||
GuiCustomOptionBrowser chtBrowser(400, 280, &cheatslst, CFG.theme_path, "bg_options_settings.png", bg_options_settings_png, 1, 90);
|
||||
chtBrowser.SetPosition(0, 90);
|
||||
chtBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
chtBrowser.SetClickable(true);
|
||||
switch ( check )
|
||||
{
|
||||
case -1:
|
||||
WindowPrompt( tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ) );
|
||||
break;
|
||||
case 0:
|
||||
download = WindowPrompt( tr( "Error" ), tr( "No Cheatfile found" ), tr( "Download Now" ), tr( "Cancel" ) );
|
||||
if ( download == 1 )
|
||||
{
|
||||
download = CodeDownload( gameID );
|
||||
if ( download < 0 || c.openTxtfile( txtfilename ) != 1 )
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
case 1:
|
||||
int cntcheats = c.getCnt();
|
||||
customOptionList cheatslst( cntcheats );
|
||||
GuiCustomOptionBrowser chtBrowser( 400, 280, &cheatslst, CFG.theme_path, "bg_options_settings.png", bg_options_settings_png, 1, 90 );
|
||||
chtBrowser.SetPosition( 0, 90 );
|
||||
chtBrowser.SetAlignment( ALIGN_CENTRE, ALIGN_TOP );
|
||||
chtBrowser.SetClickable( true );
|
||||
|
||||
GuiText titleTxt(c.getGameName().c_str(), 28, (GXColor) {0, 0, 0, 255});
|
||||
titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
titleTxt.SetMaxWidth(350, SCROLL_HORIZONTAL);
|
||||
titleTxt.SetPosition(12,40);
|
||||
GuiText titleTxt( c.getGameName().c_str(), 28, ( GXColor ) {0, 0, 0, 255} );
|
||||
titleTxt.SetAlignment( ALIGN_CENTRE, ALIGN_TOP );
|
||||
titleTxt.SetMaxWidth( 350, SCROLL_HORIZONTAL );
|
||||
titleTxt.SetPosition( 12, 40 );
|
||||
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
cheatslst.SetValue(i, "%s",c.getCheatName(i).c_str());
|
||||
cheatslst.SetName(i, "OFF");
|
||||
}
|
||||
for ( int i = 0; i <= cntcheats; i++ )
|
||||
{
|
||||
cheatslst.SetValue( i, "%s", c.getCheatName( i ).c_str() );
|
||||
cheatslst.SetName( i, "OFF" );
|
||||
}
|
||||
|
||||
HaltGui();
|
||||
GuiWindow w(screenwidth, screenheight);
|
||||
w.Append(&settingsbackground);
|
||||
w.Append(&titleTxt);
|
||||
w.Append(&backBtn);
|
||||
w.Append(&createBtn);
|
||||
w.Append(&chtBrowser);
|
||||
mainWindow->SetState(STATE_DISABLED);
|
||||
mainWindow->ChangeFocus(&w);
|
||||
mainWindow->Append(&w);
|
||||
ResumeGui();
|
||||
HaltGui();
|
||||
GuiWindow w( screenwidth, screenheight );
|
||||
w.Append( &settingsbackground );
|
||||
w.Append( &titleTxt );
|
||||
w.Append( &backBtn );
|
||||
w.Append( &createBtn );
|
||||
w.Append( &chtBrowser );
|
||||
mainWindow->SetState( STATE_DISABLED );
|
||||
mainWindow->ChangeFocus( &w );
|
||||
mainWindow->Append( &w );
|
||||
ResumeGui();
|
||||
|
||||
while (!exit) {
|
||||
VIDEO_WaitVSync ();
|
||||
while ( !exit )
|
||||
{
|
||||
VIDEO_WaitVSync ();
|
||||
|
||||
ret = chtBrowser.GetClickedOption();
|
||||
if (ret != -1) {
|
||||
const char *strCheck = cheatslst.GetName(ret);
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
cheatslst.SetName(ret,"%s","OFF");
|
||||
} else if (strncmp(strCheck,"OFF",3) == 0) {
|
||||
cheatslst.SetName(ret,"%s","ON");
|
||||
}
|
||||
}
|
||||
ret = chtBrowser.GetClickedOption();
|
||||
if ( ret != -1 )
|
||||
{
|
||||
const char *strCheck = cheatslst.GetName( ret );
|
||||
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
||||
{
|
||||
cheatslst.SetName( ret, "%s", "OFF" );
|
||||
}
|
||||
else if ( strncmp( strCheck, "OFF", 3 ) == 0 )
|
||||
{
|
||||
cheatslst.SetName( ret, "%s", "ON" );
|
||||
}
|
||||
}
|
||||
|
||||
if (createBtn.GetState() == STATE_CLICKED) {
|
||||
createBtn.ResetState();
|
||||
if (cntcheats > 0) {
|
||||
int selectednrs[30];
|
||||
int x = 0;
|
||||
for (int i = 0; i <= cntcheats; i++) {
|
||||
const char *strCheck = cheatslst.GetName(i);
|
||||
if (strncmp(strCheck,"ON",2) == 0) {
|
||||
selectednrs[x] = i;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
if (x == 0) {
|
||||
WindowPrompt(tr("Error"),tr("No cheats were selected"),tr("OK"));
|
||||
} else {
|
||||
subfoldercreate(Settings.Cheatcodespath);
|
||||
string chtpath = Settings.Cheatcodespath;
|
||||
string gctfname = chtpath + c.getGameID() + ".gct";
|
||||
c.createGCT(selectednrs,x,gctfname.c_str());
|
||||
WindowPrompt(tr("GCT File created"),NULL,tr("OK"));
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
} else WindowPrompt(tr("Error"),tr("Could not create GCT file"),tr("OK"));
|
||||
}
|
||||
if ( createBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
createBtn.ResetState();
|
||||
if ( cntcheats > 0 )
|
||||
{
|
||||
int selectednrs[30];
|
||||
int x = 0;
|
||||
for ( int i = 0; i <= cntcheats; i++ )
|
||||
{
|
||||
const char *strCheck = cheatslst.GetName( i );
|
||||
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
||||
{
|
||||
selectednrs[x] = i;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
if ( x == 0 )
|
||||
{
|
||||
WindowPrompt( tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
subfoldercreate( Settings.Cheatcodespath );
|
||||
string chtpath = Settings.Cheatcodespath;
|
||||
string gctfname = chtpath + c.getGameID() + ".gct";
|
||||
c.createGCT( selectednrs, x, gctfname.c_str() );
|
||||
WindowPrompt( tr( "GCT File created" ), NULL, tr( "OK" ) );
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else WindowPrompt( tr( "Error" ), tr( "Could not create GCT file" ), tr( "OK" ) );
|
||||
}
|
||||
|
||||
if (backBtn.GetState() == STATE_CLICKED) {
|
||||
backBtn.ResetState();
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HaltGui();
|
||||
mainWindow->SetState(STATE_DEFAULT);
|
||||
mainWindow->Remove(&w);
|
||||
ResumeGui();
|
||||
break;
|
||||
}
|
||||
if ( backBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
backBtn.ResetState();
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HaltGui();
|
||||
mainWindow->SetState( STATE_DEFAULT );
|
||||
mainWindow->Remove( &w );
|
||||
ResumeGui();
|
||||
break;
|
||||
}
|
||||
|
||||
return choice;
|
||||
return choice;
|
||||
}
|
||||
|
@ -8,6 +8,6 @@
|
||||
#ifndef _CHEATMENU_H_
|
||||
#define _CHEATMENU_H_
|
||||
|
||||
int CheatMenu(const char * gameID);
|
||||
int CheatMenu( const char * gameID );
|
||||
|
||||
#endif
|
||||
|
@ -12,96 +12,116 @@
|
||||
|
||||
#define ERRORRANGE "Error: CheatNr out of range"
|
||||
|
||||
GCTCheats::GCTCheats(void) {
|
||||
GCTCheats::GCTCheats( void )
|
||||
{
|
||||
iCntCheats = 0;
|
||||
}
|
||||
|
||||
GCTCheats::~GCTCheats(void) {
|
||||
GCTCheats::~GCTCheats( void )
|
||||
{
|
||||
|
||||
string sGameID ="";
|
||||
string sGameID = "";
|
||||
string sGameTitle = "";
|
||||
/*string sCheatName[MAXCHEATS];
|
||||
string sCheats[MAXCHEATS];
|
||||
string sCheatComment[MAXCHEATS];*/
|
||||
}
|
||||
|
||||
int GCTCheats::getCnt() {
|
||||
int GCTCheats::getCnt()
|
||||
{
|
||||
return iCntCheats;
|
||||
}
|
||||
|
||||
string GCTCheats::getGameName(void) {
|
||||
string GCTCheats::getGameName( void )
|
||||
{
|
||||
return sGameTitle;
|
||||
}
|
||||
|
||||
string GCTCheats::getGameID(void) {
|
||||
string GCTCheats::getGameID( void )
|
||||
{
|
||||
return sGameID;
|
||||
}
|
||||
|
||||
string GCTCheats::getCheat(int nr) {
|
||||
if (nr <= (iCntCheats-1)) {
|
||||
string GCTCheats::getCheat( int nr )
|
||||
{
|
||||
if ( nr <= ( iCntCheats - 1 ) )
|
||||
{
|
||||
return sCheats[nr];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERRORRANGE;
|
||||
}
|
||||
}
|
||||
|
||||
string GCTCheats::getCheatName(int nr) {
|
||||
if (nr <= (iCntCheats-1)) {
|
||||
string GCTCheats::getCheatName( int nr )
|
||||
{
|
||||
if ( nr <= ( iCntCheats - 1 ) )
|
||||
{
|
||||
return sCheatName[nr];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERRORRANGE;
|
||||
}
|
||||
}
|
||||
|
||||
string GCTCheats::getCheatComment(int nr) {
|
||||
if (nr <= (iCntCheats-1)) {
|
||||
string GCTCheats::getCheatComment( int nr )
|
||||
{
|
||||
if ( nr <= ( iCntCheats - 1 ) )
|
||||
{
|
||||
return sCheatComment[nr];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERRORRANGE;
|
||||
}
|
||||
}
|
||||
|
||||
int GCTCheats::createGCT(int nr,const char * filename) {
|
||||
int GCTCheats::createGCT( int nr, const char * filename )
|
||||
{
|
||||
|
||||
if (nr == 0)
|
||||
return 0;
|
||||
if ( nr == 0 )
|
||||
return 0;
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
filestr.open( filename );
|
||||
|
||||
if (filestr.fail())
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
|
||||
//Header and Footer
|
||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde};
|
||||
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
string buf = getCheat(nr);
|
||||
filestr.write(header,sizeof(header));
|
||||
string buf = getCheat( nr );
|
||||
filestr.write( header, sizeof( header ) );
|
||||
|
||||
int x = 0;
|
||||
long int li;
|
||||
int len = buf.size();
|
||||
|
||||
while (x < len) {
|
||||
string temp = buf.substr(x,2);
|
||||
li = strtol(temp.c_str(),NULL,16);
|
||||
while ( x < len )
|
||||
{
|
||||
string temp = buf.substr( x, 2 );
|
||||
li = strtol( temp.c_str(), NULL, 16 );
|
||||
temp = li;
|
||||
filestr.write(temp.c_str(),1);
|
||||
x +=2;
|
||||
filestr.write( temp.c_str(), 1 );
|
||||
x += 2;
|
||||
}
|
||||
filestr.write(footer,sizeof(footer));
|
||||
filestr.write( footer, sizeof( footer ) );
|
||||
|
||||
filestr.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
||||
int GCTCheats::createGCT( const char * chtbuffer, const char * filename )
|
||||
{
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
filestr.open( filename );
|
||||
|
||||
if (filestr.fail())
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
|
||||
//Header and Footer
|
||||
@ -109,146 +129,162 @@ int GCTCheats::createGCT(const char * chtbuffer,const char * filename) {
|
||||
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
string buf = chtbuffer;
|
||||
filestr.write(header,sizeof(header));
|
||||
filestr.write( header, sizeof( header ) );
|
||||
|
||||
int x = 0;
|
||||
long int li;
|
||||
int len = buf.size();
|
||||
|
||||
while (x < len) {
|
||||
string temp = buf.substr(x,2);
|
||||
li = strtol(temp.c_str(),NULL,16);
|
||||
while ( x < len )
|
||||
{
|
||||
string temp = buf.substr( x, 2 );
|
||||
li = strtol( temp.c_str(), NULL, 16 );
|
||||
temp = li;
|
||||
filestr.write(temp.c_str(),1);
|
||||
x +=2;
|
||||
filestr.write( temp.c_str(), 1 );
|
||||
x += 2;
|
||||
}
|
||||
|
||||
filestr.write(footer,sizeof(footer));
|
||||
filestr.write( footer, sizeof( footer ) );
|
||||
|
||||
filestr.close();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GCTCheats::createGCT(int nr[],int cnt,const char * filename) {
|
||||
int GCTCheats::createGCT( int nr[], int cnt, const char * filename )
|
||||
{
|
||||
|
||||
if (cnt == 0)
|
||||
return 0;
|
||||
if ( cnt == 0 )
|
||||
return 0;
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
filestr.open( filename );
|
||||
|
||||
if (filestr.fail())
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
|
||||
//Header and Footer
|
||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde};
|
||||
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
filestr.write(header,sizeof(header));
|
||||
filestr.write( header, sizeof( header ) );
|
||||
|
||||
int c = 0;
|
||||
while (c != cnt) {
|
||||
while ( c != cnt )
|
||||
{
|
||||
int actnr = nr[c];
|
||||
string buf = getCheat(actnr);
|
||||
string buf = getCheat( actnr );
|
||||
long int li;
|
||||
int len = buf.size();
|
||||
int x = 0;
|
||||
|
||||
while (x < len) {
|
||||
string temp = buf.substr(x,2);
|
||||
li = strtol(temp.c_str(),NULL,16);
|
||||
while ( x < len )
|
||||
{
|
||||
string temp = buf.substr( x, 2 );
|
||||
li = strtol( temp.c_str(), NULL, 16 );
|
||||
temp = li;
|
||||
filestr.write(temp.c_str(),1);
|
||||
x +=2;
|
||||
filestr.write( temp.c_str(), 1 );
|
||||
x += 2;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
filestr.write(footer,sizeof(footer));
|
||||
filestr.write( footer, sizeof( footer ) );
|
||||
filestr.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GCTCheats::openTxtfile(const char * filename) {
|
||||
int GCTCheats::openTxtfile( const char * filename )
|
||||
{
|
||||
ifstream filestr;
|
||||
int i = 0;
|
||||
string str;
|
||||
filestr.open(filename);
|
||||
filestr.open( filename );
|
||||
|
||||
if (filestr.fail())
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
|
||||
filestr.seekg(0,ios_base::end);
|
||||
filestr.seekg( 0, ios_base::end );
|
||||
int size = filestr.tellg();
|
||||
if (size <= 0) return -1;
|
||||
filestr.seekg(0,ios_base::beg);
|
||||
if ( size <= 0 ) return -1;
|
||||
filestr.seekg( 0, ios_base::beg );
|
||||
|
||||
getline(filestr,sGameID);
|
||||
if (sGameID[sGameID.length() - 1] == '\r')
|
||||
sGameID.erase(sGameID.length() - 1);
|
||||
getline( filestr, sGameID );
|
||||
if ( sGameID[sGameID.length() - 1] == '\r' )
|
||||
sGameID.erase( sGameID.length() - 1 );
|
||||
|
||||
getline(filestr,sGameTitle);
|
||||
if (sGameTitle[sGameTitle.length() - 1] == '\r')
|
||||
sGameTitle.erase(sGameTitle.length() - 1);
|
||||
getline( filestr, sGameTitle );
|
||||
if ( sGameTitle[sGameTitle.length() - 1] == '\r' )
|
||||
sGameTitle.erase( sGameTitle.length() - 1 );
|
||||
|
||||
getline(filestr,sCheatName[i]); // skip first line if file uses CRLF
|
||||
if (!sGameTitle[sGameTitle.length() - 1] == '\r')
|
||||
filestr.seekg(0,ios_base::beg);
|
||||
getline( filestr, sCheatName[i] ); // skip first line if file uses CRLF
|
||||
if ( !sGameTitle[sGameTitle.length() - 1] == '\r' )
|
||||
filestr.seekg( 0, ios_base::beg );
|
||||
|
||||
while (!filestr.eof()) {
|
||||
getline(filestr,sCheatName[i]); // '\n' delimiter by default
|
||||
if (sCheatName[i][sCheatName[i].length() - 1] == '\r')
|
||||
sCheatName[i].erase(sCheatName[i].length() - 1);
|
||||
while ( !filestr.eof() )
|
||||
{
|
||||
getline( filestr, sCheatName[i] ); // '\n' delimiter by default
|
||||
if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' )
|
||||
sCheatName[i].erase( sCheatName[i].length() - 1 );
|
||||
|
||||
string cheatdata;
|
||||
bool emptyline = false;
|
||||
|
||||
do {
|
||||
getline(filestr,str);
|
||||
if (str[str.length() - 1] == '\r')
|
||||
str.erase(str.length() - 1);
|
||||
do
|
||||
{
|
||||
getline( filestr, str );
|
||||
if ( str[str.length() - 1] == '\r' )
|
||||
str.erase( str.length() - 1 );
|
||||
|
||||
if (str == "" || str[0] == '\r' || str[0] == '\n') {
|
||||
if ( str == "" || str[0] == '\r' || str[0] == '\n' )
|
||||
{
|
||||
emptyline = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsCode(str)) {
|
||||
// remove any garbage (comment) after code
|
||||
while (str.size() > 17) {
|
||||
str.erase(str.length() - 1);
|
||||
}
|
||||
cheatdata.append(str);
|
||||
size_t found=cheatdata.find(' ');
|
||||
cheatdata.replace(found,1,"");
|
||||
} else {
|
||||
if ( IsCode( str ) )
|
||||
{
|
||||
// remove any garbage (comment) after code
|
||||
while ( str.size() > 17 )
|
||||
{
|
||||
str.erase( str.length() - 1 );
|
||||
}
|
||||
cheatdata.append( str );
|
||||
size_t found = cheatdata.find( ' ' );
|
||||
cheatdata.replace( found, 1, "" );
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("%i",str.size());
|
||||
sCheatComment[i] = str;
|
||||
}
|
||||
if (filestr.eof()) break;
|
||||
if ( filestr.eof() ) break;
|
||||
|
||||
} while (!emptyline);
|
||||
}
|
||||
while ( !emptyline );
|
||||
|
||||
sCheats[i] = cheatdata;
|
||||
i++;
|
||||
if (i == MAXCHEATS) break;
|
||||
i++;
|
||||
if ( i == MAXCHEATS ) break;
|
||||
}
|
||||
iCntCheats = i;
|
||||
filestr.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GCTCheats::IsCode(const std::string& str) {
|
||||
if (str[8] == ' ' && str.size() >= 17) {
|
||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||
char part1[9];
|
||||
char part2[9];
|
||||
snprintf(part1,sizeof(part1),"%c%c%c%c%c%c%c%c",str[0],str[1],str[2],str[3],str[4],str[5],str[6],str[7]);
|
||||
snprintf(part2,sizeof(part2),"%c%c%c%c%c%c%c%c",str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16]);
|
||||
if ((strtok(part1,"0123456789ABCDEFabcdef") == NULL) && (strtok(part2,"0123456789ABCDEFabcdef") == NULL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
bool GCTCheats::IsCode( const std::string& str )
|
||||
{
|
||||
if ( str[8] == ' ' && str.size() >= 17 )
|
||||
{
|
||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||
char part1[9];
|
||||
char part2[9];
|
||||
snprintf( part1, sizeof( part1 ), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7] );
|
||||
snprintf( part2, sizeof( part2 ), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14], str[15], str[16] );
|
||||
if ( ( strtok( part1, "0123456789ABCDEFabcdef" ) == NULL ) && ( strtok( part2, "0123456789ABCDEFabcdef" ) == NULL ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -14,61 +14,62 @@
|
||||
using namespace std;
|
||||
|
||||
//!Handles Ocarina TXT Cheatfiles
|
||||
class GCTCheats {
|
||||
private:
|
||||
string sGameID;
|
||||
string sGameTitle;
|
||||
string sCheatName[MAXCHEATS];
|
||||
string sCheats[MAXCHEATS];
|
||||
string sCheatComment[MAXCHEATS];
|
||||
int iCntCheats;
|
||||
class GCTCheats
|
||||
{
|
||||
private:
|
||||
string sGameID;
|
||||
string sGameTitle;
|
||||
string sCheatName[MAXCHEATS];
|
||||
string sCheats[MAXCHEATS];
|
||||
string sCheatComment[MAXCHEATS];
|
||||
int iCntCheats;
|
||||
|
||||
public:
|
||||
//!Constructor
|
||||
GCTCheats(void);
|
||||
//!Destructor
|
||||
~GCTCheats(void);
|
||||
//!Open txt file with cheats
|
||||
//!\param filename name of TXT file
|
||||
//!\return error code
|
||||
int openTxtfile(const char * filename);
|
||||
//!Creates GCT file for one cheat
|
||||
//!\param nr selected Cheat Numbers
|
||||
//!\param filename name of GCT file
|
||||
//!\return error code
|
||||
int createGCT(int nr,const char * filename);
|
||||
//!Creates GCT file from a buffer
|
||||
//!\param chtbuffer buffer that holds the cheat data
|
||||
//!\param filename name of GCT file
|
||||
//!\return error code
|
||||
int createGCT(const char * chtbuffer,const char * filename);
|
||||
//!Creates GCT file
|
||||
//!\param nr[] array of selected Cheat Numbers
|
||||
//!\param cnt size of array
|
||||
//!\param filename name of GCT file
|
||||
//!\return error code
|
||||
int createGCT(int nr[],int cnt,const char * filename);
|
||||
//!Gets Count cheats
|
||||
//!\return Count cheats
|
||||
int getCnt();
|
||||
//!Gets Game Name
|
||||
//!\return Game Name
|
||||
string getGameName(void);
|
||||
//!Gets GameID
|
||||
//!\return GameID
|
||||
string getGameID(void);
|
||||
//!Gets cheat data
|
||||
//!\return cheat data
|
||||
string getCheat(int nr);
|
||||
//!Gets Cheat Name
|
||||
//!\return Cheat Name
|
||||
string getCheatName(int nr);
|
||||
//!Gets Cheat Comment
|
||||
//!\return Cheat Comment
|
||||
string getCheatComment(int nr);
|
||||
//!Check if string is a code
|
||||
//!\return true/false
|
||||
bool IsCode(const std::string& s);
|
||||
public:
|
||||
//!Constructor
|
||||
GCTCheats( void );
|
||||
//!Destructor
|
||||
~GCTCheats( void );
|
||||
//!Open txt file with cheats
|
||||
//!\param filename name of TXT file
|
||||
//!\return error code
|
||||
int openTxtfile( const char * filename );
|
||||
//!Creates GCT file for one cheat
|
||||
//!\param nr selected Cheat Numbers
|
||||
//!\param filename name of GCT file
|
||||
//!\return error code
|
||||
int createGCT( int nr, const char * filename );
|
||||
//!Creates GCT file from a buffer
|
||||
//!\param chtbuffer buffer that holds the cheat data
|
||||
//!\param filename name of GCT file
|
||||
//!\return error code
|
||||
int createGCT( const char * chtbuffer, const char * filename );
|
||||
//!Creates GCT file
|
||||
//!\param nr[] array of selected Cheat Numbers
|
||||
//!\param cnt size of array
|
||||
//!\param filename name of GCT file
|
||||
//!\return error code
|
||||
int createGCT( int nr[], int cnt, const char * filename );
|
||||
//!Gets Count cheats
|
||||
//!\return Count cheats
|
||||
int getCnt();
|
||||
//!Gets Game Name
|
||||
//!\return Game Name
|
||||
string getGameName( void );
|
||||
//!Gets GameID
|
||||
//!\return GameID
|
||||
string getGameID( void );
|
||||
//!Gets cheat data
|
||||
//!\return cheat data
|
||||
string getCheat( int nr );
|
||||
//!Gets Cheat Name
|
||||
//!\return Cheat Name
|
||||
string getCheatName( int nr );
|
||||
//!Gets Cheat Comment
|
||||
//!\return Cheat Comment
|
||||
string getCheatComment( int nr );
|
||||
//!Check if string is a code
|
||||
//!\return true/false
|
||||
bool IsCode( const std::string& s );
|
||||
};
|
||||
|
||||
#endif /* _GCT_H */
|
||||
|
@ -44,198 +44,219 @@ sec_t fat_wbfs_sec = 0;
|
||||
int fs_ntfs_mount = 0;
|
||||
sec_t fs_ntfs_sec = 0;
|
||||
|
||||
int USBDevice_Init() {
|
||||
int USBDevice_Init()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf("\nUSBDevice_Init()");
|
||||
gprintf( "\nUSBDevice_Init()" );
|
||||
#endif
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("USB:/");
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount( "USB:/" );
|
||||
//right now mounts first FAT-partition
|
||||
|
||||
//try first mount with cIOS
|
||||
//try first mount with cIOS
|
||||
// if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
// //try now mount with libogc
|
||||
if (!fatMount("USB", &__io_usbstorage2, 0, CACHE, SECTORS)) {
|
||||
// //try now mount with libogc
|
||||
if ( !fatMount( "USB", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":-1");
|
||||
gprintf( ":-1" );
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
|
||||
fat_usb_mount = 1;
|
||||
fat_usb_sec = _FAT_startSector;
|
||||
fat_usb_mount = 1;
|
||||
fat_usb_sec = _FAT_startSector;
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":0");
|
||||
gprintf( ":0" );
|
||||
#endif
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBDevice_deInit() {
|
||||
void USBDevice_deInit()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf("\nUSBDevice_deInit()");
|
||||
gprintf( "\nUSBDevice_deInit()" );
|
||||
#endif
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("USB:/");
|
||||
fatUnmount( "USB:/" );
|
||||
|
||||
fat_usb_mount = 0;
|
||||
fat_usb_sec = 0;
|
||||
fat_usb_mount = 0;
|
||||
fat_usb_sec = 0;
|
||||
}
|
||||
|
||||
int WBFSDevice_Init(u32 sector) {
|
||||
int WBFSDevice_Init( u32 sector )
|
||||
{
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("WBFS:/");
|
||||
fatUnmount( "WBFS:/" );
|
||||
//right now mounts first FAT-partition
|
||||
|
||||
//try first mount with cIOS
|
||||
//try first mount with cIOS
|
||||
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
//try now mount with libogc
|
||||
if (!fatMount("WBFS", &__io_usbstorage2, 0, CACHE, SECTORS)) {
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
//try now mount with libogc
|
||||
if ( !fatMount( "WBFS", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
|
||||
fat_wbfs_mount = 1;
|
||||
fat_wbfs_sec = _FAT_startSector;
|
||||
if (sector && fat_wbfs_sec != sector) {
|
||||
// This is an error situation...actually, but is ignored in Config loader also
|
||||
// Should ask Oggzee about it...
|
||||
}
|
||||
return 0;
|
||||
fat_wbfs_mount = 1;
|
||||
fat_wbfs_sec = _FAT_startSector;
|
||||
if ( sector && fat_wbfs_sec != sector )
|
||||
{
|
||||
// This is an error situation...actually, but is ignored in Config loader also
|
||||
// Should ask Oggzee about it...
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WBFSDevice_deInit() {
|
||||
void WBFSDevice_deInit()
|
||||
{
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("WBFS:/");
|
||||
fatUnmount( "WBFS:/" );
|
||||
|
||||
fat_wbfs_mount = 0;
|
||||
fat_wbfs_sec = 0;
|
||||
fat_wbfs_mount = 0;
|
||||
fat_wbfs_sec = 0;
|
||||
}
|
||||
|
||||
int isInserted(const char *path) {
|
||||
if (!strncmp(path, "USB:", 4))
|
||||
int isInserted( const char *path )
|
||||
{
|
||||
if ( !strncmp( path, "USB:", 4 ) )
|
||||
return 1;
|
||||
|
||||
return __io_sdhc.isInserted() || __io_wiisd.isInserted();
|
||||
}
|
||||
|
||||
int SDCard_Init() {
|
||||
int SDCard_Init()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf("\nSDCard_Init()");
|
||||
gprintf( "\nSDCard_Init()" );
|
||||
#endif
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("SD:/");
|
||||
fatUnmount( "SD:/" );
|
||||
//right now mounts first FAT-partition
|
||||
if (fatMount("SD", &__io_wiisd, 0, CACHE, SECTORS)) {
|
||||
fat_sd_mount = MOUNT_SD;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
if ( fatMount( "SD", &__io_wiisd, 0, CACHE, SECTORS ) )
|
||||
{
|
||||
fat_sd_mount = MOUNT_SD;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":1");
|
||||
gprintf( ":1" );
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
else if (fatMount("SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE)) {
|
||||
fat_sd_mount = MOUNT_SDHC;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
return 1;
|
||||
}
|
||||
else if ( fatMount( "SD", &__io_sdhc, 0, CACHE, SDHC_SECTOR_SIZE ) )
|
||||
{
|
||||
fat_sd_mount = MOUNT_SDHC;
|
||||
fat_sd_sec = _FAT_startSector;
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":1");
|
||||
gprintf( ":1" );
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":-1");
|
||||
gprintf( ":-1" );
|
||||
#endif
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SDCard_deInit() {
|
||||
void SDCard_deInit()
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf("\nSDCard_deInit()");
|
||||
gprintf( "\nSDCard_deInit()" );
|
||||
#endif
|
||||
//closing all open Files write back the cache and then shutdown em!
|
||||
fatUnmount("SD:/");
|
||||
fatUnmount( "SD:/" );
|
||||
|
||||
fat_sd_mount = MOUNT_NONE;
|
||||
fat_sd_sec = 0;
|
||||
fat_sd_mount = MOUNT_NONE;
|
||||
fat_sd_sec = 0;
|
||||
}
|
||||
|
||||
void ntfsInit();
|
||||
|
||||
s32 MountNTFS(u32 sector)
|
||||
s32 MountNTFS( u32 sector )
|
||||
{
|
||||
s32 ret;
|
||||
s32 ret;
|
||||
|
||||
if (fs_ntfs_mount) return 0;
|
||||
//printf("mounting NTFS\n");
|
||||
//Wpad_WaitButtons();
|
||||
_FAT_mem_init();
|
||||
if ( fs_ntfs_mount ) return 0;
|
||||
//printf("mounting NTFS\n");
|
||||
//Wpad_WaitButtons();
|
||||
_FAT_mem_init();
|
||||
|
||||
ntfsInit(); // Call ntfs init here, to prevent locale resets
|
||||
ntfsInit(); // Call ntfs init here, to prevent locale resets
|
||||
|
||||
// ntfsInit resets locale settings
|
||||
// which breaks unicode in console
|
||||
// so we change it back to C-UTF-8
|
||||
setlocale(LC_CTYPE, "C-UTF-8");
|
||||
setlocale(LC_MESSAGES, "C-UTF-8");
|
||||
// ntfsInit resets locale settings
|
||||
// which breaks unicode in console
|
||||
// so we change it back to C-UTF-8
|
||||
setlocale( LC_CTYPE, "C-UTF-8" );
|
||||
setlocale( LC_MESSAGES, "C-UTF-8" );
|
||||
|
||||
if (wbfsDev == WBFS_DEVICE_USB) {
|
||||
/* Initialize WBFS interface */
|
||||
// if (!__io_wiiums.startup()) {
|
||||
ret = __io_usbstorage2.startup();
|
||||
if (!ret) {
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
/* Mount device */
|
||||
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||
ret = ntfsMount("NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER);
|
||||
if (!ret) {
|
||||
return -2;
|
||||
}
|
||||
// }
|
||||
} else if (wbfsDev == WBFS_DEVICE_SDHC) {
|
||||
if (sdhc_mode_sd == 0) {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER);
|
||||
} else {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER);
|
||||
}
|
||||
if (!ret) {
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
if ( wbfsDev == WBFS_DEVICE_USB )
|
||||
{
|
||||
/* Initialize WBFS interface */
|
||||
// if (!__io_wiiums.startup()) {
|
||||
ret = __io_usbstorage2.startup();
|
||||
if ( !ret )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
/* Mount device */
|
||||
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||
ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
if ( !ret )
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
// }
|
||||
}
|
||||
else if ( wbfsDev == WBFS_DEVICE_SDHC )
|
||||
{
|
||||
if ( sdhc_mode_sd == 0 )
|
||||
{
|
||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
}
|
||||
if ( !ret )
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
fs_ntfs_mount = 1;
|
||||
fs_ntfs_sec = sector; //_FAT_startSector;
|
||||
fs_ntfs_mount = 1;
|
||||
fs_ntfs_sec = sector; //_FAT_startSector;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 UnmountNTFS(void)
|
||||
s32 UnmountNTFS( void )
|
||||
{
|
||||
/* Unmount device */
|
||||
ntfsUnmount("NTFS:/", true);
|
||||
/* Unmount device */
|
||||
ntfsUnmount( "NTFS:/", true );
|
||||
|
||||
fs_ntfs_mount = 0;
|
||||
fs_ntfs_sec = 0;
|
||||
fs_ntfs_mount = 0;
|
||||
fs_ntfs_sec = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _FAT_mem_init()
|
||||
{
|
||||
}
|
||||
|
||||
void* _FAT_mem_allocate(size_t size)
|
||||
void* _FAT_mem_allocate( size_t size )
|
||||
{
|
||||
return malloc(size);
|
||||
return malloc( size );
|
||||
}
|
||||
|
||||
void* _FAT_mem_align(size_t size)
|
||||
void* _FAT_mem_align( size_t size )
|
||||
{
|
||||
return memalign(32, size);
|
||||
return memalign( 32, size );
|
||||
}
|
||||
|
||||
void _FAT_mem_free(void *mem)
|
||||
void _FAT_mem_free( void *mem )
|
||||
{
|
||||
free(mem);
|
||||
free( mem );
|
||||
}
|
||||
|
@ -2,33 +2,34 @@
|
||||
#define _FATMOUNTER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern int fat_sd_mount;
|
||||
extern sec_t fat_sd_sec;
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
extern int fat_sd_mount;
|
||||
extern sec_t fat_sd_sec;
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
|
||||
int USBDevice_Init();
|
||||
void USBDevice_deInit();
|
||||
int WBFSDevice_Init(u32 sector);
|
||||
int WBFSDevice_Init( u32 sector );
|
||||
void WBFSDevice_deInit();
|
||||
int isInserted(const char *path);
|
||||
int isInserted( const char *path );
|
||||
int SDCard_Init();
|
||||
void SDCard_deInit();
|
||||
|
||||
s32 MountNTFS(u32 sector);
|
||||
s32 UnmountNTFS(void);
|
||||
s32 MountNTFS( u32 sector );
|
||||
s32 UnmountNTFS( void );
|
||||
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
extern int fs_ntfs_mount;
|
||||
extern sec_t fs_ntfs_sec;
|
||||
extern int fat_usb_mount;
|
||||
extern sec_t fat_usb_sec;
|
||||
extern int fat_wbfs_mount;
|
||||
extern sec_t fat_wbfs_sec;
|
||||
extern int fs_ntfs_mount;
|
||||
extern sec_t fs_ntfs_sec;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -11,23 +11,23 @@
|
||||
|
||||
#include <gccore.h>
|
||||
|
||||
extern const u8 font_ttf[];
|
||||
extern const u32 font_ttf_size;
|
||||
extern const u8 font_ttf[];
|
||||
extern const u32 font_ttf_size;
|
||||
|
||||
extern const u8 clock_ttf[];
|
||||
extern const u32 clock_ttf_size;
|
||||
extern const u8 clock_ttf[];
|
||||
extern const u32 clock_ttf_size;
|
||||
|
||||
extern const u8 closebutton_png[];
|
||||
extern const u32 closebutton_png_size;
|
||||
extern const u8 closebutton_png[];
|
||||
extern const u32 closebutton_png_size;
|
||||
|
||||
extern const u8 gxlogo_png[];
|
||||
extern const u32 gxlogo_png_size;
|
||||
extern const u8 gxlogo_png[];
|
||||
extern const u32 gxlogo_png_size;
|
||||
|
||||
extern const u8 sdcard_png[];
|
||||
extern const u32 sdcard_png_size;
|
||||
extern const u8 sdcard_png[];
|
||||
extern const u32 sdcard_png_size;
|
||||
|
||||
extern const u8 sdcard_over_png[];
|
||||
extern const u32 sdcard_over_png_size;
|
||||
extern const u8 sdcard_over_png[];
|
||||
extern const u32 sdcard_over_png_size;
|
||||
|
||||
extern const u8 Wifi_btn_png[];
|
||||
extern const u32 Wifi_btn_png_size;
|
||||
@ -35,50 +35,50 @@ extern const u32 Wifi_btn_png_size;
|
||||
extern const u8 Channel_btn_png[];
|
||||
extern const u32 Channel_btn_png_size;
|
||||
|
||||
extern const u8 wiimote_png[];
|
||||
extern const u32 wiimote_png_size;
|
||||
extern const u8 wiimote_png[];
|
||||
extern const u32 wiimote_png_size;
|
||||
|
||||
extern const u8 bg_music_ogg[];
|
||||
extern const u32 bg_music_ogg_size;
|
||||
extern const u8 bg_music_ogg[];
|
||||
extern const u32 bg_music_ogg_size;
|
||||
|
||||
extern const u8 credits_music_ogg[];
|
||||
extern const u32 credits_music_ogg_size;
|
||||
extern const u8 credits_music_ogg[];
|
||||
extern const u32 credits_music_ogg_size;
|
||||
|
||||
extern const u8 gameinfo1_png[];
|
||||
extern const u32 gameinfo1_png_size;
|
||||
extern const u8 gameinfo1_png[];
|
||||
extern const u32 gameinfo1_png_size;
|
||||
|
||||
extern const u8 gameinfo2_png[];
|
||||
extern const u32 gameinfo2_png_size;
|
||||
extern const u8 gameinfo2_png[];
|
||||
extern const u32 gameinfo2_png_size;
|
||||
|
||||
extern const u8 gameinfo1a_png[];
|
||||
extern const u32 gameinfo1a_png_size;
|
||||
extern const u8 gameinfo1a_png[];
|
||||
extern const u32 gameinfo1a_png_size;
|
||||
|
||||
extern const u8 gameinfo2a_png[];
|
||||
extern const u32 gameinfo2a_png_size;
|
||||
extern const u8 gameinfo2a_png[];
|
||||
extern const u32 gameinfo2a_png_size;
|
||||
|
||||
extern const u8 menuin_ogg[];
|
||||
extern const u32 menuin_ogg_size;
|
||||
extern const u8 menuin_ogg[];
|
||||
extern const u32 menuin_ogg_size;
|
||||
|
||||
extern const u8 menuout_ogg[];
|
||||
extern const u32 menuout_ogg_size;
|
||||
extern const u8 menuout_ogg[];
|
||||
extern const u32 menuout_ogg_size;
|
||||
|
||||
extern const u8 success_ogg[];
|
||||
extern const u32 success_ogg_size;
|
||||
extern const u8 success_ogg[];
|
||||
extern const u32 success_ogg_size;
|
||||
|
||||
extern const u8 credits_button_png[];
|
||||
extern const u32 credits_button_png_size;
|
||||
extern const u8 credits_button_png[];
|
||||
extern const u32 credits_button_png_size;
|
||||
|
||||
extern const u8 credits_button_over_png[];
|
||||
extern const u32 credits_button_over_png_size;
|
||||
extern const u8 credits_button_over_png[];
|
||||
extern const u32 credits_button_over_png_size;
|
||||
|
||||
extern const u8 button_over_pcm[];
|
||||
extern const u32 button_over_pcm_size;
|
||||
extern const u8 button_over_pcm[];
|
||||
extern const u32 button_over_pcm_size;
|
||||
|
||||
extern const u8 button_click_pcm[];
|
||||
extern const u32 button_click_pcm_size;
|
||||
extern const u8 button_click_pcm[];
|
||||
extern const u32 button_click_pcm_size;
|
||||
|
||||
extern const u8 button_click2_pcm[];
|
||||
extern const u32 button_click2_pcm_size;
|
||||
extern const u8 button_click2_pcm[];
|
||||
extern const u32 button_click2_pcm_size;
|
||||
|
||||
extern const u8 tooltip_left_png[];
|
||||
extern const u32 tooltip_left_png_size;
|
||||
@ -95,11 +95,11 @@ extern const u32 startgame_arrow_left_png_size;
|
||||
extern const u8 startgame_arrow_right_png[];
|
||||
extern const u32 startgame_arrow_right_png_size;
|
||||
|
||||
extern const u8 credits_bg_png[];
|
||||
extern const u32 credits_bg_png_size;
|
||||
extern const u8 credits_bg_png[];
|
||||
extern const u32 credits_bg_png_size;
|
||||
|
||||
extern const u8 little_star_png[];
|
||||
extern const u32 little_star_png_size;
|
||||
extern const u8 little_star_png[];
|
||||
extern const u32 little_star_png_size;
|
||||
|
||||
extern const u8 background_png[];
|
||||
extern const u32 background_png_size;
|
||||
@ -116,29 +116,29 @@ extern const u32 settings_background_png_size;
|
||||
extern const u8 bg_browser_png[];
|
||||
extern const u32 bg_browser_png_size;
|
||||
|
||||
extern const u8 icon_archives_png[];
|
||||
extern const u32 icon_archives_png_size;
|
||||
extern const u8 icon_archives_png[];
|
||||
extern const u32 icon_archives_png_size;
|
||||
|
||||
//extern const u8 icon_default_png[];
|
||||
//extern const u32 icon_default_png_size;
|
||||
//extern const u8 icon_default_png[];
|
||||
//extern const u32 icon_default_png_size;
|
||||
|
||||
extern const u8 icon_folder_png[];
|
||||
extern const u32 icon_folder_png_size;
|
||||
extern const u8 icon_folder_png[];
|
||||
extern const u32 icon_folder_png_size;
|
||||
/*
|
||||
extern const u8 icon_gfx_png[];
|
||||
extern const u32 icon_gfx_png_size;
|
||||
extern const u8 icon_gfx_png[];
|
||||
extern const u32 icon_gfx_png_size;
|
||||
|
||||
extern const u8 icon_pls_png[];
|
||||
extern const u32 icon_pls_png_size;
|
||||
extern const u8 icon_pls_png[];
|
||||
extern const u32 icon_pls_png_size;
|
||||
|
||||
extern const u8 icon_sfx_png[];
|
||||
extern const u32 icon_sfx_png_size;
|
||||
extern const u8 icon_sfx_png[];
|
||||
extern const u32 icon_sfx_png_size;
|
||||
|
||||
extern const u8 icon_txt_png[];
|
||||
extern const u32 icon_txt_png_size;
|
||||
extern const u8 icon_txt_png[];
|
||||
extern const u32 icon_txt_png_size;
|
||||
|
||||
extern const u8 icon_xml_png[];
|
||||
extern const u32 icon_xml_png_size;
|
||||
extern const u8 icon_xml_png[];
|
||||
extern const u32 icon_xml_png_size;
|
||||
*/
|
||||
extern const u8 bg_browser_selection_png[];
|
||||
extern const u32 bg_browser_selection_png_size;
|
||||
@ -170,380 +170,380 @@ extern const u32 button_install_png_size;
|
||||
extern const u8 button_install_over_png[];
|
||||
extern const u32 button_install_over_png_size;
|
||||
|
||||
extern const u8 dialogue_box_startgame_png[];
|
||||
extern const u32 dialogue_box_startgame_png_size;
|
||||
extern const u8 dialogue_box_startgame_png[];
|
||||
extern const u32 dialogue_box_startgame_png_size;
|
||||
|
||||
extern const u8 wdialogue_box_startgame_png[];
|
||||
extern const u32 wdialogue_box_startgame_png_size;
|
||||
extern const u8 wdialogue_box_startgame_png[];
|
||||
extern const u32 wdialogue_box_startgame_png_size;
|
||||
|
||||
extern const u8 button_dialogue_box_startgame_png[];
|
||||
extern const u32 button_dialogue_box_startgame_size;
|
||||
extern const u8 button_dialogue_box_startgame_png[];
|
||||
extern const u32 button_dialogue_box_startgame_size;
|
||||
|
||||
extern const u8 button_dialogue_box_png[];
|
||||
extern const u32 button_dialogue_box_size;
|
||||
extern const u8 button_dialogue_box_png[];
|
||||
extern const u32 button_dialogue_box_size;
|
||||
|
||||
extern const u8 keyboard_textbox_png[];
|
||||
extern const u32 keyboard_textbox_png_size;
|
||||
extern const u8 keyboard_textbox_png[];
|
||||
extern const u32 keyboard_textbox_png_size;
|
||||
|
||||
extern const u8 keyboard_key_png[];
|
||||
extern const u32 keyboard_key_png_size;
|
||||
extern const u8 keyboard_key_png[];
|
||||
extern const u32 keyboard_key_png_size;
|
||||
|
||||
extern const u8 keyboard_key_over_png[];
|
||||
extern const u32 keyboard_key_over_png_size;
|
||||
extern const u8 keyboard_key_over_png[];
|
||||
extern const u32 keyboard_key_over_png_size;
|
||||
|
||||
extern const u8 keyboard_mediumkey_over_png[];
|
||||
extern const u32 keyboard_mediumkey_over_png_size;
|
||||
extern const u8 keyboard_mediumkey_over_png[];
|
||||
extern const u32 keyboard_mediumkey_over_png_size;
|
||||
|
||||
extern const u8 keyboard_largekey_over_png[];
|
||||
extern const u32 keyboard_largekey_over_png_size;
|
||||
extern const u8 keyboard_largekey_over_png[];
|
||||
extern const u32 keyboard_largekey_over_png_size;
|
||||
|
||||
extern const u8 keyboard_backspace_over_png[];
|
||||
extern const u32 keyboard_backspace_over_png_size;
|
||||
extern const u8 keyboard_backspace_over_png[];
|
||||
extern const u32 keyboard_backspace_over_png_size;
|
||||
|
||||
extern const u8 keyboard_clear_over_png[];
|
||||
extern const u32 keyboard_clear_over_png_size;
|
||||
extern const u8 keyboard_clear_over_png[];
|
||||
extern const u32 keyboard_clear_over_png_size;
|
||||
|
||||
extern const u8 menu_button_png[];
|
||||
extern const u32 menu_button_size;
|
||||
extern const u8 menu_button_png[];
|
||||
extern const u32 menu_button_size;
|
||||
|
||||
extern const u8 menu_button_over_png[];
|
||||
extern const u32 menu_button_over_size;
|
||||
extern const u8 menu_button_over_png[];
|
||||
extern const u32 menu_button_over_size;
|
||||
|
||||
extern const u8 settings_button_png[];
|
||||
extern const u32 settings_button_size;
|
||||
extern const u8 settings_button_png[];
|
||||
extern const u32 settings_button_size;
|
||||
|
||||
extern const u8 settings_button_over_png[];
|
||||
extern const u32 settings_button_over_size;
|
||||
extern const u8 settings_button_over_png[];
|
||||
extern const u32 settings_button_over_size;
|
||||
|
||||
extern const u8 settings_menu_button_png[];
|
||||
extern const u32 settings_menu_button_size;
|
||||
extern const u8 settings_menu_button_png[];
|
||||
extern const u32 settings_menu_button_size;
|
||||
|
||||
extern const u8 wiimote_poweroff_png[];
|
||||
extern const u32 wiimote_poweroff_png_size;
|
||||
extern const u8 wiimote_poweroff_png[];
|
||||
extern const u32 wiimote_poweroff_png_size;
|
||||
|
||||
extern const u8 dialogue_box_png[];
|
||||
extern const u32 dialogue_box_png_size;
|
||||
extern const u8 dialogue_box_png[];
|
||||
extern const u32 dialogue_box_png_size;
|
||||
|
||||
extern const u8 theme_box_png[];
|
||||
extern const u32 theme_box_png_size;
|
||||
extern const u8 theme_box_png[];
|
||||
extern const u32 theme_box_png_size;
|
||||
|
||||
extern const u8 wiimote_poweroff_over_png[];
|
||||
extern const u32 wiimote_poweroff_over_png_size;
|
||||
extern const u8 wiimote_poweroff_over_png[];
|
||||
extern const u32 wiimote_poweroff_over_png_size;
|
||||
|
||||
extern const u8 bg_options_png[];
|
||||
extern const u32 bg_options_png_size;
|
||||
extern const u8 bg_options_png[];
|
||||
extern const u32 bg_options_png_size;
|
||||
|
||||
extern const u8 bg_options_entry_png[];
|
||||
extern const u32 bg_options_entry_png_size;
|
||||
extern const u8 bg_options_entry_png[];
|
||||
extern const u32 bg_options_entry_png_size;
|
||||
|
||||
extern const u8 scrollbar_png[];
|
||||
extern const u32 scrollbar_png_size;
|
||||
extern const u8 scrollbar_png[];
|
||||
extern const u32 scrollbar_png_size;
|
||||
|
||||
extern const u8 scrollbar_arrowup_png[];
|
||||
extern const u32 scrollbar_arrowup_png_size;
|
||||
extern const u8 scrollbar_arrowup_png[];
|
||||
extern const u32 scrollbar_arrowup_png_size;
|
||||
|
||||
extern const u8 scrollbar_arrowup_over_png[];
|
||||
extern const u32 scrollbar_arrowup_over_png_size;
|
||||
extern const u8 scrollbar_arrowup_over_png[];
|
||||
extern const u32 scrollbar_arrowup_over_png_size;
|
||||
|
||||
extern const u8 scrollbar_arrowdown_png[];
|
||||
extern const u32 scrollbar_arrowdown_png_size;
|
||||
extern const u8 scrollbar_arrowdown_png[];
|
||||
extern const u32 scrollbar_arrowdown_png_size;
|
||||
|
||||
extern const u8 scrollbar_arrowdown_over_png[];
|
||||
extern const u32 scrollbar_arrowdown_over_png_size;
|
||||
extern const u8 scrollbar_arrowdown_over_png[];
|
||||
extern const u32 scrollbar_arrowdown_over_png_size;
|
||||
|
||||
extern const u8 scrollbar_box_png[];
|
||||
extern const u32 scrollbar_box_png_size;
|
||||
extern const u8 scrollbar_box_png[];
|
||||
extern const u32 scrollbar_box_png_size;
|
||||
|
||||
extern const u8 scrollbar_box_over_png[];
|
||||
extern const u32 scrollbar_box_over_png_size;
|
||||
extern const u8 scrollbar_box_over_png[];
|
||||
extern const u32 scrollbar_box_over_png_size;
|
||||
|
||||
extern const u8 progressbar_png[];
|
||||
extern const u32 progressbar_png_size;
|
||||
extern const u8 progressbar_png[];
|
||||
extern const u32 progressbar_png_size;
|
||||
|
||||
extern const u8 progressbar_empty_png[];
|
||||
extern const u32 progressbar_empty_png_size;
|
||||
extern const u8 progressbar_empty_png[];
|
||||
extern const u32 progressbar_empty_png_size;
|
||||
|
||||
extern const u8 progressbar_outline_png[];
|
||||
extern const u32 progressbar_outline_png_size;
|
||||
extern const u8 progressbar_outline_png[];
|
||||
extern const u32 progressbar_outline_png_size;
|
||||
|
||||
extern const u8 player1_point_png[];
|
||||
extern const u32 player1_point_png_size;
|
||||
extern const u8 player1_point_png[];
|
||||
extern const u32 player1_point_png_size;
|
||||
|
||||
extern const u8 player2_point_png[];
|
||||
extern const u32 player2_point_png_size;
|
||||
extern const u8 player2_point_png[];
|
||||
extern const u32 player2_point_png_size;
|
||||
|
||||
extern const u8 player3_point_png[];
|
||||
extern const u32 player3_point_png_size;
|
||||
extern const u8 player3_point_png[];
|
||||
extern const u32 player3_point_png_size;
|
||||
|
||||
extern const u8 player4_point_png[];
|
||||
extern const u32 player4_point_png_size;
|
||||
extern const u8 player4_point_png[];
|
||||
extern const u32 player4_point_png_size;
|
||||
|
||||
extern const u8 rplayer1_point_png[];
|
||||
extern const u32 rplayer1_point_png_size;
|
||||
extern const u8 rplayer1_point_png[];
|
||||
extern const u32 rplayer1_point_png_size;
|
||||
|
||||
extern const u8 rplayer2_point_png[];
|
||||
extern const u32 rplayer2_point_png_size;
|
||||
extern const u8 rplayer2_point_png[];
|
||||
extern const u32 rplayer2_point_png_size;
|
||||
|
||||
extern const u8 rplayer3_point_png[];
|
||||
extern const u32 rplayer3_point_png_size;
|
||||
extern const u8 rplayer3_point_png[];
|
||||
extern const u32 rplayer3_point_png_size;
|
||||
|
||||
extern const u8 rplayer4_point_png[];
|
||||
extern const u32 rplayer4_point_png_size;
|
||||
extern const u8 rplayer4_point_png[];
|
||||
extern const u32 rplayer4_point_png_size;
|
||||
|
||||
extern const u8 battery_png[];
|
||||
extern const u32 battery_png_size;
|
||||
extern const u8 battery_png[];
|
||||
extern const u32 battery_png_size;
|
||||
|
||||
extern const u8 battery_bar_png[];
|
||||
extern const u32 battery_bar_png_size;
|
||||
extern const u8 battery_bar_png[];
|
||||
extern const u32 battery_bar_png_size;
|
||||
|
||||
extern const u8 battery_white_png[];
|
||||
extern const u32 battery_white_png_size;
|
||||
extern const u8 battery_white_png[];
|
||||
extern const u32 battery_white_png_size;
|
||||
|
||||
extern const u8 battery_bar_white_png[];
|
||||
extern const u32 battery_bar_white_png_size;
|
||||
extern const u8 battery_bar_white_png[];
|
||||
extern const u32 battery_bar_white_png_size;
|
||||
|
||||
extern const u8 battery_red_png[];
|
||||
extern const u32 battery_red_png_size;
|
||||
extern const u8 battery_red_png[];
|
||||
extern const u32 battery_red_png_size;
|
||||
|
||||
extern const u8 battery_bar_red_png[];
|
||||
extern const u32 battery_bar_red_png_size;
|
||||
extern const u8 battery_bar_red_png[];
|
||||
extern const u32 battery_bar_red_png_size;
|
||||
|
||||
extern const u8 arrow_next_png[];
|
||||
extern const u32 arrow_next_png_size;
|
||||
extern const u8 arrow_next_png[];
|
||||
extern const u32 arrow_next_png_size;
|
||||
|
||||
extern const u8 arrow_previous_png[];
|
||||
extern const u32 arrow_previous_png_size;
|
||||
extern const u8 arrow_previous_png[];
|
||||
extern const u32 arrow_previous_png_size;
|
||||
|
||||
extern const u8 mp3_pause_png[];
|
||||
extern const u32 mp3_pause_png_size;
|
||||
extern const u8 mp3_pause_png[];
|
||||
extern const u32 mp3_pause_png_size;
|
||||
|
||||
extern const u8 exit_top_png[];
|
||||
extern const u32 exit_top_png_size;
|
||||
extern const u8 exit_top_png[];
|
||||
extern const u32 exit_top_png_size;
|
||||
|
||||
extern const u8 exit_top_over_png[];
|
||||
extern const u32 exit_top_over_png_size;
|
||||
extern const u8 exit_top_over_png[];
|
||||
extern const u32 exit_top_over_png_size;
|
||||
|
||||
extern const u8 exit_bottom_png[];
|
||||
extern const u32 exit_bottom_png_size;
|
||||
extern const u8 exit_bottom_png[];
|
||||
extern const u32 exit_bottom_png_size;
|
||||
|
||||
extern const u8 exit_bottom_over_png[];
|
||||
extern const u32 exit_bottom_over_png_size;
|
||||
extern const u8 exit_bottom_over_png[];
|
||||
extern const u32 exit_bottom_over_png_size;
|
||||
|
||||
extern const u8 exit_button_png[];
|
||||
extern const u32 exit_button_png_size;
|
||||
extern const u8 exit_button_png[];
|
||||
extern const u32 exit_button_png_size;
|
||||
|
||||
extern const u8 mp3_stop_png[];
|
||||
extern const u32 mp3_stop_png_size;
|
||||
extern const u8 mp3_stop_png[];
|
||||
extern const u32 mp3_stop_png_size;
|
||||
|
||||
extern const u8 favorite_png[];
|
||||
extern const u32 favorite_png_size;
|
||||
extern const u8 favorite_png[];
|
||||
extern const u32 favorite_png_size;
|
||||
|
||||
extern const u8 not_favorite_png[];
|
||||
extern const u32 not_favorite_png_size;
|
||||
extern const u8 not_favorite_png[];
|
||||
extern const u32 not_favorite_png_size;
|
||||
|
||||
extern const u8 favIcon_png[];
|
||||
extern const u32 favIcon_png_size;
|
||||
extern const u8 favIcon_png[];
|
||||
extern const u32 favIcon_png_size;
|
||||
|
||||
extern const u8 searchIcon_png[];
|
||||
extern const u32 searchIcon_png_size;
|
||||
extern const u8 searchIcon_png[];
|
||||
extern const u32 searchIcon_png_size;
|
||||
|
||||
extern const u8 abcIcon_png[];
|
||||
extern const u32 abcIcon_png_size;
|
||||
extern const u8 abcIcon_png[];
|
||||
extern const u32 abcIcon_png_size;
|
||||
|
||||
extern const u8 rankIcon_png[];
|
||||
extern const u32 rankIcon_png_size;
|
||||
extern const u8 rankIcon_png[];
|
||||
extern const u32 rankIcon_png_size;
|
||||
|
||||
extern const u8 playCountIcon_png[];
|
||||
extern const u32 playCountIcon_png_size;
|
||||
extern const u8 playCountIcon_png[];
|
||||
extern const u32 playCountIcon_png_size;
|
||||
|
||||
extern const u8 arrangeList_png[];
|
||||
extern const u32 arrangeList_png_size;
|
||||
extern const u8 arrangeList_png[];
|
||||
extern const u32 arrangeList_png_size;
|
||||
|
||||
extern const u8 arrangeGrid_png[];
|
||||
extern const u32 arrangeGrid_png_size;
|
||||
extern const u8 arrangeGrid_png[];
|
||||
extern const u32 arrangeGrid_png_size;
|
||||
|
||||
extern const u8 arrangeCarousel_png[];
|
||||
extern const u32 arrangeCarousel_png_size;
|
||||
extern const u8 arrangeCarousel_png[];
|
||||
extern const u32 arrangeCarousel_png_size;
|
||||
|
||||
extern const u8 settings_title_png[];
|
||||
extern const u32 settings_title_png_size;
|
||||
extern const u8 settings_title_png[];
|
||||
extern const u32 settings_title_png_size;
|
||||
|
||||
extern const u8 settings_title_over_png[];
|
||||
extern const u32 settings_title_over_png_size;
|
||||
extern const u8 settings_title_over_png[];
|
||||
extern const u32 settings_title_over_png_size;
|
||||
|
||||
extern const u8 pageindicator_png[];
|
||||
extern const u32 pageindicator_png_size;
|
||||
extern const u8 pageindicator_png[];
|
||||
extern const u32 pageindicator_png_size;
|
||||
|
||||
extern const u8 Wiimote1_png[];
|
||||
extern const u32 Wiimote1_png_size;
|
||||
extern const u8 Wiimote1_png[];
|
||||
extern const u32 Wiimote1_png_size;
|
||||
|
||||
extern const u8 Wiimote2_png[];
|
||||
extern const u32 Wiimote2_png_size;
|
||||
extern const u8 Wiimote2_png[];
|
||||
extern const u32 Wiimote2_png_size;
|
||||
|
||||
extern const u8 Wiimote4_png[];
|
||||
extern const u32 Wiimote4_png_size;
|
||||
extern const u8 Wiimote4_png[];
|
||||
extern const u32 Wiimote4_png_size;
|
||||
|
||||
extern const u8 wifi1_png[];
|
||||
extern const u32 wifi1_png_size;
|
||||
extern const u8 wifi1_png[];
|
||||
extern const u32 wifi1_png_size;
|
||||
|
||||
extern const u8 wifi2_png[];
|
||||
extern const u32 wifi2png_size;
|
||||
extern const u8 wifi2_png[];
|
||||
extern const u32 wifi2png_size;
|
||||
|
||||
extern const u8 wifi3_png[];
|
||||
extern const u32 wifi3_png_size;
|
||||
extern const u8 wifi3_png[];
|
||||
extern const u32 wifi3_png_size;
|
||||
|
||||
extern const u8 wifi4_png[];
|
||||
extern const u32 wifi4_png_size;
|
||||
extern const u8 wifi4_png[];
|
||||
extern const u32 wifi4_png_size;
|
||||
|
||||
//extern const u8 wifi6_png[];
|
||||
//extern const u32 wifi6_png_size;
|
||||
//extern const u8 wifi6_png[];
|
||||
//extern const u32 wifi6_png_size;
|
||||
|
||||
extern const u8 wifi8_png[];
|
||||
extern const u32 wifi8_png_size;
|
||||
extern const u8 wifi8_png[];
|
||||
extern const u32 wifi8_png_size;
|
||||
|
||||
extern const u8 wifi12_png[];
|
||||
extern const u32 wifi12_png_size;
|
||||
extern const u8 wifi12_png[];
|
||||
extern const u32 wifi12_png_size;
|
||||
|
||||
extern const u8 wifi16_png[];
|
||||
extern const u32 wifi16_png_size;
|
||||
extern const u8 wifi16_png[];
|
||||
extern const u32 wifi16_png_size;
|
||||
|
||||
extern const u8 wifi32_png[];
|
||||
extern const u32 wifi32_png_size;
|
||||
extern const u8 wifi32_png[];
|
||||
extern const u32 wifi32_png_size;
|
||||
|
||||
extern const u8 norating_png[];
|
||||
extern const u32 norating_png_size;
|
||||
extern const u8 norating_png[];
|
||||
extern const u32 norating_png_size;
|
||||
|
||||
extern const u8 guitar_png[];
|
||||
extern const u32 guitar_png_size;
|
||||
extern const u8 guitarR_png[];
|
||||
extern const u32 guitarR_png_size;
|
||||
extern const u8 guitar_png[];
|
||||
extern const u32 guitar_png_size;
|
||||
extern const u8 guitarR_png[];
|
||||
extern const u32 guitarR_png_size;
|
||||
|
||||
extern const u8 microphone_png[];
|
||||
extern const u32 microphone_png_size;
|
||||
extern const u8 microphoneR_png[];
|
||||
extern const u32 microphoneR_png_size;
|
||||
extern const u8 microphone_png[];
|
||||
extern const u32 microphone_png_size;
|
||||
extern const u8 microphoneR_png[];
|
||||
extern const u32 microphoneR_png_size;
|
||||
|
||||
extern const u8 gcncontroller_png[];
|
||||
extern const u32 gcncontroller_png_size;
|
||||
extern const u8 gcncontrollerR_png[];
|
||||
extern const u32 gcncontrollerR_png_size;
|
||||
extern const u8 gcncontroller_png[];
|
||||
extern const u32 gcncontroller_png_size;
|
||||
extern const u8 gcncontrollerR_png[];
|
||||
extern const u32 gcncontrollerR_png_size;
|
||||
|
||||
extern const u8 classiccontroller_png[];
|
||||
extern const u32 classiccontroller_png_size;
|
||||
extern const u8 classiccontrollerR_png[];
|
||||
extern const u32 classiccontrollerR_png_size;
|
||||
extern const u8 classiccontroller_png[];
|
||||
extern const u32 classiccontroller_png_size;
|
||||
extern const u8 classiccontrollerR_png[];
|
||||
extern const u32 classiccontrollerR_png_size;
|
||||
|
||||
extern const u8 nunchuk_png[];
|
||||
extern const u32 nunchuk_png_size;
|
||||
extern const u8 nunchukR_png[];
|
||||
extern const u32 nunchukR_png_size;
|
||||
extern const u8 nunchuk_png[];
|
||||
extern const u32 nunchuk_png_size;
|
||||
extern const u8 nunchukR_png[];
|
||||
extern const u32 nunchukR_png_size;
|
||||
|
||||
extern const u8 dancepadR_png[];
|
||||
extern const u32 dancepadR_size;
|
||||
extern const u8 dancepad_png[];
|
||||
extern const u32 dancepad_png_size;
|
||||
extern const u8 dancepadR_png[];
|
||||
extern const u32 dancepadR_size;
|
||||
extern const u8 dancepad_png[];
|
||||
extern const u32 dancepad_png_size;
|
||||
|
||||
extern const u8 balanceboard_png[];
|
||||
extern const u32 balanceboard_png_size;
|
||||
extern const u8 balanceboardR_png[];
|
||||
extern const u32 balanceboardR_png_size;
|
||||
extern const u8 balanceboard_png[];
|
||||
extern const u32 balanceboard_png_size;
|
||||
extern const u8 balanceboardR_png[];
|
||||
extern const u32 balanceboardR_png_size;
|
||||
|
||||
extern const u8 drums_png[];
|
||||
extern const u32 drums_png_size;
|
||||
extern const u8 drumsR_png[];
|
||||
extern const u32 drumsR_png_size;
|
||||
extern const u8 drums_png[];
|
||||
extern const u32 drums_png_size;
|
||||
extern const u8 drumsR_png[];
|
||||
extern const u32 drumsR_png_size;
|
||||
|
||||
extern const u8 motionplus_png[];
|
||||
extern const u32 motionplus_png_size;
|
||||
extern const u8 motionplusR_png[];
|
||||
extern const u32 motionplusR_png_size;
|
||||
extern const u8 motionplus_png[];
|
||||
extern const u32 motionplus_png_size;
|
||||
extern const u8 motionplusR_png[];
|
||||
extern const u32 motionplusR_png_size;
|
||||
|
||||
extern const u8 wheel_png[];
|
||||
extern const u32 wheel_png_size;
|
||||
extern const u8 wheelR_png[];
|
||||
extern const u32 wheelR_png_size;
|
||||
extern const u8 wheel_png[];
|
||||
extern const u32 wheel_png_size;
|
||||
extern const u8 wheelR_png[];
|
||||
extern const u32 wheelR_png_size;
|
||||
|
||||
extern const u8 zapper_png[];
|
||||
extern const u32 zapper_png_size;
|
||||
extern const u8 zapperR_png[];
|
||||
extern const u32 zapperR_png_size;
|
||||
extern const u8 zapper_png[];
|
||||
extern const u32 zapper_png_size;
|
||||
extern const u8 zapperR_png[];
|
||||
extern const u32 zapperR_png_size;
|
||||
|
||||
extern const u8 wiispeak_png[];
|
||||
extern const u32 wiispeak_png_size;
|
||||
extern const u8 wiispeakR_png[];
|
||||
extern const u32 wiispeakR_png_size;
|
||||
extern const u8 wiispeak_png[];
|
||||
extern const u32 wiispeak_png_size;
|
||||
extern const u8 wiispeakR_png[];
|
||||
extern const u32 wiispeakR_png_size;
|
||||
|
||||
extern const u8 nintendods_png[];
|
||||
extern const u32 nintendods_png_size;
|
||||
extern const u8 nintendodsR_png[];
|
||||
extern const u32 nintendodsR_png_size;
|
||||
extern const u8 nintendods_png[];
|
||||
extern const u32 nintendods_png_size;
|
||||
extern const u8 nintendodsR_png[];
|
||||
extern const u32 nintendodsR_png_size;
|
||||
/*
|
||||
extern const u8 vitalitysensor_png[];
|
||||
extern const u32 vitalitysensor_png_size;
|
||||
extern const u8 vitalitysensor_png[];
|
||||
extern const u32 vitalitysensorR_png_size;
|
||||
extern const u8 vitalitysensor_png[];
|
||||
extern const u32 vitalitysensor_png_size;
|
||||
extern const u8 vitalitysensor_png[];
|
||||
extern const u32 vitalitysensorR_png_size;
|
||||
*/
|
||||
extern const u8 esrb_ec_png[];
|
||||
extern const u32 esrb_ec_png_size;
|
||||
extern const u8 esrb_ec_png[];
|
||||
extern const u32 esrb_ec_png_size;
|
||||
|
||||
extern const u8 esrb_e_png[];
|
||||
extern const u32 esrb_e_png_size;
|
||||
extern const u8 esrb_e_png[];
|
||||
extern const u32 esrb_e_png_size;
|
||||
|
||||
extern const u8 esrb_eten_png[];
|
||||
extern const u32 esrb_eten_png_size;
|
||||
extern const u8 esrb_eten_png[];
|
||||
extern const u32 esrb_eten_png_size;
|
||||
|
||||
extern const u8 esrb_t_png[];
|
||||
extern const u32 esrb_t_png_size;
|
||||
extern const u8 esrb_t_png[];
|
||||
extern const u32 esrb_t_png_size;
|
||||
|
||||
extern const u8 esrb_m_png[];
|
||||
extern const u32 esrb_m_png_size;
|
||||
extern const u8 esrb_m_png[];
|
||||
extern const u32 esrb_m_png_size;
|
||||
|
||||
extern const u8 esrb_ao_png[];
|
||||
extern const u32 esrb_ao_png_size;
|
||||
extern const u8 esrb_ao_png[];
|
||||
extern const u32 esrb_ao_png_size;
|
||||
|
||||
extern const u8 cero_a_png[];
|
||||
extern const u32 cero_a_png_size;
|
||||
extern const u8 cero_a_png[];
|
||||
extern const u32 cero_a_png_size;
|
||||
|
||||
extern const u8 cero_b_png[];
|
||||
extern const u32 cero_b_png_size;
|
||||
extern const u8 cero_b_png[];
|
||||
extern const u32 cero_b_png_size;
|
||||
|
||||
extern const u8 cero_c_png[];
|
||||
extern const u32 cero_c_png_size;
|
||||
extern const u8 cero_c_png[];
|
||||
extern const u32 cero_c_png_size;
|
||||
|
||||
extern const u8 cero_d_png[];
|
||||
extern const u32 cero_d_png_size;
|
||||
extern const u8 cero_d_png[];
|
||||
extern const u32 cero_d_png_size;
|
||||
|
||||
extern const u8 cero_z_png[];
|
||||
extern const u32 cero_z_png_size;
|
||||
extern const u8 cero_z_png[];
|
||||
extern const u32 cero_z_png_size;
|
||||
|
||||
extern const u8 pegi_3_png[];
|
||||
extern const u32 pegi_3_png_size;
|
||||
extern const u8 pegi_3_png[];
|
||||
extern const u32 pegi_3_png_size;
|
||||
|
||||
extern const u8 pegi_7_png[];
|
||||
extern const u32 pegi_7_png_size;
|
||||
extern const u8 pegi_7_png[];
|
||||
extern const u32 pegi_7_png_size;
|
||||
|
||||
extern const u8 pegi_12_png[];
|
||||
extern const u32 pegi_12_png_size;
|
||||
extern const u8 pegi_12_png[];
|
||||
extern const u32 pegi_12_png_size;
|
||||
|
||||
extern const u8 pegi_16_png[];
|
||||
extern const u32 pegi_16_png_size;
|
||||
extern const u8 pegi_16_png[];
|
||||
extern const u32 pegi_16_png_size;
|
||||
|
||||
extern const u8 pegi_18_png[];
|
||||
extern const u32 pegi_18_png_size;
|
||||
extern const u8 pegi_18_png[];
|
||||
extern const u32 pegi_18_png_size;
|
||||
|
||||
extern const u8 usbport_png[];
|
||||
extern const u32 usbport_png_size;
|
||||
extern const u8 usbport_png[];
|
||||
extern const u32 usbport_png_size;
|
||||
|
||||
extern const u8 dvd_png[];
|
||||
extern const u32 dvd_png_size;
|
||||
extern const u8 dvd_png[];
|
||||
extern const u32 dvd_png_size;
|
||||
|
||||
extern const u8 new_png[];
|
||||
extern const u32 new_png_size;
|
||||
extern const u32 new_png_size;
|
||||
|
||||
extern const u8 lock_png[];
|
||||
extern const u32 lock_png_size;
|
||||
extern const u8 lock_png[];
|
||||
extern const u32 lock_png_size;
|
||||
|
||||
extern const u8 unlock_png[];
|
||||
extern const u32 unlock_png_size;
|
||||
extern const u8 unlock_png[];
|
||||
extern const u32 unlock_png_size;
|
||||
|
||||
#endif
|
||||
|
@ -12,67 +12,67 @@ bool textVideoInit = false;
|
||||
//using the gprintf from crediar because it is smaller than mine
|
||||
void gprintf( const char *str, ... )
|
||||
{
|
||||
if (!(geckoinit))return;
|
||||
if ( !( geckoinit ) )return;
|
||||
|
||||
char astr[4096];
|
||||
char astr[4096];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap,str);
|
||||
va_list ap;
|
||||
va_start( ap, str );
|
||||
|
||||
vsprintf( astr, str, ap );
|
||||
vsprintf( astr, str, ap );
|
||||
|
||||
va_end(ap);
|
||||
va_end( ap );
|
||||
|
||||
usb_sendbuffer( 1, astr, strlen(astr) );
|
||||
//usb_sendbuffer_safe( 1, astr, strlen(astr) );
|
||||
usb_sendbuffer( 1, astr, strlen( astr ) );
|
||||
//usb_sendbuffer_safe( 1, astr, strlen(astr) );
|
||||
}
|
||||
|
||||
bool InitGecko()
|
||||
{
|
||||
u32 geckoattached = usb_isgeckoalive(EXI_CHANNEL_1);
|
||||
if (geckoattached)
|
||||
{
|
||||
usb_flush(EXI_CHANNEL_1);
|
||||
CON_EnableGecko( 1, true );
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
u32 geckoattached = usb_isgeckoalive( EXI_CHANNEL_1 );
|
||||
if ( geckoattached )
|
||||
{
|
||||
usb_flush( EXI_CHANNEL_1 );
|
||||
CON_EnableGecko( 1, true );
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
char ascii(char s)
|
||||
char ascii( char s )
|
||||
{
|
||||
if(s < 0x20)
|
||||
return '.';
|
||||
if(s > 0x7E)
|
||||
return '.';
|
||||
if ( s < 0x20 )
|
||||
return '.';
|
||||
if ( s > 0x7E )
|
||||
return '.';
|
||||
return s;
|
||||
}
|
||||
|
||||
void hexdump(void *d, int len)
|
||||
void hexdump( void *d, int len )
|
||||
{
|
||||
u8 *data;
|
||||
int i, off;
|
||||
data = (u8*)d;
|
||||
data = ( u8* )d;
|
||||
|
||||
gprintf("\n 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF");
|
||||
gprintf("\n==== =============================================== ================\n");
|
||||
gprintf( "\n 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF" );
|
||||
gprintf( "\n==== =============================================== ================\n" );
|
||||
|
||||
for (off=0; off<len; off += 16)
|
||||
for ( off = 0; off < len; off += 16 )
|
||||
{
|
||||
gprintf("%04x ",off);
|
||||
for(i=0; i<16; i++)
|
||||
if((i+off)>=len)
|
||||
gprintf(" ");
|
||||
else
|
||||
gprintf("%02x ",data[off+i]);
|
||||
gprintf( "%04x ", off );
|
||||
for ( i = 0; i < 16; i++ )
|
||||
if ( ( i + off ) >= len )
|
||||
gprintf( " " );
|
||||
else
|
||||
gprintf( "%02x ", data[off+i] );
|
||||
|
||||
gprintf(" ");
|
||||
for(i=0; i<16; i++)
|
||||
if((i+off)>=len)
|
||||
gprintf(" ");
|
||||
else
|
||||
gprintf("%c",ascii(data[off+i]));
|
||||
gprintf("\n");
|
||||
gprintf( " " );
|
||||
for ( i = 0; i < 16; i++ )
|
||||
if ( ( i + off ) >= len )
|
||||
gprintf( " " );
|
||||
else
|
||||
gprintf( "%c", ascii( data[off+i] ) );
|
||||
gprintf( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,20 +4,21 @@
|
||||
#define _GECKO_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
char ascii(char s);
|
||||
char ascii( char s );
|
||||
|
||||
#ifndef NO_DEBUG
|
||||
//use this just like printf();
|
||||
void gprintf(const char *str, ...);
|
||||
bool InitGecko();
|
||||
void hexdump(void *d, int len);
|
||||
//use this just like printf();
|
||||
void gprintf( const char *str, ... );
|
||||
bool InitGecko();
|
||||
void hexdump( void *d, int len );
|
||||
#else
|
||||
#define gprintf(...)
|
||||
#define InitGecko() false
|
||||
#define hexdump( x, y )
|
||||
#define gprintf(...)
|
||||
#define InitGecko() false
|
||||
#define hexdump( x, y )
|
||||
#endif /* NO_DEBUG */
|
||||
|
||||
|
||||
|
@ -14,62 +14,62 @@
|
||||
#include "fatmounter.h"
|
||||
#include "sys.h"
|
||||
|
||||
extern const u8 app_booter_dol[];
|
||||
extern const u8 app_booter_dol[];
|
||||
extern const u32 app_booter_dol_size;
|
||||
|
||||
static u8 *homebrewbuffer = (u8 *) 0x92000000;
|
||||
static u8 *homebrewbuffer = ( u8 * ) 0x92000000;
|
||||
static int homebrewsize = 0;
|
||||
static std::vector<std::string> Arguments;
|
||||
|
||||
void AddBootArgument(const char * argv)
|
||||
void AddBootArgument( const char * argv )
|
||||
{
|
||||
std::string arg(argv);
|
||||
Arguments.push_back(arg);
|
||||
std::string arg( argv );
|
||||
Arguments.push_back( arg );
|
||||
}
|
||||
|
||||
int CopyHomebrewMemory(u8 *temp, u32 pos, u32 len)
|
||||
int CopyHomebrewMemory( u8 *temp, u32 pos, u32 len )
|
||||
{
|
||||
homebrewsize += len;
|
||||
memcpy((homebrewbuffer)+pos, temp, len);
|
||||
memcpy( ( homebrewbuffer ) + pos, temp, len );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void FreeHomebrewBuffer()
|
||||
{
|
||||
homebrewbuffer = (u8 *)0x92000000;
|
||||
homebrewbuffer = ( u8 * )0x92000000;
|
||||
homebrewsize = 0;
|
||||
}
|
||||
|
||||
static int SetupARGV(struct __argv * args)
|
||||
static int SetupARGV( struct __argv * args )
|
||||
{
|
||||
if(!args)
|
||||
if ( !args )
|
||||
return -1;
|
||||
|
||||
bzero(args, sizeof(struct __argv));
|
||||
bzero( args, sizeof( struct __argv ) );
|
||||
args->argvMagic = ARGV_MAGIC;
|
||||
|
||||
u32 stringlength = 1;
|
||||
|
||||
/** Append Arguments **/
|
||||
for(u32 i = 0; i < Arguments.size(); i++)
|
||||
for ( u32 i = 0; i < Arguments.size(); i++ )
|
||||
{
|
||||
stringlength += Arguments[i].size()+1;
|
||||
stringlength += Arguments[i].size() + 1;
|
||||
}
|
||||
|
||||
args->length = stringlength;
|
||||
args->commandLine = (char*) malloc(args->length);
|
||||
if (!args->commandLine)
|
||||
args->commandLine = ( char* ) malloc( args->length );
|
||||
if ( !args->commandLine )
|
||||
return -1;
|
||||
|
||||
u32 argc = 0;
|
||||
u32 position = 0;
|
||||
|
||||
/** Append Arguments **/
|
||||
for(u32 i = 0; i < Arguments.size(); i++)
|
||||
for ( u32 i = 0; i < Arguments.size(); i++ )
|
||||
{
|
||||
strcpy(&args->commandLine[position], Arguments[i].c_str());
|
||||
position += Arguments[i].size()+1;
|
||||
strcpy( &args->commandLine[position], Arguments[i].c_str() );
|
||||
position += Arguments[i].size() + 1;
|
||||
argc++;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ static int SetupARGV(struct __argv * args)
|
||||
|
||||
int BootHomebrew()
|
||||
{
|
||||
if(homebrewsize <= 0)
|
||||
if ( homebrewsize <= 0 )
|
||||
Sys_BackToLoader();
|
||||
|
||||
SDCard_deInit();
|
||||
@ -94,43 +94,43 @@ int BootHomebrew()
|
||||
USBStorage2_Deinit();
|
||||
|
||||
struct __argv args;
|
||||
SetupARGV(&args);
|
||||
SetupARGV( &args );
|
||||
|
||||
u32 cpu_isr;
|
||||
|
||||
entrypoint entry = (entrypoint) load_dol(app_booter_dol, &args);
|
||||
entrypoint entry = ( entrypoint ) load_dol( app_booter_dol, &args );
|
||||
|
||||
if (!entry)
|
||||
if ( !entry )
|
||||
Sys_BackToLoader();
|
||||
|
||||
VIDEO_SetBlack(true);
|
||||
VIDEO_SetBlack( true );
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
|
||||
SYS_ResetSystem(SYS_SHUTDOWN, 0, 0);
|
||||
_CPU_ISR_Disable (cpu_isr);
|
||||
SYS_ResetSystem( SYS_SHUTDOWN, 0, 0 );
|
||||
_CPU_ISR_Disable ( cpu_isr );
|
||||
__exception_closeall();
|
||||
entry();
|
||||
_CPU_ISR_Restore (cpu_isr);
|
||||
_CPU_ISR_Restore ( cpu_isr );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BootHomebrew(const char * filepath)
|
||||
int BootHomebrew( const char * filepath )
|
||||
{
|
||||
FILE * file = fopen(filepath, "rb");
|
||||
if(!file)
|
||||
FILE * file = fopen( filepath, "rb" );
|
||||
if ( !file )
|
||||
Sys_BackToLoader();
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
fseek( file, 0, SEEK_END );
|
||||
|
||||
int size = ftell(file);
|
||||
rewind(file);
|
||||
int size = ftell( file );
|
||||
rewind( file );
|
||||
|
||||
homebrewsize = fread(homebrewbuffer, 1, size, file);
|
||||
fclose(file);
|
||||
homebrewsize = fread( homebrewbuffer, 1, size, file );
|
||||
fclose( file );
|
||||
|
||||
AddBootArgument(filepath);
|
||||
AddBootArgument( filepath );
|
||||
|
||||
return BootHomebrew();
|
||||
}
|
||||
@ -155,11 +155,11 @@ int BootHomebrew(const char * filepath)
|
||||
|
||||
|
||||
void *innetbuffer = NULL;
|
||||
static u8 *homebrewbuffer =( u8 * )0x92000000;
|
||||
static u8 *homebrewbuffer = ( u8 * )0x92000000;
|
||||
u32 homebrewsize = 0;
|
||||
static std::vector<std::string> Arguments;
|
||||
|
||||
extern const u8 app_booter_dol[];
|
||||
extern const u8 app_booter_dol[];
|
||||
|
||||
int AllocHomebrewMemory( u32 filesize )
|
||||
{
|
||||
@ -167,7 +167,7 @@ int AllocHomebrewMemory( u32 filesize )
|
||||
innetbuffer = malloc( filesize );
|
||||
|
||||
if ( !innetbuffer )
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
homebrewsize = filesize;
|
||||
return 1;
|
||||
@ -182,7 +182,7 @@ void AddBootArgument( const char * argv )
|
||||
int CopyHomebrewMemory( u8 *temp, u32 pos, u32 len )
|
||||
{
|
||||
homebrewsize += len;
|
||||
memcpy(( homebrewbuffer ) + pos, temp, len );
|
||||
memcpy( ( homebrewbuffer ) + pos, temp, len );
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -194,8 +194,8 @@ void FreeHomebrewBuffer()
|
||||
|
||||
if ( innetbuffer )
|
||||
{
|
||||
free( innetbuffer );
|
||||
innetbuffer = NULL;
|
||||
free( innetbuffer );
|
||||
innetbuffer = NULL;
|
||||
}
|
||||
|
||||
Arguments.clear();
|
||||
@ -204,7 +204,7 @@ void FreeHomebrewBuffer()
|
||||
static int SetupARGV( struct __argv * args )
|
||||
{
|
||||
if ( !args )
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
bzero( args, sizeof( struct __argv ) );
|
||||
args->argvMagic = ARGV_MAGIC;
|
||||
@ -214,14 +214,14 @@ static int SetupARGV( struct __argv * args )
|
||||
/** Append Arguments **/
|
||||
for ( u32 i = 0; i < Arguments.size(); i++ )
|
||||
{
|
||||
stringlength += Arguments[i].size() + 1;
|
||||
stringlength += Arguments[i].size() + 1;
|
||||
}
|
||||
|
||||
args->length = stringlength;
|
||||
args->commandLine = ( char* ) malloc( args->length );
|
||||
|
||||
if ( !args->commandLine )
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
u32 argc = 0;
|
||||
u32 position = 0;
|
||||
@ -229,9 +229,9 @@ static int SetupARGV( struct __argv * args )
|
||||
/** Append Arguments **/
|
||||
for ( u32 i = 0; i < Arguments.size(); i++ )
|
||||
{
|
||||
strcpy( &args->commandLine[position], Arguments[i].c_str() );
|
||||
position += Arguments[i].size() + 1;
|
||||
argc++;
|
||||
strcpy( &args->commandLine[position], Arguments[i].c_str() );
|
||||
position += Arguments[i].size() + 1;
|
||||
argc++;
|
||||
}
|
||||
|
||||
args->argc = argc;
|
||||
@ -248,19 +248,19 @@ static int SetupARGV( struct __argv * args )
|
||||
static int RunAppbooter()
|
||||
{
|
||||
if ( homebrewsize == 0 )
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
struct __argv args;
|
||||
SetupARGV( &args );
|
||||
|
||||
u32 cpu_isr;
|
||||
|
||||
entrypoint entry = ( entrypoint ) load_dol(( void* ) app_booter_dol, &args );
|
||||
entrypoint entry = ( entrypoint ) load_dol( ( void* ) app_booter_dol, &args );
|
||||
|
||||
if ( !entry )
|
||||
{
|
||||
FreeHomebrewBuffer();
|
||||
return -1;
|
||||
FreeHomebrewBuffer();
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 currentStub = getStubDest();
|
||||
@ -268,13 +268,13 @@ static int RunAppbooter()
|
||||
|
||||
if ( Set_Stub_Split( 0x00010001, "UNEO" ) < 0 )
|
||||
{
|
||||
if ( Set_Stub_Split( 0x00010001, "ULNR" ) < 0 )
|
||||
{
|
||||
if ( !currentStub )
|
||||
currentStub = 0x100000002ULL;
|
||||
if ( Set_Stub_Split( 0x00010001, "ULNR" ) < 0 )
|
||||
{
|
||||
if ( !currentStub )
|
||||
currentStub = 0x100000002ULL;
|
||||
|
||||
Set_Stub( currentStub );
|
||||
}
|
||||
Set_Stub( currentStub );
|
||||
}
|
||||
}
|
||||
|
||||
SDCard_deInit();
|
||||
@ -301,7 +301,7 @@ int BootHomebrew( char * filepath )
|
||||
FILE *file = fopen( filepath, "rb" );
|
||||
|
||||
if ( !file )
|
||||
Sys_BackToLoader();
|
||||
Sys_BackToLoader();
|
||||
|
||||
fseek( file, 0, SEEK_END );
|
||||
filesize = ftell( file );
|
||||
@ -311,21 +311,21 @@ int BootHomebrew( char * filepath )
|
||||
|
||||
if ( fread( buffer, 1, filesize, file ) != filesize )
|
||||
{
|
||||
fclose( file );
|
||||
free( buffer );
|
||||
SDCard_deInit();
|
||||
USBDevice_deInit();
|
||||
Sys_BackToLoader();
|
||||
fclose( file );
|
||||
free( buffer );
|
||||
SDCard_deInit();
|
||||
USBDevice_deInit();
|
||||
Sys_BackToLoader();
|
||||
}
|
||||
|
||||
fclose( file );
|
||||
|
||||
CopyHomebrewMemory(( u8* ) buffer, 0, filesize );
|
||||
CopyHomebrewMemory( ( u8* ) buffer, 0, filesize );
|
||||
|
||||
if ( buffer )
|
||||
{
|
||||
free( buffer );
|
||||
buffer = NULL;
|
||||
free( buffer );
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
AddBootArgument( filepath );
|
||||
@ -338,13 +338,13 @@ int BootHomebrewFromMem()
|
||||
|
||||
if ( !innetbuffer )
|
||||
{
|
||||
gprintf( "!innetbuffer\n" );
|
||||
SDCard_deInit();
|
||||
USBDevice_deInit();
|
||||
Sys_BackToLoader();
|
||||
gprintf( "!innetbuffer\n" );
|
||||
SDCard_deInit();
|
||||
USBDevice_deInit();
|
||||
Sys_BackToLoader();
|
||||
}
|
||||
|
||||
CopyHomebrewMemory(( u8* ) innetbuffer, 0, homebrewsize );
|
||||
CopyHomebrewMemory( ( u8* ) innetbuffer, 0, homebrewsize );
|
||||
free( innetbuffer );
|
||||
|
||||
return RunAppbooter();
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
//int BootHomebrew();
|
||||
int BootHomebrewFromMem();
|
||||
int BootHomebrew( char * filepath);
|
||||
int CopyHomebrewMemory(u8 *temp, u32 pos, u32 len);
|
||||
void AddBootArgument(const char * arg);
|
||||
int BootHomebrew( char * filepath );
|
||||
int CopyHomebrewMemory( u8 *temp, u32 pos, u32 len );
|
||||
void AddBootArgument( const char * arg );
|
||||
void FreeHomebrewBuffer();
|
||||
int LoadHomebrew(const char * filepath);
|
||||
int LoadHomebrew( const char * filepath );
|
||||
int AllocHomebrewMemory( u32 filesize );
|
||||
extern void *innetbuffer;
|
||||
extern u32 homebrewsize;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@
|
||||
#ifndef _HOMEBREWBROWSE_H_
|
||||
#define _HOMEBREWBROWSE_H_
|
||||
|
||||
int roundup(float number);
|
||||
int roundup( float number );
|
||||
int MenuHomebrewBrowse();
|
||||
|
||||
#endif
|
||||
|
@ -9,108 +9,128 @@
|
||||
|
||||
#include "HomebrewFiles.h"
|
||||
|
||||
HomebrewFiles::HomebrewFiles(const char * path) {
|
||||
HomebrewFiles::HomebrewFiles( const char * path )
|
||||
{
|
||||
filecount = 0;
|
||||
|
||||
FileInfo = (FileInfos *) malloc(sizeof(FileInfos));
|
||||
if (!FileInfo) {
|
||||
FileInfo = ( FileInfos * ) malloc( sizeof( FileInfos ) );
|
||||
if ( !FileInfo )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&FileInfo[filecount], 0, sizeof(FileInfos));
|
||||
memset( &FileInfo[filecount], 0, sizeof( FileInfos ) );
|
||||
|
||||
this->LoadPath(path);
|
||||
this->LoadPath( path );
|
||||
this->SortList();
|
||||
}
|
||||
|
||||
HomebrewFiles::~HomebrewFiles() {
|
||||
if (FileInfo) {
|
||||
free(FileInfo);
|
||||
HomebrewFiles::~HomebrewFiles()
|
||||
{
|
||||
if ( FileInfo )
|
||||
{
|
||||
free( FileInfo );
|
||||
FileInfo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool HomebrewFiles::LoadPath(const char * folderpath) {
|
||||
bool HomebrewFiles::LoadPath( const char * folderpath )
|
||||
{
|
||||
struct stat st;
|
||||
DIR_ITER *dir = NULL;
|
||||
char filename[1024];
|
||||
|
||||
dir = diropen(folderpath);
|
||||
if (dir == NULL) {
|
||||
dir = diropen( folderpath );
|
||||
if ( dir == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (dirnext(dir,filename,&st) == 0) {
|
||||
if ((st.st_mode & S_IFDIR) != 0) {
|
||||
if (strcmp(filename,".") != 0 && strcmp(filename,"..") != 0) {
|
||||
while ( dirnext( dir, filename, &st ) == 0 )
|
||||
{
|
||||
if ( ( st.st_mode & S_IFDIR ) != 0 )
|
||||
{
|
||||
if ( strcmp( filename, "." ) != 0 && strcmp( filename, ".." ) != 0 )
|
||||
{
|
||||
char currentname[200];
|
||||
snprintf(currentname, sizeof(currentname), "%s%s/", folderpath, filename);
|
||||
this->LoadPath(currentname);
|
||||
snprintf( currentname, sizeof( currentname ), "%s%s/", folderpath, filename );
|
||||
this->LoadPath( currentname );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char temp[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
temp[i] = filename[strlen(filename)-4+i];
|
||||
for ( int i = 0; i < 5; i++ )
|
||||
{
|
||||
temp[i] = filename[strlen( filename )-4+i];
|
||||
}
|
||||
|
||||
if ((strncasecmp(temp, ".dol", 4) == 0 || strncasecmp(temp, ".elf", 4) == 0)
|
||||
&& filecount < MAXHOMEBREWS && filename[0]!='.') {
|
||||
if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 )
|
||||
&& filecount < MAXHOMEBREWS && filename[0] != '.' )
|
||||
{
|
||||
|
||||
FileInfo = (FileInfos *) realloc(FileInfo, (filecount+1)*sizeof(FileInfos));
|
||||
FileInfo = ( FileInfos * ) realloc( FileInfo, ( filecount + 1 ) * sizeof( FileInfos ) );
|
||||
|
||||
if (!FileInfo) {
|
||||
free(FileInfo);
|
||||
if ( !FileInfo )
|
||||
{
|
||||
free( FileInfo );
|
||||
FileInfo = NULL;
|
||||
filecount = 0;
|
||||
dirclose(dir);
|
||||
dirclose( dir );
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&(FileInfo[filecount]), 0, sizeof(FileInfo));
|
||||
memset( &( FileInfo[filecount] ), 0, sizeof( FileInfo ) );
|
||||
|
||||
strlcpy(FileInfo[filecount].FilePath, folderpath, sizeof(FileInfo[filecount].FilePath));
|
||||
strlcpy(FileInfo[filecount].FileName, filename, sizeof(FileInfo[filecount].FileName));
|
||||
strlcpy( FileInfo[filecount].FilePath, folderpath, sizeof( FileInfo[filecount].FilePath ) );
|
||||
strlcpy( FileInfo[filecount].FileName, filename, sizeof( FileInfo[filecount].FileName ) );
|
||||
FileInfo[filecount].FileSize = st.st_size;
|
||||
filecount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
dirclose(dir);
|
||||
dirclose( dir );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char * HomebrewFiles::GetFilename(int ind) {
|
||||
if (ind > filecount)
|
||||
char * HomebrewFiles::GetFilename( int ind )
|
||||
{
|
||||
if ( ind > filecount )
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FileName;
|
||||
}
|
||||
|
||||
char * HomebrewFiles::GetFilepath(int ind) {
|
||||
if (ind > filecount)
|
||||
char * HomebrewFiles::GetFilepath( int ind )
|
||||
{
|
||||
if ( ind > filecount )
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FilePath;
|
||||
}
|
||||
|
||||
unsigned int HomebrewFiles::GetFilesize(int ind) {
|
||||
if (ind > filecount || !filecount || !FileInfo)
|
||||
unsigned int HomebrewFiles::GetFilesize( int ind )
|
||||
{
|
||||
if ( ind > filecount || !filecount || !FileInfo )
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FileSize;
|
||||
}
|
||||
|
||||
int HomebrewFiles::GetFilecount() {
|
||||
int HomebrewFiles::GetFilecount()
|
||||
{
|
||||
return filecount;
|
||||
}
|
||||
|
||||
static int ListCompare(const void *a, const void *b) {
|
||||
FileInfos *ab = (FileInfos*) a;
|
||||
FileInfos *bb = (FileInfos*) b;
|
||||
static int ListCompare( const void *a, const void *b )
|
||||
{
|
||||
FileInfos *ab = ( FileInfos* ) a;
|
||||
FileInfos *bb = ( FileInfos* ) b;
|
||||
|
||||
return stricmp((char *) ab->FilePath, (char *) bb->FilePath);
|
||||
return stricmp( ( char * ) ab->FilePath, ( char * ) bb->FilePath );
|
||||
}
|
||||
void HomebrewFiles::SortList() {
|
||||
qsort(FileInfo, filecount, sizeof(FileInfos), ListCompare);
|
||||
void HomebrewFiles::SortList()
|
||||
{
|
||||
qsort( FileInfo, filecount, sizeof( FileInfos ), ListCompare );
|
||||
}
|
||||
|
@ -7,38 +7,40 @@
|
||||
|
||||
#define MAXHOMEBREWS 500
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char FileName[100];
|
||||
char FilePath[150];
|
||||
unsigned int FileSize;
|
||||
} FileInfos;
|
||||
|
||||
class HomebrewFiles {
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param path Path where to check for homebrew files
|
||||
HomebrewFiles(const char * path);
|
||||
//!Destructor
|
||||
~HomebrewFiles();
|
||||
//! Load the dol/elf list of a path
|
||||
//!\param path Path where to check for homebrew files
|
||||
bool LoadPath(const char * path);
|
||||
//! Get the a filename of the list
|
||||
//!\param list index
|
||||
char * GetFilename(int index);
|
||||
//! Get the a filepath of the list
|
||||
//!\param list index
|
||||
char * GetFilepath(int index);
|
||||
//! Get the a filesize of the list
|
||||
//!\param list index
|
||||
unsigned int GetFilesize(int index);
|
||||
//! Get the filecount of the whole list
|
||||
int GetFilecount();
|
||||
//! Sort list by filepath
|
||||
void SortList();
|
||||
protected:
|
||||
int filecount;
|
||||
FileInfos *FileInfo;
|
||||
class HomebrewFiles
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param path Path where to check for homebrew files
|
||||
HomebrewFiles( const char * path );
|
||||
//!Destructor
|
||||
~HomebrewFiles();
|
||||
//! Load the dol/elf list of a path
|
||||
//!\param path Path where to check for homebrew files
|
||||
bool LoadPath( const char * path );
|
||||
//! Get the a filename of the list
|
||||
//!\param list index
|
||||
char * GetFilename( int index );
|
||||
//! Get the a filepath of the list
|
||||
//!\param list index
|
||||
char * GetFilepath( int index );
|
||||
//! Get the a filesize of the list
|
||||
//!\param list index
|
||||
unsigned int GetFilesize( int index );
|
||||
//! Get the filecount of the whole list
|
||||
int GetFilecount();
|
||||
//! Sort list by filepath
|
||||
void SortList();
|
||||
protected:
|
||||
int filecount;
|
||||
FileInfos *FileInfo;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -11,58 +11,58 @@
|
||||
|
||||
#define ENTRIE_SIZE 8192
|
||||
|
||||
int HomebrewXML::LoadHomebrewXMLData(const char* filename)
|
||||
int HomebrewXML::LoadHomebrewXMLData( const char* filename )
|
||||
{
|
||||
mxml_node_t *nodedataHB = NULL;
|
||||
mxml_node_t *nodetreeHB = NULL;
|
||||
|
||||
/* Load XML file */
|
||||
FILE *filexml;
|
||||
filexml = fopen(filename, "rb");
|
||||
if (!filexml)
|
||||
filexml = fopen( filename, "rb" );
|
||||
if ( !filexml )
|
||||
return -1;
|
||||
|
||||
nodetreeHB = mxmlLoadFile(NULL, filexml, MXML_OPAQUE_CALLBACK);
|
||||
fclose(filexml);
|
||||
nodetreeHB = mxmlLoadFile( NULL, filexml, MXML_OPAQUE_CALLBACK );
|
||||
fclose( filexml );
|
||||
|
||||
if (nodetreeHB == NULL)
|
||||
if ( nodetreeHB == NULL )
|
||||
return -2;
|
||||
|
||||
nodedataHB = mxmlFindElement(nodetreeHB, nodetreeHB, "app", NULL, NULL, MXML_DESCEND);
|
||||
if (nodedataHB == NULL)
|
||||
nodedataHB = mxmlFindElement( nodetreeHB, nodetreeHB, "app", NULL, NULL, MXML_DESCEND );
|
||||
if ( nodedataHB == NULL )
|
||||
return -5;
|
||||
|
||||
char * Entrie = new char[ENTRIE_SIZE];
|
||||
|
||||
GetTextFromNode(nodedataHB, nodedataHB, (char*) "name", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE);
|
||||
GetTextFromNode( nodedataHB, nodedataHB, ( char* ) "name", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE );
|
||||
Name = Entrie;
|
||||
|
||||
GetTextFromNode(nodedataHB, nodedataHB, (char*) "coder", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE);
|
||||
GetTextFromNode( nodedataHB, nodedataHB, ( char* ) "coder", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE );
|
||||
Coder = Entrie;
|
||||
|
||||
GetTextFromNode(nodedataHB, nodedataHB, (char*) "version", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE);
|
||||
GetTextFromNode( nodedataHB, nodedataHB, ( char* ) "version", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE );
|
||||
Version = Entrie;
|
||||
|
||||
GetTextFromNode(nodedataHB, nodedataHB, (char*) "short_description", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE);
|
||||
GetTextFromNode( nodedataHB, nodedataHB, ( char* ) "short_description", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE );
|
||||
ShortDescription = Entrie;
|
||||
|
||||
GetTextFromNode(nodedataHB, nodedataHB, (char*) "long_description", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE);
|
||||
GetTextFromNode( nodedataHB, nodedataHB, ( char* ) "long_description", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE );
|
||||
LongDescription = Entrie;
|
||||
|
||||
GetTextFromNode(nodedataHB, nodedataHB, (char*) "release_date", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE);
|
||||
GetTextFromNode( nodedataHB, nodedataHB, ( char* ) "release_date", NULL, NULL, MXML_DESCEND, Entrie, ENTRIE_SIZE );
|
||||
|
||||
int len = (strlen(Entrie)-6); //length of the date string without the 200000 at the end
|
||||
if (len == 8)
|
||||
snprintf(Entrie, ENTRIE_SIZE, "%c%c/%c%c/%c%c%c%c", Entrie[4],Entrie[5],Entrie[6],Entrie[7],Entrie[0],Entrie[1],Entrie[2],Entrie[3]);
|
||||
else if (len == 6)
|
||||
snprintf(Entrie, ENTRIE_SIZE, "%c%c/%c%c%c%c", Entrie[4],Entrie[5],Entrie[0],Entrie[1],Entrie[2],Entrie[3]);
|
||||
int len = ( strlen( Entrie ) - 6 ); //length of the date string without the 200000 at the end
|
||||
if ( len == 8 )
|
||||
snprintf( Entrie, ENTRIE_SIZE, "%c%c/%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[6], Entrie[7], Entrie[0], Entrie[1], Entrie[2], Entrie[3] );
|
||||
else if ( len == 6 )
|
||||
snprintf( Entrie, ENTRIE_SIZE, "%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[0], Entrie[1], Entrie[2], Entrie[3] );
|
||||
else
|
||||
snprintf(Entrie, ENTRIE_SIZE, "%s", Entrie);
|
||||
snprintf( Entrie, ENTRIE_SIZE, "%s", Entrie );
|
||||
|
||||
Releasedate = Entrie;
|
||||
|
||||
free(nodedataHB);
|
||||
free(nodetreeHB);
|
||||
free( nodedataHB );
|
||||
free( nodetreeHB );
|
||||
|
||||
delete [] Entrie;
|
||||
|
||||
|
@ -16,7 +16,7 @@ class HomebrewXML
|
||||
//!Destructor
|
||||
~HomebrewXML() { };
|
||||
//!\param filename Filepath of the XML file
|
||||
int LoadHomebrewXMLData(const char* filename);
|
||||
int LoadHomebrewXMLData( const char* filename );
|
||||
//! Get name
|
||||
const char * GetName() { return Name.c_str(); };
|
||||
//! Get coder
|
||||
@ -30,7 +30,7 @@ class HomebrewXML
|
||||
//! Get longdescription
|
||||
const char * GetLongDescription() { return LongDescription.c_str(); };
|
||||
//! Set Name
|
||||
void SetName(char * newName) { Name = newName; };
|
||||
void SetName( char * newName ) { Name = newName; };
|
||||
protected:
|
||||
std::string Name;
|
||||
std::string Coder;
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
#include "dolloader.h"
|
||||
|
||||
typedef struct _dolheader {
|
||||
typedef struct _dolheader
|
||||
{
|
||||
u32 text_pos[7];
|
||||
u32 data_pos[11];
|
||||
u32 text_start[7];
|
||||
@ -20,31 +21,36 @@ typedef struct _dolheader {
|
||||
u32 entry_point;
|
||||
} dolheader;
|
||||
|
||||
u32 load_dol(const void *dolstart, struct __argv *argv) {
|
||||
u32 load_dol( const void *dolstart, struct __argv *argv )
|
||||
{
|
||||
u32 i;
|
||||
dolheader *dolfile;
|
||||
|
||||
if (dolstart) {
|
||||
dolfile = (dolheader *) dolstart;
|
||||
for (i = 0; i < 7; i++) {
|
||||
if ((!dolfile->text_size[i]) || (dolfile->text_start[i] < 0x100)) continue;
|
||||
ICInvalidateRange ((void *) dolfile->text_start[i],dolfile->text_size[i]);
|
||||
memcpy((void *) dolfile->text_start[i],dolstart+dolfile->text_pos[i],dolfile->text_size[i]);
|
||||
if ( dolstart )
|
||||
{
|
||||
dolfile = ( dolheader * ) dolstart;
|
||||
for ( i = 0; i < 7; i++ )
|
||||
{
|
||||
if ( ( !dolfile->text_size[i] ) || ( dolfile->text_start[i] < 0x100 ) ) continue;
|
||||
ICInvalidateRange ( ( void * ) dolfile->text_start[i], dolfile->text_size[i] );
|
||||
memcpy( ( void * ) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i] );
|
||||
}
|
||||
|
||||
for (i = 0; i < 11; i++) {
|
||||
if ((!dolfile->data_size[i]) || (dolfile->data_start[i] < 0x100)) continue;
|
||||
memcpy((void *) dolfile->data_start[i],dolstart+dolfile->data_pos[i],dolfile->data_size[i]);
|
||||
DCFlushRangeNoSync ((void *) dolfile->data_start[i],dolfile->data_size[i]);
|
||||
for ( i = 0; i < 11; i++ )
|
||||
{
|
||||
if ( ( !dolfile->data_size[i] ) || ( dolfile->data_start[i] < 0x100 ) ) continue;
|
||||
memcpy( ( void * ) dolfile->data_start[i], dolstart + dolfile->data_pos[i], dolfile->data_size[i] );
|
||||
DCFlushRangeNoSync ( ( void * ) dolfile->data_start[i], dolfile->data_size[i] );
|
||||
}
|
||||
|
||||
memset ((void *) dolfile->bss_start, 0, dolfile->bss_size);
|
||||
DCFlushRange((void *) dolfile->bss_start, dolfile->bss_size);
|
||||
memset ( ( void * ) dolfile->bss_start, 0, dolfile->bss_size );
|
||||
DCFlushRange( ( void * ) dolfile->bss_start, dolfile->bss_size );
|
||||
|
||||
if (argv && argv->argvMagic == ARGV_MAGIC) {
|
||||
void *new_argv = (void *)(dolfile->entry_point + 8);
|
||||
memcpy(new_argv, argv, sizeof(*argv));
|
||||
DCFlushRange(new_argv, sizeof(*argv));
|
||||
if ( argv && argv->argvMagic == ARGV_MAGIC )
|
||||
{
|
||||
void *new_argv = ( void * )( dolfile->entry_point + 8 );
|
||||
memcpy( new_argv, argv, sizeof( *argv ) );
|
||||
DCFlushRange( new_argv, sizeof( *argv ) );
|
||||
}
|
||||
|
||||
return dolfile->entry_point;
|
||||
|
@ -2,13 +2,14 @@
|
||||
#define _DOLLOADER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern void __exception_closeall();
|
||||
typedef void (*entrypoint) (void);
|
||||
extern void __exception_closeall();
|
||||
typedef void ( *entrypoint ) ( void );
|
||||
|
||||
u32 load_dol(const void *dolstart, struct __argv *argv);
|
||||
u32 load_dol( const void *dolstart, struct __argv *argv );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
136
source/input.cpp
136
source/input.cpp
@ -20,9 +20,9 @@
|
||||
#include "input.h"
|
||||
#include "libwiigui/gui.h"
|
||||
|
||||
int rumbleRequest[4] = {0,0,0,0};
|
||||
int rumbleRequest[4] = {0, 0, 0, 0};
|
||||
GuiTrigger userInput[4];
|
||||
static int rumbleCount[4] = {0,0,0,0};
|
||||
static int rumbleCount[4] = {0, 0, 0, 0};
|
||||
|
||||
/****************************************************************************
|
||||
* UpdatePads
|
||||
@ -34,22 +34,22 @@ void UpdatePads()
|
||||
WPAD_ScanPads();
|
||||
PAD_ScanPads();
|
||||
|
||||
for (int i=3; i >= 0; i--)
|
||||
for ( int i = 3; i >= 0; i-- )
|
||||
{
|
||||
memcpy(&userInput[i].wpad, WPAD_Data(i), sizeof(WPADData));
|
||||
memcpy( &userInput[i].wpad, WPAD_Data( i ), sizeof( WPADData ) );
|
||||
userInput[i].chan = i;
|
||||
userInput[i].pad.btns_d = PAD_ButtonsDown(i);
|
||||
userInput[i].pad.btns_u = PAD_ButtonsUp(i);
|
||||
userInput[i].pad.btns_h = PAD_ButtonsHeld(i);
|
||||
userInput[i].pad.stickX = PAD_StickX(i);
|
||||
userInput[i].pad.stickY = PAD_StickY(i);
|
||||
userInput[i].pad.substickX = PAD_SubStickX(i);
|
||||
userInput[i].pad.substickY = PAD_SubStickY(i);
|
||||
userInput[i].pad.triggerL = PAD_TriggerL(i);
|
||||
userInput[i].pad.triggerR = PAD_TriggerR(i);
|
||||
userInput[i].pad.btns_d = PAD_ButtonsDown( i );
|
||||
userInput[i].pad.btns_u = PAD_ButtonsUp( i );
|
||||
userInput[i].pad.btns_h = PAD_ButtonsHeld( i );
|
||||
userInput[i].pad.stickX = PAD_StickX( i );
|
||||
userInput[i].pad.stickY = PAD_StickY( i );
|
||||
userInput[i].pad.substickX = PAD_SubStickX( i );
|
||||
userInput[i].pad.substickY = PAD_SubStickY( i );
|
||||
userInput[i].pad.triggerL = PAD_TriggerL( i );
|
||||
userInput[i].pad.triggerR = PAD_TriggerR( i );
|
||||
|
||||
if(Settings.rumble == RumbleOn)
|
||||
DoRumble(i);
|
||||
if ( Settings.rumble == RumbleOn )
|
||||
DoRumble( i );
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,26 +60,28 @@ void UpdatePads()
|
||||
***************************************************************************/
|
||||
void SetupPads()
|
||||
{
|
||||
PAD_Init();
|
||||
WPAD_Init();
|
||||
PAD_Init();
|
||||
WPAD_Init();
|
||||
|
||||
// read wiimote accelerometer and IR data
|
||||
WPAD_SetDataFormat(WPAD_CHAN_ALL,WPAD_FMT_BTNS_ACC_IR);
|
||||
WPAD_SetVRes(WPAD_CHAN_ALL, screenwidth, screenheight);
|
||||
// read wiimote accelerometer and IR data
|
||||
WPAD_SetDataFormat( WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR );
|
||||
WPAD_SetVRes( WPAD_CHAN_ALL, screenwidth, screenheight );
|
||||
|
||||
for(int i=0; i < 4; i++)
|
||||
{
|
||||
userInput[i].chan = i;
|
||||
}
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
userInput[i].chan = i;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* ShutoffRumble
|
||||
***************************************************************************/
|
||||
|
||||
void ShutoffRumble() {
|
||||
for (int i=0;i<4;i++) {
|
||||
WPAD_Rumble(i, 0);
|
||||
void ShutoffRumble()
|
||||
{
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
WPAD_Rumble( i, 0 );
|
||||
rumbleCount[i] = 0;
|
||||
}
|
||||
}
|
||||
@ -88,17 +90,23 @@ void ShutoffRumble() {
|
||||
* DoRumble
|
||||
***************************************************************************/
|
||||
|
||||
void DoRumble(int i) {
|
||||
if (rumbleRequest[i] && rumbleCount[i] < 3) {
|
||||
WPAD_Rumble(i, 1); // rumble on
|
||||
void DoRumble( int i )
|
||||
{
|
||||
if ( rumbleRequest[i] && rumbleCount[i] < 3 )
|
||||
{
|
||||
WPAD_Rumble( i, 1 ); // rumble on
|
||||
rumbleCount[i]++;
|
||||
} else if (rumbleRequest[i]) {
|
||||
}
|
||||
else if ( rumbleRequest[i] )
|
||||
{
|
||||
rumbleCount[i] = 20;
|
||||
rumbleRequest[i] = 0;
|
||||
} else {
|
||||
if (rumbleCount[i])
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rumbleCount[i] )
|
||||
rumbleCount[i]--;
|
||||
WPAD_Rumble(i, 0); // rumble off
|
||||
WPAD_Rumble( i, 0 ); // rumble off
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,43 +116,49 @@ void DoRumble(int i) {
|
||||
* Get X/Y value from Wii Joystick (classic, nunchuk) input
|
||||
***************************************************************************/
|
||||
|
||||
s8 WPAD_Stick(u8 chan, u8 right, int axis) {
|
||||
s8 WPAD_Stick( u8 chan, u8 right, int axis )
|
||||
{
|
||||
float mag = 0.0;
|
||||
float ang = 0.0;
|
||||
WPADData *data = WPAD_Data(chan);
|
||||
WPADData *data = WPAD_Data( chan );
|
||||
|
||||
switch (data->exp.type) {
|
||||
case WPAD_EXP_NUNCHUK:
|
||||
case WPAD_EXP_GUITARHERO3:
|
||||
if (right == 0) {
|
||||
mag = data->exp.nunchuk.js.mag;
|
||||
ang = data->exp.nunchuk.js.ang;
|
||||
}
|
||||
break;
|
||||
switch ( data->exp.type )
|
||||
{
|
||||
case WPAD_EXP_NUNCHUK:
|
||||
case WPAD_EXP_GUITARHERO3:
|
||||
if ( right == 0 )
|
||||
{
|
||||
mag = data->exp.nunchuk.js.mag;
|
||||
ang = data->exp.nunchuk.js.ang;
|
||||
}
|
||||
break;
|
||||
|
||||
case WPAD_EXP_CLASSIC:
|
||||
if (right == 0) {
|
||||
mag = data->exp.classic.ljs.mag;
|
||||
ang = data->exp.classic.ljs.ang;
|
||||
} else {
|
||||
mag = data->exp.classic.rjs.mag;
|
||||
ang = data->exp.classic.rjs.ang;
|
||||
}
|
||||
break;
|
||||
case WPAD_EXP_CLASSIC:
|
||||
if ( right == 0 )
|
||||
{
|
||||
mag = data->exp.classic.ljs.mag;
|
||||
ang = data->exp.classic.ljs.ang;
|
||||
}
|
||||
else
|
||||
{
|
||||
mag = data->exp.classic.rjs.mag;
|
||||
ang = data->exp.classic.rjs.ang;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* calculate x/y value (angle need to be converted into radian) */
|
||||
if (mag > 1.0) mag = 1.0;
|
||||
else if (mag < -1.0) mag = -1.0;
|
||||
if ( mag > 1.0 ) mag = 1.0;
|
||||
else if ( mag < -1.0 ) mag = -1.0;
|
||||
double val;
|
||||
|
||||
if (axis == 0) // x-axis
|
||||
val = mag * sin((PI * ang)/180.0f);
|
||||
if ( axis == 0 ) // x-axis
|
||||
val = mag * sin( ( PI * ang ) / 180.0f );
|
||||
else // y-axis
|
||||
val = mag * cos((PI * ang)/180.0f);
|
||||
val = mag * cos( ( PI * ang ) / 180.0f );
|
||||
|
||||
return (s8)(val * 128.0f);
|
||||
return ( s8 )( val * 128.0f );
|
||||
}
|
||||
|
@ -12,14 +12,14 @@
|
||||
#include <gccore.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
|
||||
#define PI 3.14159265f
|
||||
#define PADCAL 50
|
||||
#define PI 3.14159265f
|
||||
#define PADCAL 50
|
||||
|
||||
extern int rumbleRequest[4];
|
||||
|
||||
void SetupPads();
|
||||
void UpdatePads();
|
||||
void ShutoffRumble();
|
||||
void DoRumble(int i);
|
||||
void DoRumble( int i );
|
||||
|
||||
#endif
|
||||
|
@ -13,46 +13,53 @@
|
||||
#include "network/networkops.h"
|
||||
#include "network/http.h"
|
||||
|
||||
int updateLanguageFiles() {
|
||||
int updateLanguageFiles()
|
||||
{
|
||||
char languageFiles[50][MAXLANGUAGEFILES];
|
||||
|
||||
//get all the files in the language path
|
||||
int countfiles = GetAllDirFiles(Settings.languagefiles_path);
|
||||
int countfiles = GetAllDirFiles( Settings.languagefiles_path );
|
||||
|
||||
//give up now if we didn't find any
|
||||
if (!countfiles) return -2;
|
||||
if ( !countfiles ) return -2;
|
||||
|
||||
//now from the files we got, get only the .lang files
|
||||
for (int cnt = 0; cnt < countfiles; cnt++) {
|
||||
for ( int cnt = 0; cnt < countfiles; cnt++ )
|
||||
{
|
||||
char filename[64];
|
||||
strlcpy(filename, GetFileName(cnt),sizeof(filename));
|
||||
if (strcasestr(filename,".lang")) {
|
||||
strcpy(languageFiles[cnt],filename);
|
||||
strlcpy( filename, GetFileName( cnt ), sizeof( filename ) );
|
||||
if ( strcasestr( filename, ".lang" ) )
|
||||
{
|
||||
strcpy( languageFiles[cnt], filename );
|
||||
}
|
||||
}
|
||||
|
||||
subfoldercreate(Settings.languagefiles_path);
|
||||
subfoldercreate( Settings.languagefiles_path );
|
||||
|
||||
//we assume that the network will already be init by another function
|
||||
// ( that has gui eletents in it because this one doesn't)
|
||||
int done = 0,j = 0;
|
||||
if (IsNetworkInit()) {
|
||||
int done = 0, j = 0;
|
||||
if ( IsNetworkInit() )
|
||||
{
|
||||
//build the URL, save path, and download each file and save it
|
||||
while (j<countfiles) {
|
||||
while ( j < countfiles )
|
||||
{
|
||||
char savepath[150];
|
||||
char codeurl[200];
|
||||
snprintf(codeurl, sizeof(codeurl), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s",languageFiles[j]);
|
||||
snprintf(savepath, sizeof(savepath), "%s%s",Settings.languagefiles_path,languageFiles[j]);
|
||||
snprintf( codeurl, sizeof( codeurl ), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s", languageFiles[j] );
|
||||
snprintf( savepath, sizeof( savepath ), "%s%s", Settings.languagefiles_path, languageFiles[j] );
|
||||
|
||||
struct block file = downloadfile(codeurl);
|
||||
struct block file = downloadfile( codeurl );
|
||||
|
||||
if (file.data != NULL) {
|
||||
if ( file.data != NULL )
|
||||
{
|
||||
FILE * pfile;
|
||||
pfile = fopen(savepath, "wb");
|
||||
if(pfile != NULL) {
|
||||
fwrite(file.data,1,file.size,pfile);
|
||||
fclose(pfile);
|
||||
free(file.data);
|
||||
pfile = fopen( savepath, "wb" );
|
||||
if ( pfile != NULL )
|
||||
{
|
||||
fwrite( file.data, 1, file.size, pfile );
|
||||
fclose( pfile );
|
||||
free( file.data );
|
||||
done++;
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,13 @@
|
||||
#include <gctypes.h>
|
||||
#include "gettext.h"
|
||||
|
||||
typedef struct _MSG {
|
||||
typedef struct _MSG
|
||||
{
|
||||
u32 id;
|
||||
char* msgstr;
|
||||
struct _MSG *next;
|
||||
} MSG;
|
||||
static MSG *baseMSG=0;
|
||||
static MSG *baseMSG = 0;
|
||||
|
||||
|
||||
#define HASHWORDBITS 32
|
||||
@ -18,18 +19,21 @@ static MSG *baseMSG=0;
|
||||
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
||||
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
||||
static inline u32
|
||||
hash_string (const char *str_param) {
|
||||
hash_string ( const char *str_param )
|
||||
{
|
||||
u32 hval, g;
|
||||
const char *str = str_param;
|
||||
|
||||
/* Compute the hash value for the given string. */
|
||||
hval = 0;
|
||||
while (*str != '\0') {
|
||||
while ( *str != '\0' )
|
||||
{
|
||||
hval <<= 4;
|
||||
hval += (u8) *str++;
|
||||
g = hval & ((u32) 0xf << (HASHWORDBITS - 4));
|
||||
if (g != 0) {
|
||||
hval ^= g >> (HASHWORDBITS - 8);
|
||||
hval += ( u8 ) * str++;
|
||||
g = hval & ( ( u32 ) 0xf << ( HASHWORDBITS - 4 ) );
|
||||
if ( g != 0 )
|
||||
{
|
||||
hval ^= g >> ( HASHWORDBITS - 8 );
|
||||
hval ^= g;
|
||||
}
|
||||
}
|
||||
@ -38,88 +42,95 @@ hash_string (const char *str_param) {
|
||||
|
||||
/* Expand some escape sequences found in the argument string. */
|
||||
static char *
|
||||
expand_escape (const char *str) {
|
||||
expand_escape ( const char *str )
|
||||
{
|
||||
char *retval, *rp;
|
||||
const char *cp = str;
|
||||
|
||||
retval = (char *) malloc (strlen (str)+1);
|
||||
if (retval==NULL) return NULL;
|
||||
retval = ( char * ) malloc ( strlen ( str ) + 1 );
|
||||
if ( retval == NULL ) return NULL;
|
||||
rp = retval;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != '\\')
|
||||
while ( cp[0] != '\0' && cp[0] != '\\' )
|
||||
*rp++ = *cp++;
|
||||
if (cp[0] == '\0')
|
||||
if ( cp[0] == '\0' )
|
||||
goto terminate;
|
||||
do {
|
||||
do
|
||||
{
|
||||
|
||||
/* Here cp[0] == '\\'. */
|
||||
switch (*++cp) {
|
||||
case '\"': /* " */
|
||||
*rp++ = '\"';
|
||||
++cp;
|
||||
break;
|
||||
case 'a': /* alert */
|
||||
*rp++ = '\a';
|
||||
++cp;
|
||||
break;
|
||||
case 'b': /* backspace */
|
||||
*rp++ = '\b';
|
||||
++cp;
|
||||
break;
|
||||
case 'f': /* form feed */
|
||||
*rp++ = '\f';
|
||||
++cp;
|
||||
break;
|
||||
case 'n': /* new line */
|
||||
*rp++ = '\n';
|
||||
++cp;
|
||||
break;
|
||||
case 'r': /* carriage return */
|
||||
*rp++ = '\r';
|
||||
++cp;
|
||||
break;
|
||||
case 't': /* horizontal tab */
|
||||
*rp++ = '\t';
|
||||
++cp;
|
||||
break;
|
||||
case 'v': /* vertical tab */
|
||||
*rp++ = '\v';
|
||||
++cp;
|
||||
break;
|
||||
case '\\':
|
||||
*rp = '\\';
|
||||
++cp;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7': {
|
||||
int ch = *cp++ - '0';
|
||||
switch ( *++cp )
|
||||
{
|
||||
case '\"': /* " */
|
||||
*rp++ = '\"';
|
||||
++cp;
|
||||
break;
|
||||
case 'a': /* alert */
|
||||
*rp++ = '\a';
|
||||
++cp;
|
||||
break;
|
||||
case 'b': /* backspace */
|
||||
*rp++ = '\b';
|
||||
++cp;
|
||||
break;
|
||||
case 'f': /* form feed */
|
||||
*rp++ = '\f';
|
||||
++cp;
|
||||
break;
|
||||
case 'n': /* new line */
|
||||
*rp++ = '\n';
|
||||
++cp;
|
||||
break;
|
||||
case 'r': /* carriage return */
|
||||
*rp++ = '\r';
|
||||
++cp;
|
||||
break;
|
||||
case 't': /* horizontal tab */
|
||||
*rp++ = '\t';
|
||||
++cp;
|
||||
break;
|
||||
case 'v': /* vertical tab */
|
||||
*rp++ = '\v';
|
||||
++cp;
|
||||
break;
|
||||
case '\\':
|
||||
*rp = '\\';
|
||||
++cp;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
int ch = *cp++ - '0';
|
||||
|
||||
if (*cp >= '0' && *cp <= '7') {
|
||||
ch *= 8;
|
||||
ch += *cp++ - '0';
|
||||
|
||||
if (*cp >= '0' && *cp <= '7') {
|
||||
if ( *cp >= '0' && *cp <= '7' )
|
||||
{
|
||||
ch *= 8;
|
||||
ch += *cp++ - '0';
|
||||
|
||||
if ( *cp >= '0' && *cp <= '7' )
|
||||
{
|
||||
ch *= 8;
|
||||
ch += *cp++ - '0';
|
||||
}
|
||||
}
|
||||
*rp = ch;
|
||||
}
|
||||
*rp = ch;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*rp = '\\';
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
*rp = '\\';
|
||||
break;
|
||||
}
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != '\\')
|
||||
while ( cp[0] != '\0' && cp[0] != '\\' )
|
||||
*rp++ = *cp++;
|
||||
} while (cp[0] != '\0');
|
||||
}
|
||||
while ( cp[0] != '\0' );
|
||||
|
||||
/* Terminate string. */
|
||||
terminate:
|
||||
@ -127,95 +138,112 @@ terminate:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static MSG *findMSG(u32 id) {
|
||||
static MSG *findMSG( u32 id )
|
||||
{
|
||||
MSG *msg;
|
||||
for (msg=baseMSG; msg; msg=msg->next) {
|
||||
if (msg->id == id)
|
||||
for ( msg = baseMSG; msg; msg = msg->next )
|
||||
{
|
||||
if ( msg->id == id )
|
||||
return msg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static MSG *setMSG(const char *msgid, const char *msgstr) {
|
||||
u32 id = hash_string(msgid);
|
||||
MSG *msg = findMSG(id);
|
||||
if (!msg) {
|
||||
msg = (MSG *)malloc(sizeof(MSG));
|
||||
msg->id = id;
|
||||
static MSG *setMSG( const char *msgid, const char *msgstr )
|
||||
{
|
||||
u32 id = hash_string( msgid );
|
||||
MSG *msg = findMSG( id );
|
||||
if ( !msg )
|
||||
{
|
||||
msg = ( MSG * )malloc( sizeof( MSG ) );
|
||||
msg->id = id;
|
||||
msg->msgstr = NULL;
|
||||
msg->next = baseMSG;
|
||||
baseMSG = msg;
|
||||
msg->next = baseMSG;
|
||||
baseMSG = msg;
|
||||
}
|
||||
if (msg) {
|
||||
if (msgstr) {
|
||||
if (msg->msgstr) free(msg->msgstr);
|
||||
if ( msg )
|
||||
{
|
||||
if ( msgstr )
|
||||
{
|
||||
if ( msg->msgstr ) free( msg->msgstr );
|
||||
//msg->msgstr = strdup(msgstr);
|
||||
msg->msgstr = expand_escape(msgstr);
|
||||
msg->msgstr = expand_escape( msgstr );
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void gettextCleanUp(void) {
|
||||
while (baseMSG) {
|
||||
MSG *nextMsg =baseMSG->next;
|
||||
free(baseMSG->msgstr);
|
||||
free(baseMSG);
|
||||
void gettextCleanUp( void )
|
||||
{
|
||||
while ( baseMSG )
|
||||
{
|
||||
MSG *nextMsg = baseMSG->next;
|
||||
free( baseMSG->msgstr );
|
||||
free( baseMSG );
|
||||
baseMSG = nextMsg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool gettextLoadLanguage(const char* langFile) {
|
||||
bool gettextLoadLanguage( const char* langFile )
|
||||
{
|
||||
FILE *f;
|
||||
char line[200];
|
||||
char *lastID=NULL;
|
||||
char *lastID = NULL;
|
||||
|
||||
gettextCleanUp();
|
||||
f = fopen(langFile, "r");
|
||||
if (!f)
|
||||
f = fopen( langFile, "r" );
|
||||
if ( !f )
|
||||
return false;
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
while ( fgets( line, sizeof( line ), f ) )
|
||||
{
|
||||
// lines starting with # are comments
|
||||
if (line[0] == '#')
|
||||
if ( line[0] == '#' )
|
||||
continue;
|
||||
else if (strncmp(line, "msgid \"", 7) == 0) {
|
||||
else if ( strncmp( line, "msgid \"", 7 ) == 0 )
|
||||
{
|
||||
char *msgid, *end;
|
||||
if (lastID) {
|
||||
free(lastID);
|
||||
lastID=NULL;
|
||||
if ( lastID )
|
||||
{
|
||||
free( lastID );
|
||||
lastID = NULL;
|
||||
}
|
||||
msgid = &line[7];
|
||||
end = strrchr(msgid, '"');
|
||||
if (end && end-msgid>1) {
|
||||
end = strrchr( msgid, '"' );
|
||||
if ( end && end - msgid > 1 )
|
||||
{
|
||||
*end = 0;
|
||||
lastID = strdup(msgid);
|
||||
lastID = strdup( msgid );
|
||||
}
|
||||
} else if (strncmp(line, "msgstr \"", 8) == 0) {
|
||||
}
|
||||
else if ( strncmp( line, "msgstr \"", 8 ) == 0 )
|
||||
{
|
||||
char *msgstr, *end;
|
||||
|
||||
if (lastID == NULL)
|
||||
if ( lastID == NULL )
|
||||
continue;
|
||||
|
||||
msgstr = &line[8];
|
||||
end = strrchr(msgstr, '"');
|
||||
if (end && end-msgstr>1) {
|
||||
end = strrchr( msgstr, '"' );
|
||||
if ( end && end - msgstr > 1 )
|
||||
{
|
||||
*end = 0;
|
||||
setMSG(lastID, msgstr);
|
||||
setMSG( lastID, msgstr );
|
||||
}
|
||||
free(lastID);
|
||||
lastID=NULL;
|
||||
free( lastID );
|
||||
lastID = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
fclose( f );
|
||||
return true;
|
||||
}
|
||||
const char *gettext(const char *msgid) {
|
||||
MSG *msg = findMSG(hash_string(msgid));
|
||||
if (msg && msg->msgstr) return msg->msgstr;
|
||||
const char *gettext( const char *msgid )
|
||||
{
|
||||
MSG *msg = findMSG( hash_string( msgid ) );
|
||||
if ( msg && msg->msgstr ) return msg->msgstr;
|
||||
return msgid;
|
||||
}
|
||||
|
||||
|
@ -2,17 +2,18 @@
|
||||
#define _GETTEXT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
bool gettextLoadLanguage(const char* langFile);
|
||||
void gettextCleanUp(void);
|
||||
bool gettextLoadLanguage( const char* langFile );
|
||||
void gettextCleanUp( void );
|
||||
/*
|
||||
* input msg = a text in ASCII
|
||||
* output = the translated msg in utf-8
|
||||
*/
|
||||
const char *gettext(const char *msg);
|
||||
const char *gettext( const char *msg );
|
||||
#define tr(s) gettext(s)
|
||||
#define trNOOP(s) (s)
|
||||
|
||||
|
@ -34,24 +34,28 @@
|
||||
/*-----------------------------------------------------------------
|
||||
Functions to deal with little endian values stored in uint8_t arrays
|
||||
-----------------------------------------------------------------*/
|
||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8));
|
||||
static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
||||
}
|
||||
|
||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
|
||||
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
||||
}
|
||||
|
||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
}
|
||||
|
||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
item[offset + 2] = (uint8_t)(value >> 16);
|
||||
item[offset + 3] = (uint8_t)(value >> 24);
|
||||
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
||||
item[offset + 3] = ( uint8_t )( value >> 24 );
|
||||
}
|
||||
|
||||
#endif // _BIT_OPS_H
|
||||
|
@ -42,20 +42,22 @@
|
||||
#define PAGE_SECTORS 64
|
||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||
|
||||
typedef struct {
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
bool dirty;
|
||||
uint8_t* cache;
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
bool dirty;
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
} CACHE;
|
||||
|
||||
/*
|
||||
@ -65,9 +67,9 @@ offset is the position to start reading from
|
||||
size is the amount of data to read
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
bool _FAT_cache_readPartialSector ( CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
|
||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes);
|
||||
bool _FAT_cache_readLittleEndianValue ( CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes );
|
||||
|
||||
/*
|
||||
Write data to a sector in the cache
|
||||
@ -77,9 +79,9 @@ offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
bool _FAT_cache_writePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
|
||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes);
|
||||
bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes );
|
||||
|
||||
/*
|
||||
Write data to a sector in the cache, zeroing the sector first
|
||||
@ -89,42 +91,44 @@ offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
bool _FAT_cache_eraseWritePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
|
||||
/*
|
||||
Read several sectors from the cache
|
||||
*/
|
||||
bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer);
|
||||
bool _FAT_cache_readSectors ( CACHE* cache, sec_t sector, sec_t numSectors, void* buffer );
|
||||
|
||||
/*
|
||||
Read a full sector from the cache
|
||||
*/
|
||||
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) {
|
||||
return _FAT_cache_readPartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
|
||||
static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
|
||||
{
|
||||
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||
}
|
||||
|
||||
/*
|
||||
Write a full sector to the cache
|
||||
*/
|
||||
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) {
|
||||
return _FAT_cache_writePartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
|
||||
static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
|
||||
{
|
||||
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
bool _FAT_cache_writeSectors ( CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer );
|
||||
|
||||
/*
|
||||
Write any dirty sectors back to disc and clear out the contents of the cache
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache);
|
||||
bool _FAT_cache_flush ( CACHE* cache );
|
||||
|
||||
/*
|
||||
Clear out the contents of the cache without writing any dirty sectors first
|
||||
*/
|
||||
void _FAT_cache_invalidate (CACHE* cache);
|
||||
void _FAT_cache_invalidate ( CACHE* cache );
|
||||
|
||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition);
|
||||
CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition );
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache);
|
||||
void _FAT_cache_destructor ( CACHE* cache );
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,8 +36,8 @@
|
||||
#include "partition.h"
|
||||
|
||||
#define DIR_ENTRY_DATA_SIZE 0x20
|
||||
#define MAX_LFN_LENGTH 256
|
||||
#define MAX_FILENAME_LENGTH 768 // 256 UCS-2 characters encoded into UTF-8 can use up to 768 UTF-8 chars
|
||||
#define MAX_LFN_LENGTH 256
|
||||
#define MAX_FILENAME_LENGTH 768 // 256 UCS-2 characters encoded into UTF-8 can use up to 768 UTF-8 chars
|
||||
#define MAX_ALIAS_LENGTH 13
|
||||
#define LFN_ENTRY_LENGTH 13
|
||||
#define ALIAS_ENTRY_LENGTH 11
|
||||
@ -49,60 +49,66 @@
|
||||
#define DIR_SEPARATOR '/'
|
||||
|
||||
// File attributes
|
||||
#define ATTRIB_ARCH 0x20 // Archive
|
||||
#define ATTRIB_DIR 0x10 // Directory
|
||||
#define ATTRIB_LFN 0x0F // Long file name
|
||||
#define ATTRIB_VOL 0x08 // Volume
|
||||
#define ATTRIB_SYS 0x04 // System
|
||||
#define ATTRIB_HID 0x02 // Hidden
|
||||
#define ATTRIB_RO 0x01 // Read only
|
||||
#define ATTRIB_ARCH 0x20 // Archive
|
||||
#define ATTRIB_DIR 0x10 // Directory
|
||||
#define ATTRIB_LFN 0x0F // Long file name
|
||||
#define ATTRIB_VOL 0x08 // Volume
|
||||
#define ATTRIB_SYS 0x04 // System
|
||||
#define ATTRIB_HID 0x02 // Hidden
|
||||
#define ATTRIB_RO 0x01 // Read only
|
||||
|
||||
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
uint32_t cluster;
|
||||
sec_t sector;
|
||||
int32_t offset;
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cluster;
|
||||
sec_t sector;
|
||||
int32_t offset;
|
||||
} DIR_ENTRY_POSITION;
|
||||
|
||||
typedef struct {
|
||||
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
||||
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
|
||||
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
|
||||
char filename[MAX_FILENAME_LENGTH];
|
||||
typedef struct
|
||||
{
|
||||
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
||||
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
|
||||
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
|
||||
char filename[MAX_FILENAME_LENGTH];
|
||||
} DIR_ENTRY;
|
||||
|
||||
// Directory entry offsets
|
||||
enum DIR_ENTRY_offset {
|
||||
DIR_ENTRY_name = 0x00,
|
||||
DIR_ENTRY_extension = 0x08,
|
||||
DIR_ENTRY_attributes = 0x0B,
|
||||
DIR_ENTRY_reserved = 0x0C,
|
||||
DIR_ENTRY_cTime_ms = 0x0D,
|
||||
DIR_ENTRY_cTime = 0x0E,
|
||||
DIR_ENTRY_cDate = 0x10,
|
||||
DIR_ENTRY_aDate = 0x12,
|
||||
DIR_ENTRY_clusterHigh = 0x14,
|
||||
DIR_ENTRY_mTime = 0x16,
|
||||
DIR_ENTRY_mDate = 0x18,
|
||||
DIR_ENTRY_cluster = 0x1A,
|
||||
DIR_ENTRY_fileSize = 0x1C
|
||||
enum DIR_ENTRY_offset
|
||||
{
|
||||
DIR_ENTRY_name = 0x00,
|
||||
DIR_ENTRY_extension = 0x08,
|
||||
DIR_ENTRY_attributes = 0x0B,
|
||||
DIR_ENTRY_reserved = 0x0C,
|
||||
DIR_ENTRY_cTime_ms = 0x0D,
|
||||
DIR_ENTRY_cTime = 0x0E,
|
||||
DIR_ENTRY_cDate = 0x10,
|
||||
DIR_ENTRY_aDate = 0x12,
|
||||
DIR_ENTRY_clusterHigh = 0x14,
|
||||
DIR_ENTRY_mTime = 0x16,
|
||||
DIR_ENTRY_mDate = 0x18,
|
||||
DIR_ENTRY_cluster = 0x1A,
|
||||
DIR_ENTRY_fileSize = 0x1C
|
||||
};
|
||||
|
||||
/*
|
||||
Returns true if the file specified by entry is a directory
|
||||
*/
|
||||
static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) {
|
||||
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) != 0);
|
||||
static inline bool _FAT_directory_isDirectory ( DIR_ENTRY* entry )
|
||||
{
|
||||
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR ) != 0 );
|
||||
}
|
||||
|
||||
static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) {
|
||||
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO) == 0);
|
||||
static inline bool _FAT_directory_isWritable ( DIR_ENTRY* entry )
|
||||
{
|
||||
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO ) == 0 );
|
||||
}
|
||||
|
||||
static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) {
|
||||
return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') ||
|
||||
((entry->filename[1] == '.') && entry->filename[2] == '\0')));
|
||||
static inline bool _FAT_directory_isDot ( DIR_ENTRY* entry )
|
||||
{
|
||||
return ( ( entry->filename[0] == '.' ) && ( ( entry->filename[1] == '\0' ) ||
|
||||
( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -111,7 +117,7 @@ Places result in entry
|
||||
entry will be destroyed even if no directory entry is found
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
|
||||
bool _FAT_directory_getFirstEntry ( PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster );
|
||||
|
||||
/*
|
||||
Reads the next directory entry after the one already pointed to by entry
|
||||
@ -119,7 +125,7 @@ Places result in entry
|
||||
entry will be destroyed even if no directory entry is found
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry);
|
||||
bool _FAT_directory_getNextEntry ( PARTITION* partition, DIR_ENTRY* entry );
|
||||
|
||||
/*
|
||||
Gets the directory entry corrsponding to the supplied path
|
||||
@ -130,20 +136,20 @@ pathEnd specifies the end of the path string, for cutting strings short if neede
|
||||
after pathEND.
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd);
|
||||
bool _FAT_directory_entryFromPath ( PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd );
|
||||
|
||||
/*
|
||||
Changes the current directory to the one specified by path
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_chdir (PARTITION* partition, const char* path);
|
||||
bool _FAT_directory_chdir ( PARTITION* partition, const char* path );
|
||||
|
||||
/*
|
||||
Removes the directory entry specified by entry
|
||||
Assumes that entry is valid
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry);
|
||||
bool _FAT_directory_removeEntry ( PARTITION* partition, DIR_ENTRY* entry );
|
||||
|
||||
/*
|
||||
Add a directory entry to the directory specified by dirCluster
|
||||
@ -151,23 +157,23 @@ The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are
|
||||
updated with the new directory entry position and alias.
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
|
||||
bool _FAT_directory_addEntry ( PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster );
|
||||
|
||||
/*
|
||||
Get the start cluster of a file from it's entry data
|
||||
*/
|
||||
uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData);
|
||||
uint32_t _FAT_directory_entryGetCluster ( PARTITION* partition, const uint8_t* entryData );
|
||||
|
||||
/*
|
||||
Fill in the file name and entry data of DIR_ENTRY* entry.
|
||||
Assumes that the entry's dataStart and dataEnd are correct
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry);
|
||||
bool _FAT_directory_entryFromPosition ( PARTITION* partition, DIR_ENTRY* entry );
|
||||
|
||||
/*
|
||||
Fill in a stat struct based on a file entry
|
||||
*/
|
||||
void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st);
|
||||
void _FAT_directory_entryStat ( PARTITION* partition, DIR_ENTRY* entry, struct stat *st );
|
||||
|
||||
#endif // _DIRECTORY_H
|
||||
|
@ -35,9 +35,10 @@
|
||||
A list of all default devices to try at startup,
|
||||
terminated by a {NULL,NULL} entry.
|
||||
*/
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const DISC_INTERFACE* (*getInterface)(void);
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const DISC_INTERFACE* ( *getInterface )( void );
|
||||
} INTERFACE_ID;
|
||||
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
|
||||
@ -45,8 +46,9 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
Check if a disc is inserted
|
||||
Return true if a disc is inserted and ready, false otherwise
|
||||
*/
|
||||
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) {
|
||||
return disc->isInserted();
|
||||
static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->isInserted();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -56,8 +58,9 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to fill
|
||||
*/
|
||||
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) {
|
||||
return disc->readSectors (sector, numSectors, buffer);
|
||||
static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
|
||||
{
|
||||
return disc->readSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -67,44 +70,50 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to read from
|
||||
*/
|
||||
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) {
|
||||
return disc->writeSectors (sector, numSectors, buffer);
|
||||
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
{
|
||||
return disc->writeSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
Reset the card back to a ready state
|
||||
*/
|
||||
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) {
|
||||
return disc->clearStatus();
|
||||
static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->clearStatus();
|
||||
}
|
||||
|
||||
/*
|
||||
Initialise the disc to a state ready for data reading or writing
|
||||
*/
|
||||
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
return disc->startup();
|
||||
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->startup();
|
||||
}
|
||||
|
||||
/*
|
||||
Put the disc in a state ready for power down.
|
||||
Complete any pending writes and disable the disc if necessary
|
||||
*/
|
||||
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) {
|
||||
return disc->shutdown();
|
||||
static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value unique to each type of interface
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) {
|
||||
return disc->ioType;
|
||||
static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->ioType;
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value that specifies the capabilities of the disc
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) {
|
||||
return disc->features;
|
||||
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->features;
|
||||
}
|
||||
|
||||
#endif // _DISC_H
|
||||
|
@ -43,25 +43,30 @@ The list is terminated by a NULL/NULL entry.
|
||||
#include "usbloader/usbstorage2.h"
|
||||
#include <sdcard/gcsd.h>
|
||||
|
||||
static const DISC_INTERFACE* get_io_wiisd (void) {
|
||||
return &__io_wiisd;
|
||||
static const DISC_INTERFACE* get_io_wiisd ( void )
|
||||
{
|
||||
return &__io_wiisd;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_usbstorage (void) {
|
||||
return &__io_usbstorage2;
|
||||
static const DISC_INTERFACE* get_io_usbstorage ( void )
|
||||
{
|
||||
return &__io_usbstorage2;
|
||||
}
|
||||
|
||||
static const DISC_INTERFACE* get_io_gcsda (void) {
|
||||
return &__io_gcsda;
|
||||
static const DISC_INTERFACE* get_io_gcsda ( void )
|
||||
{
|
||||
return &__io_gcsda;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_gcsdb (void) {
|
||||
return &__io_gcsdb;
|
||||
static const DISC_INTERFACE* get_io_gcsdb ( void )
|
||||
{
|
||||
return &__io_gcsdb;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
{"sd", get_io_wiisd},
|
||||
{"usb", get_io_usbstorage},
|
||||
{"carda", get_io_gcsda},
|
||||
{"cardb", get_io_gcsdb},
|
||||
{NULL, NULL}
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] =
|
||||
{
|
||||
{"sd", get_io_wiisd},
|
||||
{"usb", get_io_usbstorage},
|
||||
{"carda", get_io_gcsda},
|
||||
{"cardb", get_io_gcsdb},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -35,9 +35,10 @@
|
||||
A list of all default devices to try at startup,
|
||||
terminated by a {NULL,NULL} entry.
|
||||
*/
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const DISC_INTERFACE* (*getInterface)(void);
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const DISC_INTERFACE* ( *getInterface )( void );
|
||||
} INTERFACE_ID;
|
||||
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
|
||||
@ -45,8 +46,9 @@ extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
Check if a disc is inserted
|
||||
Return true if a disc is inserted and ready, false otherwise
|
||||
*/
|
||||
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) {
|
||||
return disc->isInserted();
|
||||
static inline bool _FAT_disc_isInserted ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->isInserted();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -56,8 +58,9 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to fill
|
||||
*/
|
||||
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) {
|
||||
return disc->readSectors (sector, numSectors, buffer);
|
||||
static inline bool _FAT_disc_readSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer )
|
||||
{
|
||||
return disc->readSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -67,44 +70,50 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to read from
|
||||
*/
|
||||
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) {
|
||||
return disc->writeSectors (sector, numSectors, buffer);
|
||||
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
{
|
||||
return disc->writeSectors ( sector, numSectors, buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
Reset the card back to a ready state
|
||||
*/
|
||||
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) {
|
||||
return disc->clearStatus();
|
||||
static inline bool _FAT_disc_clearStatus ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->clearStatus();
|
||||
}
|
||||
|
||||
/*
|
||||
Initialise the disc to a state ready for data reading or writing
|
||||
*/
|
||||
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
return disc->startup();
|
||||
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->startup();
|
||||
}
|
||||
|
||||
/*
|
||||
Put the disc in a state ready for power down.
|
||||
Complete any pending writes and disable the disc if necessary
|
||||
*/
|
||||
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) {
|
||||
return disc->shutdown();
|
||||
static inline bool _FAT_disc_shutdown ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value unique to each type of interface
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) {
|
||||
return disc->ioType;
|
||||
static inline uint32_t _FAT_disc_hostType ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->ioType;
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value that specifies the capabilities of the disc
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) {
|
||||
return disc->features;
|
||||
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->features;
|
||||
}
|
||||
|
||||
#endif // _DISC_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
fat.h
|
||||
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||
fat.h
|
||||
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
@ -31,47 +31,48 @@
|
||||
#define _LIBFAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ogc/disc_io.h>
|
||||
|
||||
/*
|
||||
Initialise any inserted block-devices.
|
||||
Add the fat device driver to the devoptab, making it available for standard file functions.
|
||||
cacheSize: The number of pages to allocate for each inserted block-device
|
||||
setAsDefaultDevice: if true, make this the default device driver for file operations
|
||||
*/
|
||||
extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
|
||||
/*
|
||||
Initialise any inserted block-devices.
|
||||
Add the fat device driver to the devoptab, making it available for standard file functions.
|
||||
cacheSize: The number of pages to allocate for each inserted block-device
|
||||
setAsDefaultDevice: if true, make this the default device driver for file operations
|
||||
*/
|
||||
extern bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice );
|
||||
|
||||
/*
|
||||
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
|
||||
*/
|
||||
extern bool fatInitDefault (void);
|
||||
/*
|
||||
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
|
||||
*/
|
||||
extern bool fatInitDefault ( void );
|
||||
|
||||
/*
|
||||
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||
You can then access the filesystem using "name:/".
|
||||
This will mount the active partition or the first valid partition on the disc,
|
||||
and will use a cache size optimized for the host system.
|
||||
*/
|
||||
extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface);
|
||||
/*
|
||||
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||
You can then access the filesystem using "name:/".
|
||||
This will mount the active partition or the first valid partition on the disc,
|
||||
and will use a cache size optimized for the host system.
|
||||
*/
|
||||
extern bool fatMountSimple ( const char* name, const DISC_INTERFACE* interface );
|
||||
|
||||
/*
|
||||
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||
You can then access the filesystem using "name:/".
|
||||
If startSector = 0, it will mount the active partition of the first valid partition on
|
||||
the disc. Otherwise it will try to mount the partition starting at startSector.
|
||||
cacheSize specifies the number of pages to allocate for the cache.
|
||||
This will not startup the disc, so you need to call interface->startup(); first.
|
||||
*/
|
||||
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage);
|
||||
/*
|
||||
Unmount the partition specified by name.
|
||||
If there are open files, it will attempt to synchronise them to disc.
|
||||
*/
|
||||
extern void fatUnmount (const char* name);
|
||||
/*
|
||||
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||
You can then access the filesystem using "name:/".
|
||||
If startSector = 0, it will mount the active partition of the first valid partition on
|
||||
the disc. Otherwise it will try to mount the partition starting at startSector.
|
||||
cacheSize specifies the number of pages to allocate for the cache.
|
||||
This will not startup the disc, so you need to call interface->startup(); first.
|
||||
*/
|
||||
extern bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage );
|
||||
/*
|
||||
Unmount the partition specified by name.
|
||||
If there are open files, it will attempt to synchronise them to disc.
|
||||
*/
|
||||
extern void fatUnmount ( const char* name );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -46,321 +46,356 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition) {
|
||||
CACHE* cache;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition )
|
||||
{
|
||||
CACHE* cache;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if (numberOfPages < 2) {
|
||||
numberOfPages = 2;
|
||||
}
|
||||
if ( numberOfPages < 2 )
|
||||
{
|
||||
numberOfPages = 2;
|
||||
}
|
||||
|
||||
if (sectorsPerPage < 8) {
|
||||
sectorsPerPage = 8;
|
||||
}
|
||||
if ( sectorsPerPage < 8 )
|
||||
{
|
||||
sectorsPerPage = 8;
|
||||
}
|
||||
|
||||
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) );
|
||||
if ( cache == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache->disc = discInterface;
|
||||
cache->endOfPartition = endOfPartition;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
cache->disc = discInterface;
|
||||
cache->endOfPartition = endOfPartition;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
|
||||
|
||||
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL) {
|
||||
_FAT_mem_free (cache);
|
||||
return NULL;
|
||||
}
|
||||
cacheEntries = ( CACHE_ENTRY* ) _FAT_mem_allocate ( sizeof( CACHE_ENTRY ) * numberOfPages );
|
||||
if ( cacheEntries == NULL )
|
||||
{
|
||||
_FAT_mem_free ( cache );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numberOfPages; i++) {
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = (uint8_t*) _FAT_mem_align ( sectorsPerPage * BYTES_PER_READ );
|
||||
}
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = ( uint8_t* ) _FAT_mem_align ( sectorsPerPage * BYTES_PER_READ );
|
||||
}
|
||||
|
||||
cache->cacheEntries = cacheEntries;
|
||||
cache->cacheEntries = cacheEntries;
|
||||
|
||||
return cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache) {
|
||||
unsigned int i;
|
||||
// Clear out cache before destroying it
|
||||
_FAT_cache_flush(cache);
|
||||
void _FAT_cache_destructor ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
// Clear out cache before destroying it
|
||||
_FAT_cache_flush( cache );
|
||||
|
||||
// Free memory in reverse allocation order
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
_FAT_mem_free (cache->cacheEntries[i].cache);
|
||||
}
|
||||
_FAT_mem_free (cache->cacheEntries);
|
||||
_FAT_mem_free (cache);
|
||||
// Free memory in reverse allocation order
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
_FAT_mem_free ( cache->cacheEntries[i].cache );
|
||||
}
|
||||
_FAT_mem_free ( cache->cacheEntries );
|
||||
_FAT_mem_free ( cache );
|
||||
}
|
||||
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
static u32 accessTime()
|
||||
{
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
|
||||
static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector)
|
||||
static CACHE_ENTRY* _FAT_cache_getPage( CACHE *cache, sec_t sector )
|
||||
{
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &(cacheEntries[i]);
|
||||
}
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
||||
{
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &( cacheEntries[i] );
|
||||
}
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
||||
{
|
||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||
if(!_FAT_disc_writeSectors(cache->disc,cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
||||
{
|
||||
if ( !_FAT_disc_writeSectors( cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
|
||||
sector = (sector/sectorsPerPage)*sectorsPerPage; // align base sector to page size
|
||||
sec_t next_page = sector + sectorsPerPage;
|
||||
if(next_page > cache->endOfPartition) next_page = cache->endOfPartition;
|
||||
sector = ( sector / sectorsPerPage ) * sectorsPerPage; // align base sector to page size
|
||||
sec_t next_page = sector + sectorsPerPage;
|
||||
if ( next_page > cache->endOfPartition ) next_page = cache->endOfPartition;
|
||||
|
||||
if(!_FAT_disc_readSectors(cache->disc,sector,next_page-sector,cacheEntries[oldUsed].cache)) return NULL;
|
||||
if ( !_FAT_disc_readSectors( cache->disc, sector, next_page - sector, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = next_page-sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = next_page - sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
|
||||
return &(cacheEntries[oldUsed]);
|
||||
return &( cacheEntries[oldUsed] );
|
||||
}
|
||||
|
||||
bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
|
||||
bool _FAT_cache_readSectors( CACHE *cache, sec_t sector, sec_t numSectors, void *buffer )
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_read;
|
||||
CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
sec_t sec;
|
||||
sec_t secs_to_read;
|
||||
CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
|
||||
while(numSectors>0) {
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _FAT_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_read = entry->count - sec;
|
||||
if(secs_to_read>numSectors) secs_to_read = numSectors;
|
||||
sec = sector - entry->sector;
|
||||
secs_to_read = entry->count - sec;
|
||||
if ( secs_to_read > numSectors ) secs_to_read = numSectors;
|
||||
|
||||
memcpy(dest,entry->cache + (sec*BYTES_PER_READ),(secs_to_read*BYTES_PER_READ));
|
||||
memcpy( dest, entry->cache + ( sec*BYTES_PER_READ ), ( secs_to_read*BYTES_PER_READ ) );
|
||||
|
||||
dest += (secs_to_read*BYTES_PER_READ);
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
dest += ( secs_to_read * BYTES_PER_READ );
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Reads some data from a cache page, determined by the sector number
|
||||
*/
|
||||
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _FAT_cache_readPartialSector ( CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
{
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > BYTES_PER_READ) return false;
|
||||
if ( offset + size > BYTES_PER_READ ) return false;
|
||||
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
entry = _FAT_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy(buffer,entry->cache + ((sec*BYTES_PER_READ) + offset),size);
|
||||
sec = sector - entry->sector;
|
||||
memcpy( buffer, entry->cache + ( ( sec*BYTES_PER_READ ) + offset ), size );
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
uint8_t buf[4];
|
||||
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||
bool _FAT_cache_readLittleEndianValue ( CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if ( !_FAT_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||
|
||||
switch(num_bytes) {
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16(buf,0); break;
|
||||
case 4: *value = u8array_to_u32(buf,0); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
switch ( num_bytes )
|
||||
{
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||
*/
|
||||
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _FAT_cache_writePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
{
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > BYTES_PER_READ) return false;
|
||||
if ( offset + size > BYTES_PER_READ ) return false;
|
||||
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
entry = _FAT_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy(entry->cache + ((sec*BYTES_PER_READ) + offset),buffer,size);
|
||||
sec = sector - entry->sector;
|
||||
memcpy( entry->cache + ( ( sec*BYTES_PER_READ ) + offset ), buffer, size );
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
||||
{
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
|
||||
switch(size) {
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array(buf, 0, value); break;
|
||||
case 4: u32_to_u8array(buf, 0, value); break;
|
||||
default: return false;
|
||||
}
|
||||
switch ( size )
|
||||
{
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return _FAT_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
return _FAT_cache_writePartialSector( cache, buf, sector, offset, size );
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, zeroing out the page first
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _FAT_cache_eraseWritePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
{
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > BYTES_PER_READ) return false;
|
||||
if ( offset + size > BYTES_PER_READ ) return false;
|
||||
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
entry = _FAT_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memset(entry->cache + (sec*BYTES_PER_READ),0,BYTES_PER_READ);
|
||||
memcpy(entry->cache + ((sec*BYTES_PER_READ) + offset),buffer,size);
|
||||
sec = sector - entry->sector;
|
||||
memset( entry->cache + ( sec*BYTES_PER_READ ), 0, BYTES_PER_READ );
|
||||
memcpy( entry->cache + ( ( sec*BYTES_PER_READ ) + offset ), buffer, size );
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count) {
|
||||
static CACHE_ENTRY* _FAT_cache_findPage( CACHE *cache, sec_t sector, sec_t count )
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||
{
|
||||
bool intersect;
|
||||
if ( sector > cacheEntries[i].sector )
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
bool _FAT_cache_writeSectors ( CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
CACHE_ENTRY* entry;
|
||||
const uint8_t *src = buffer;
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
CACHE_ENTRY* entry;
|
||||
const uint8_t *src = buffer;
|
||||
|
||||
while(numSectors>0)
|
||||
{
|
||||
entry = _FAT_cache_findPage(cache,sector,numSectors);
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _FAT_cache_findPage( cache, sector, numSectors );
|
||||
|
||||
if(entry!=NULL) {
|
||||
if ( entry != NULL )
|
||||
{
|
||||
|
||||
if ( entry->sector > sector) {
|
||||
if ( entry->sector > sector )
|
||||
{
|
||||
|
||||
secs_to_write = entry->sector - sector;
|
||||
secs_to_write = entry->sector - sector;
|
||||
|
||||
_FAT_disc_writeSectors(cache->disc,sector,secs_to_write,src);
|
||||
src += (secs_to_write*BYTES_PER_READ);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
_FAT_disc_writeSectors( cache->disc, sector, secs_to_write, src );
|
||||
src += ( secs_to_write * BYTES_PER_READ );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
|
||||
if(secs_to_write>numSectors) secs_to_write = numSectors;
|
||||
if ( secs_to_write > numSectors ) secs_to_write = numSectors;
|
||||
|
||||
memcpy(entry->cache + (sec*BYTES_PER_READ),src,(secs_to_write*BYTES_PER_READ));
|
||||
memcpy( entry->cache + ( sec*BYTES_PER_READ ), src, ( secs_to_write*BYTES_PER_READ ) );
|
||||
|
||||
src += (secs_to_write*BYTES_PER_READ);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
src += ( secs_to_write * BYTES_PER_READ );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
_FAT_disc_writeSectors(cache->disc,sector,numSectors,src);
|
||||
numSectors=0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_FAT_disc_writeSectors( cache->disc, sector, numSectors, src );
|
||||
numSectors = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache) {
|
||||
unsigned int i;
|
||||
bool _FAT_cache_flush ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
if (cache->cacheEntries[i].dirty) {
|
||||
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
if ( cache->cacheEntries[i].dirty )
|
||||
{
|
||||
if ( !_FAT_disc_writeSectors ( cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void _FAT_cache_invalidate (CACHE* cache) {
|
||||
unsigned int i;
|
||||
_FAT_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
void _FAT_cache_invalidate ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
_FAT_cache_flush( cache );
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -42,20 +42,22 @@
|
||||
#define PAGE_SECTORS 64
|
||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||
|
||||
typedef struct {
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
bool dirty;
|
||||
uint8_t* cache;
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
bool dirty;
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
} CACHE;
|
||||
|
||||
/*
|
||||
@ -65,9 +67,9 @@ offset is the position to start reading from
|
||||
size is the amount of data to read
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
bool _FAT_cache_readPartialSector ( CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
|
||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes);
|
||||
bool _FAT_cache_readLittleEndianValue ( CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes );
|
||||
|
||||
/*
|
||||
Write data to a sector in the cache
|
||||
@ -77,9 +79,9 @@ offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
bool _FAT_cache_writePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
|
||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes);
|
||||
bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes );
|
||||
|
||||
/*
|
||||
Write data to a sector in the cache, zeroing the sector first
|
||||
@ -89,42 +91,44 @@ offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
bool _FAT_cache_eraseWritePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
|
||||
/*
|
||||
Read several sectors from the cache
|
||||
*/
|
||||
bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer);
|
||||
bool _FAT_cache_readSectors ( CACHE* cache, sec_t sector, sec_t numSectors, void* buffer );
|
||||
|
||||
/*
|
||||
Read a full sector from the cache
|
||||
*/
|
||||
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) {
|
||||
return _FAT_cache_readPartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
|
||||
static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
|
||||
{
|
||||
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||
}
|
||||
|
||||
/*
|
||||
Write a full sector to the cache
|
||||
*/
|
||||
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) {
|
||||
return _FAT_cache_writePartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
|
||||
static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
|
||||
{
|
||||
return _FAT_cache_writePartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
bool _FAT_cache_writeSectors ( CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer );
|
||||
|
||||
/*
|
||||
Write any dirty sectors back to disc and clear out the contents of the cache
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache);
|
||||
bool _FAT_cache_flush ( CACHE* cache );
|
||||
|
||||
/*
|
||||
Clear out the contents of the cache without writing any dirty sectors first
|
||||
*/
|
||||
void _FAT_cache_invalidate (CACHE* cache);
|
||||
void _FAT_cache_invalidate ( CACHE* cache );
|
||||
|
||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition);
|
||||
CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition );
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache);
|
||||
void _FAT_cache_destructor ( CACHE* cache );
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,35 +39,36 @@
|
||||
#include "common.h"
|
||||
#include "directory.h"
|
||||
|
||||
typedef struct {
|
||||
PARTITION* partition;
|
||||
DIR_ENTRY currentEntry;
|
||||
uint32_t startCluster;
|
||||
bool inUse;
|
||||
bool validEntry;
|
||||
typedef struct
|
||||
{
|
||||
PARTITION* partition;
|
||||
DIR_ENTRY currentEntry;
|
||||
uint32_t startCluster;
|
||||
bool inUse;
|
||||
bool validEntry;
|
||||
} DIR_STATE_STRUCT;
|
||||
|
||||
extern int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st);
|
||||
extern int _FAT_stat_r ( struct _reent *r, const char *path, struct stat *st );
|
||||
|
||||
extern int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink);
|
||||
extern int _FAT_link_r ( struct _reent *r, const char *existing, const char *newLink );
|
||||
|
||||
extern int _FAT_unlink_r (struct _reent *r, const char *name);
|
||||
extern int _FAT_unlink_r ( struct _reent *r, const char *name );
|
||||
|
||||
extern int _FAT_chdir_r (struct _reent *r, const char *name);
|
||||
extern int _FAT_chdir_r ( struct _reent *r, const char *name );
|
||||
|
||||
extern int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName);
|
||||
extern int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName );
|
||||
|
||||
extern int _FAT_mkdir_r (struct _reent *r, const char *path, int mode);
|
||||
extern int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode );
|
||||
|
||||
extern int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf);
|
||||
extern int _FAT_statvfs_r ( struct _reent *r, const char *path, struct statvfs *buf );
|
||||
|
||||
/*
|
||||
Directory iterator functions
|
||||
*/
|
||||
extern DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path);
|
||||
extern int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState);
|
||||
extern int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
|
||||
extern int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState);
|
||||
extern DIR_ITER* _FAT_diropen_r( struct _reent *r, DIR_ITER *dirState, const char *path );
|
||||
extern int _FAT_dirreset_r ( struct _reent *r, DIR_ITER *dirState );
|
||||
extern int _FAT_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat );
|
||||
extern int _FAT_dirclose_r ( struct _reent *r, DIR_ITER *dirState );
|
||||
|
||||
|
||||
#endif // _FATDIR_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,67 +39,69 @@
|
||||
#include "partition.h"
|
||||
#include "directory.h"
|
||||
|
||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
||||
|
||||
typedef struct {
|
||||
u32 cluster;
|
||||
sec_t sector;
|
||||
s32 byte;
|
||||
typedef struct
|
||||
{
|
||||
u32 cluster;
|
||||
sec_t sector;
|
||||
s32 byte;
|
||||
} FILE_POSITION;
|
||||
|
||||
struct _FILE_STRUCT;
|
||||
|
||||
struct _FILE_STRUCT {
|
||||
uint32_t filesize;
|
||||
uint32_t startCluster;
|
||||
uint32_t currentPosition;
|
||||
FILE_POSITION rwPosition;
|
||||
FILE_POSITION appendPosition;
|
||||
DIR_ENTRY_POSITION dirEntryStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
|
||||
DIR_ENTRY_POSITION dirEntryEnd; // Always points to the file's alias entry
|
||||
PARTITION* partition;
|
||||
struct _FILE_STRUCT* prevOpenFile; // The previous entry in a double-linked list of open files
|
||||
struct _FILE_STRUCT* nextOpenFile; // The next entry in a double-linked list of open files
|
||||
bool read;
|
||||
bool write;
|
||||
bool append;
|
||||
bool inUse;
|
||||
bool modified;
|
||||
struct _FILE_STRUCT
|
||||
{
|
||||
uint32_t filesize;
|
||||
uint32_t startCluster;
|
||||
uint32_t currentPosition;
|
||||
FILE_POSITION rwPosition;
|
||||
FILE_POSITION appendPosition;
|
||||
DIR_ENTRY_POSITION dirEntryStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
|
||||
DIR_ENTRY_POSITION dirEntryEnd; // Always points to the file's alias entry
|
||||
PARTITION* partition;
|
||||
struct _FILE_STRUCT* prevOpenFile; // The previous entry in a double-linked list of open files
|
||||
struct _FILE_STRUCT* nextOpenFile; // The next entry in a double-linked list of open files
|
||||
bool read;
|
||||
bool write;
|
||||
bool append;
|
||||
bool inUse;
|
||||
bool modified;
|
||||
};
|
||||
|
||||
typedef struct _FILE_STRUCT FILE_STRUCT;
|
||||
|
||||
extern int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
|
||||
extern int _FAT_open_r ( struct _reent *r, void *fileStruct, const char *path, int flags, int mode );
|
||||
|
||||
extern int _FAT_close_r (struct _reent *r, int fd);
|
||||
extern int _FAT_close_r ( struct _reent *r, int fd );
|
||||
|
||||
extern ssize_t _FAT_write_r (struct _reent *r,int fd, const char *ptr, size_t len);
|
||||
extern ssize_t _FAT_write_r ( struct _reent *r, int fd, const char *ptr, size_t len );
|
||||
|
||||
extern ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len);
|
||||
extern ssize_t _FAT_read_r ( struct _reent *r, int fd, char *ptr, size_t len );
|
||||
|
||||
extern off_t _FAT_seek_r (struct _reent *r, int fd, off_t pos, int dir);
|
||||
extern off_t _FAT_seek_r ( struct _reent *r, int fd, off_t pos, int dir );
|
||||
|
||||
extern int _FAT_fstat_r (struct _reent *r, int fd, struct stat *st);
|
||||
extern int _FAT_fstat_r ( struct _reent *r, int fd, struct stat *st );
|
||||
|
||||
extern int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st);
|
||||
extern int _FAT_stat_r ( struct _reent *r, const char *path, struct stat *st );
|
||||
|
||||
extern int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink);
|
||||
extern int _FAT_link_r ( struct _reent *r, const char *existing, const char *newLink );
|
||||
|
||||
extern int _FAT_unlink_r (struct _reent *r, const char *name);
|
||||
extern int _FAT_unlink_r ( struct _reent *r, const char *name );
|
||||
|
||||
extern int _FAT_chdir_r (struct _reent *r, const char *name);
|
||||
extern int _FAT_chdir_r ( struct _reent *r, const char *name );
|
||||
|
||||
extern int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName);
|
||||
extern int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName );
|
||||
|
||||
extern int _FAT_ftruncate_r (struct _reent *r, int fd, off_t len);
|
||||
extern int _FAT_ftruncate_r ( struct _reent *r, int fd, off_t len );
|
||||
|
||||
extern int _FAT_fsync_r (struct _reent *r, int fd);
|
||||
extern int _FAT_fsync_r ( struct _reent *r, int fd );
|
||||
|
||||
/*
|
||||
Synchronizes the file data to disc.
|
||||
Does no locking of its own -- lock the partition before calling.
|
||||
Returns 0 on success, an error code on failure.
|
||||
*/
|
||||
extern int _FAT_syncToDisc (FILE_STRUCT* file);
|
||||
extern int _FAT_syncToDisc ( FILE_STRUCT* file );
|
||||
|
||||
#endif // _FATFILE_H
|
||||
|
@ -35,166 +35,179 @@
|
||||
/*
|
||||
Gets the cluster linked from input cluster
|
||||
*/
|
||||
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||
uint32_t _FAT_fat_nextCluster( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t nextCluster = CLUSTER_FREE;
|
||||
sec_t sector;
|
||||
int offset;
|
||||
uint32_t nextCluster = CLUSTER_FREE;
|
||||
sec_t sector;
|
||||
int offset;
|
||||
|
||||
if (cluster == CLUSTER_FREE) {
|
||||
return CLUSTER_FREE;
|
||||
}
|
||||
if ( cluster == CLUSTER_FREE )
|
||||
{
|
||||
return CLUSTER_FREE;
|
||||
}
|
||||
|
||||
switch (partition->filesysType)
|
||||
{
|
||||
case FS_UNKNOWN:
|
||||
return CLUSTER_ERROR;
|
||||
break;
|
||||
switch ( partition->filesysType )
|
||||
{
|
||||
case FS_UNKNOWN:
|
||||
return CLUSTER_ERROR;
|
||||
break;
|
||||
|
||||
case FS_FAT12:
|
||||
{
|
||||
u32 nextCluster_h;
|
||||
sector = partition->fat.fatStart + (((cluster * 3) / 2) / BYTES_PER_READ);
|
||||
offset = ((cluster * 3) / 2) % BYTES_PER_READ;
|
||||
case FS_FAT12:
|
||||
{
|
||||
u32 nextCluster_h;
|
||||
sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ );
|
||||
offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ;
|
||||
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u8));
|
||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u8 ) );
|
||||
|
||||
offset++;
|
||||
offset++;
|
||||
|
||||
if (offset >= BYTES_PER_READ) {
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
nextCluster_h = 0;
|
||||
if ( offset >= BYTES_PER_READ )
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
nextCluster_h = 0;
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster_h, sector, offset, sizeof(u8));
|
||||
nextCluster |= (nextCluster_h << 8);
|
||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster_h, sector, offset, sizeof( u8 ) );
|
||||
nextCluster |= ( nextCluster_h << 8 );
|
||||
|
||||
if (cluster & 0x01) {
|
||||
nextCluster = nextCluster >> 4;
|
||||
} else {
|
||||
nextCluster &= 0x0FFF;
|
||||
}
|
||||
if ( cluster & 0x01 )
|
||||
{
|
||||
nextCluster = nextCluster >> 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextCluster &= 0x0FFF;
|
||||
}
|
||||
|
||||
if (nextCluster >= 0x0FF7)
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
if ( nextCluster >= 0x0FF7 )
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ((cluster << 1) / BYTES_PER_READ);
|
||||
offset = (cluster % (BYTES_PER_READ >> 1)) << 1;
|
||||
break;
|
||||
}
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ( ( cluster << 1 ) / BYTES_PER_READ );
|
||||
offset = ( cluster % ( BYTES_PER_READ >> 1 ) ) << 1;
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u16));
|
||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u16 ) );
|
||||
|
||||
if (nextCluster >= 0xFFF7) {
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
break;
|
||||
if ( nextCluster >= 0xFFF7 )
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
break;
|
||||
|
||||
case FS_FAT32:
|
||||
sector = partition->fat.fatStart + ((cluster << 2) / BYTES_PER_READ);
|
||||
offset = (cluster % (BYTES_PER_READ >> 2)) << 2;
|
||||
case FS_FAT32:
|
||||
sector = partition->fat.fatStart + ( ( cluster << 2 ) / BYTES_PER_READ );
|
||||
offset = ( cluster % ( BYTES_PER_READ >> 2 ) ) << 2;
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u32));
|
||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u32 ) );
|
||||
|
||||
if (nextCluster >= 0x0FFFFFF7) {
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
break;
|
||||
if ( nextCluster >= 0x0FFFFFF7 )
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return CLUSTER_ERROR;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return CLUSTER_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return nextCluster;
|
||||
return nextCluster;
|
||||
}
|
||||
|
||||
/*
|
||||
writes value into the correct offset within a partition's FAT, based
|
||||
on the cluster number.
|
||||
*/
|
||||
static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value) {
|
||||
sec_t sector;
|
||||
int offset;
|
||||
uint32_t oldValue;
|
||||
static bool _FAT_fat_writeFatEntry ( PARTITION* partition, uint32_t cluster, uint32_t value )
|
||||
{
|
||||
sec_t sector;
|
||||
int offset;
|
||||
uint32_t oldValue;
|
||||
|
||||
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (partition->filesysType)
|
||||
{
|
||||
case FS_UNKNOWN:
|
||||
return false;
|
||||
break;
|
||||
switch ( partition->filesysType )
|
||||
{
|
||||
case FS_UNKNOWN:
|
||||
return false;
|
||||
break;
|
||||
|
||||
case FS_FAT12:
|
||||
sector = partition->fat.fatStart + (((cluster * 3) / 2) / BYTES_PER_READ);
|
||||
offset = ((cluster * 3) / 2) % BYTES_PER_READ;
|
||||
case FS_FAT12:
|
||||
sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ );
|
||||
offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ;
|
||||
|
||||
if (cluster & 0x01) {
|
||||
if ( cluster & 0x01 )
|
||||
{
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8));
|
||||
_FAT_cache_readLittleEndianValue ( partition->cache, &oldValue, sector, offset, sizeof( u8 ) );
|
||||
|
||||
value = (value << 4) | (oldValue & 0x0F);
|
||||
value = ( value << 4 ) | ( oldValue & 0x0F );
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value & 0xFF, sector, offset, sizeof(u8));
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value & 0xFF, sector, offset, sizeof( u8 ) );
|
||||
|
||||
offset++;
|
||||
if (offset >= BYTES_PER_READ) {
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
offset++;
|
||||
if ( offset >= BYTES_PER_READ )
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, (value >> 8) & 0xFF, sector, offset, sizeof(u8));
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, ( value >> 8 ) & 0xFF, sector, offset, sizeof( u8 ) );
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8));
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) );
|
||||
|
||||
offset++;
|
||||
if (offset >= BYTES_PER_READ) {
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
offset++;
|
||||
if ( offset >= BYTES_PER_READ )
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8));
|
||||
_FAT_cache_readLittleEndianValue ( partition->cache, &oldValue, sector, offset, sizeof( u8 ) );
|
||||
|
||||
value = ((value >> 8) & 0x0F) | (oldValue & 0xF0);
|
||||
value = ( ( value >> 8 ) & 0x0F ) | ( oldValue & 0xF0 );
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8));
|
||||
}
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) );
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ((cluster << 1) / BYTES_PER_READ);
|
||||
offset = (cluster % (BYTES_PER_READ >> 1)) << 1;
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ( ( cluster << 1 ) / BYTES_PER_READ );
|
||||
offset = ( cluster % ( BYTES_PER_READ >> 1 ) ) << 1;
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u16));
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u16 ) );
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case FS_FAT32:
|
||||
sector = partition->fat.fatStart + ((cluster << 2) / BYTES_PER_READ);
|
||||
offset = (cluster % (BYTES_PER_READ >> 2)) << 2;
|
||||
case FS_FAT32:
|
||||
sector = partition->fat.fatStart + ( ( cluster << 2 ) / BYTES_PER_READ );
|
||||
offset = ( cluster % ( BYTES_PER_READ >> 2 ) ) << 2;
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u32));
|
||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u32 ) );
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
@ -203,58 +216,67 @@ to end of file, links the input cluster to it then returns the
|
||||
cluster number
|
||||
If an error occurs, return CLUSTER_ERROR
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
|
||||
uint32_t firstFree;
|
||||
uint32_t curLink;
|
||||
uint32_t lastCluster;
|
||||
bool loopedAroundFAT = false;
|
||||
uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t firstFree;
|
||||
uint32_t curLink;
|
||||
uint32_t lastCluster;
|
||||
bool loopedAroundFAT = false;
|
||||
|
||||
lastCluster = partition->fat.lastCluster;
|
||||
lastCluster = partition->fat.lastCluster;
|
||||
|
||||
if (cluster > lastCluster) {
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
if ( cluster > lastCluster )
|
||||
{
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
|
||||
// Check if the cluster already has a link, and return it if so
|
||||
curLink = _FAT_fat_nextCluster(partition, cluster);
|
||||
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster)) {
|
||||
return curLink; // Return the current link - don't allocate a new one
|
||||
}
|
||||
// Check if the cluster already has a link, and return it if so
|
||||
curLink = _FAT_fat_nextCluster( partition, cluster );
|
||||
if ( ( curLink >= CLUSTER_FIRST ) && ( curLink <= lastCluster ) )
|
||||
{
|
||||
return curLink; // Return the current link - don't allocate a new one
|
||||
}
|
||||
|
||||
// Get a free cluster
|
||||
firstFree = partition->fat.firstFree;
|
||||
// Start at first valid cluster
|
||||
if (firstFree < CLUSTER_FIRST) {
|
||||
firstFree = CLUSTER_FIRST;
|
||||
}
|
||||
// Get a free cluster
|
||||
firstFree = partition->fat.firstFree;
|
||||
// Start at first valid cluster
|
||||
if ( firstFree < CLUSTER_FIRST )
|
||||
{
|
||||
firstFree = CLUSTER_FIRST;
|
||||
}
|
||||
|
||||
// Search until a free cluster is found
|
||||
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) {
|
||||
firstFree++;
|
||||
if (firstFree > lastCluster) {
|
||||
if (loopedAroundFAT) {
|
||||
// If couldn't get a free cluster then return an error
|
||||
partition->fat.firstFree = firstFree;
|
||||
return CLUSTER_ERROR;
|
||||
} else {
|
||||
// Try looping back to the beginning of the FAT
|
||||
// This was suggested by loopy
|
||||
firstFree = CLUSTER_FIRST;
|
||||
loopedAroundFAT = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
partition->fat.firstFree = firstFree;
|
||||
// Search until a free cluster is found
|
||||
while ( _FAT_fat_nextCluster( partition, firstFree ) != CLUSTER_FREE )
|
||||
{
|
||||
firstFree++;
|
||||
if ( firstFree > lastCluster )
|
||||
{
|
||||
if ( loopedAroundFAT )
|
||||
{
|
||||
// If couldn't get a free cluster then return an error
|
||||
partition->fat.firstFree = firstFree;
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try looping back to the beginning of the FAT
|
||||
// This was suggested by loopy
|
||||
firstFree = CLUSTER_FIRST;
|
||||
loopedAroundFAT = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
partition->fat.firstFree = firstFree;
|
||||
|
||||
if ((cluster >= CLUSTER_FIRST) && (cluster < lastCluster))
|
||||
{
|
||||
// Update the linked from FAT entry
|
||||
_FAT_fat_writeFatEntry (partition, cluster, firstFree);
|
||||
}
|
||||
// Create the linked to FAT entry
|
||||
_FAT_fat_writeFatEntry (partition, firstFree, CLUSTER_EOF);
|
||||
if ( ( cluster >= CLUSTER_FIRST ) && ( cluster < lastCluster ) )
|
||||
{
|
||||
// Update the linked from FAT entry
|
||||
_FAT_fat_writeFatEntry ( partition, cluster, firstFree );
|
||||
}
|
||||
// Create the linked to FAT entry
|
||||
_FAT_fat_writeFatEntry ( partition, firstFree, CLUSTER_EOF );
|
||||
|
||||
return firstFree;
|
||||
return firstFree;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
@ -263,27 +285,30 @@ to end of file, links the input cluster to it, clears the new
|
||||
cluster to 0 valued bytes, then returns the cluster number
|
||||
If an error occurs, return CLUSTER_ERROR
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster) {
|
||||
uint32_t newCluster;
|
||||
uint32_t i;
|
||||
uint8_t emptySector[BYTES_PER_READ];
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t newCluster;
|
||||
uint32_t i;
|
||||
uint8_t emptySector[BYTES_PER_READ];
|
||||
|
||||
// Link the cluster
|
||||
newCluster = _FAT_fat_linkFreeCluster(partition, cluster);
|
||||
// Link the cluster
|
||||
newCluster = _FAT_fat_linkFreeCluster( partition, cluster );
|
||||
|
||||
if (newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR) {
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
if ( newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR )
|
||||
{
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
|
||||
// Clear all the sectors within the cluster
|
||||
memset (emptySector, 0, BYTES_PER_READ);
|
||||
for (i = 0; i < partition->sectorsPerCluster; i++) {
|
||||
_FAT_cache_writeSectors (partition->cache,
|
||||
_FAT_fat_clusterToSector (partition, newCluster) + i,
|
||||
1, emptySector);
|
||||
}
|
||||
// Clear all the sectors within the cluster
|
||||
memset ( emptySector, 0, BYTES_PER_READ );
|
||||
for ( i = 0; i < partition->sectorsPerCluster; i++ )
|
||||
{
|
||||
_FAT_cache_writeSectors ( partition->cache,
|
||||
_FAT_fat_clusterToSector ( partition, newCluster ) + i,
|
||||
1, emptySector );
|
||||
}
|
||||
|
||||
return newCluster;
|
||||
return newCluster;
|
||||
}
|
||||
|
||||
|
||||
@ -291,29 +316,32 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster
|
||||
_FAT_fat_clearLinks
|
||||
frees any cluster used by a file
|
||||
-----------------------------------------------------------------*/
|
||||
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster) {
|
||||
uint32_t nextCluster;
|
||||
bool _FAT_fat_clearLinks ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
|
||||
return false;
|
||||
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
|
||||
return false;
|
||||
|
||||
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
||||
if (cluster < partition->fat.firstFree) {
|
||||
partition->fat.firstFree = cluster;
|
||||
}
|
||||
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
||||
if ( cluster < partition->fat.firstFree )
|
||||
{
|
||||
partition->fat.firstFree = cluster;
|
||||
}
|
||||
|
||||
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR)) {
|
||||
// Store next cluster before erasing the link
|
||||
nextCluster = _FAT_fat_nextCluster (partition, cluster);
|
||||
while ( ( cluster != CLUSTER_EOF ) && ( cluster != CLUSTER_FREE ) && ( cluster != CLUSTER_ERROR ) )
|
||||
{
|
||||
// Store next cluster before erasing the link
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, cluster );
|
||||
|
||||
// Erase the link
|
||||
_FAT_fat_writeFatEntry (partition, cluster, CLUSTER_FREE);
|
||||
// Erase the link
|
||||
_FAT_fat_writeFatEntry ( partition, cluster, CLUSTER_FREE );
|
||||
|
||||
// Move onto next cluster
|
||||
cluster = nextCluster;
|
||||
}
|
||||
// Move onto next cluster
|
||||
cluster = nextCluster;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
@ -324,60 +352,71 @@ If chainLength is 1, the first cluster is kept and the rest are
|
||||
dropped, and so on.
|
||||
Return the last cluster left in the chain.
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength) {
|
||||
uint32_t nextCluster;
|
||||
uint32_t _FAT_fat_trimChain ( PARTITION* partition, uint32_t startCluster, unsigned int chainLength )
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if (chainLength == 0) {
|
||||
// Drop the entire chain
|
||||
_FAT_fat_clearLinks (partition, startCluster);
|
||||
return CLUSTER_FREE;
|
||||
} else {
|
||||
// Find the last cluster in the chain, and the one after it
|
||||
chainLength--;
|
||||
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
|
||||
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) {
|
||||
chainLength--;
|
||||
startCluster = nextCluster;
|
||||
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
|
||||
}
|
||||
if ( chainLength == 0 )
|
||||
{
|
||||
// Drop the entire chain
|
||||
_FAT_fat_clearLinks ( partition, startCluster );
|
||||
return CLUSTER_FREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the last cluster in the chain, and the one after it
|
||||
chainLength--;
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
||||
while ( ( chainLength > 0 ) && ( nextCluster != CLUSTER_FREE ) && ( nextCluster != CLUSTER_EOF ) )
|
||||
{
|
||||
chainLength--;
|
||||
startCluster = nextCluster;
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
||||
}
|
||||
|
||||
// Drop all clusters after the last in the chain
|
||||
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF) {
|
||||
_FAT_fat_clearLinks (partition, nextCluster);
|
||||
}
|
||||
// Drop all clusters after the last in the chain
|
||||
if ( nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF )
|
||||
{
|
||||
_FAT_fat_clearLinks ( partition, nextCluster );
|
||||
}
|
||||
|
||||
// Mark the last cluster in the chain as the end of the file
|
||||
_FAT_fat_writeFatEntry (partition, startCluster, CLUSTER_EOF);
|
||||
// Mark the last cluster in the chain as the end of the file
|
||||
_FAT_fat_writeFatEntry ( partition, startCluster, CLUSTER_EOF );
|
||||
|
||||
return startCluster;
|
||||
}
|
||||
return startCluster;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
_FAT_fat_lastCluster
|
||||
Trace the cluster links until the last one is found
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
|
||||
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF)) {
|
||||
cluster = _FAT_fat_nextCluster(partition, cluster);
|
||||
}
|
||||
return cluster;
|
||||
uint32_t _FAT_fat_lastCluster ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
while ( ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_FREE ) && ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_EOF ) )
|
||||
{
|
||||
cluster = _FAT_fat_nextCluster( partition, cluster );
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
_FAT_fat_freeClusterCount
|
||||
Return the number of free clusters available
|
||||
-----------------------------------------------------------------*/
|
||||
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition) {
|
||||
unsigned int count = 0;
|
||||
uint32_t curCluster;
|
||||
unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition )
|
||||
{
|
||||
unsigned int count = 0;
|
||||
uint32_t curCluster;
|
||||
|
||||
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++) {
|
||||
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
for ( curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++ )
|
||||
{
|
||||
if ( _FAT_fat_nextCluster( partition, curCluster ) == CLUSTER_FREE )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -33,38 +33,40 @@
|
||||
#include "common.h"
|
||||
#include "partition.h"
|
||||
|
||||
#define CLUSTER_EOF_16 0xFFFF
|
||||
#define CLUSTER_EOF 0x0FFFFFFF
|
||||
#define CLUSTER_FREE 0x00000000
|
||||
#define CLUSTER_ROOT 0x00000000
|
||||
#define CLUSTER_FIRST 0x00000002
|
||||
#define CLUSTER_ERROR 0xFFFFFFFF
|
||||
#define CLUSTER_EOF_16 0xFFFF
|
||||
#define CLUSTER_EOF 0x0FFFFFFF
|
||||
#define CLUSTER_FREE 0x00000000
|
||||
#define CLUSTER_ROOT 0x00000000
|
||||
#define CLUSTER_FIRST 0x00000002
|
||||
#define CLUSTER_ERROR 0xFFFFFFFF
|
||||
|
||||
#define CLUSTERS_PER_FAT12 4085
|
||||
#define CLUSTERS_PER_FAT16 65525
|
||||
|
||||
|
||||
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster);
|
||||
uint32_t _FAT_fat_nextCluster( PARTITION* partition, uint32_t cluster );
|
||||
|
||||
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster);
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster);
|
||||
uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster );
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared ( PARTITION* partition, uint32_t cluster );
|
||||
|
||||
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster);
|
||||
bool _FAT_fat_clearLinks ( PARTITION* partition, uint32_t cluster );
|
||||
|
||||
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength);
|
||||
uint32_t _FAT_fat_trimChain ( PARTITION* partition, uint32_t startCluster, unsigned int chainLength );
|
||||
|
||||
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster);
|
||||
uint32_t _FAT_fat_lastCluster ( PARTITION* partition, uint32_t cluster );
|
||||
|
||||
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition);
|
||||
unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition );
|
||||
|
||||
static inline sec_t _FAT_fat_clusterToSector (PARTITION* partition, uint32_t cluster) {
|
||||
return (cluster >= CLUSTER_FIRST) ?
|
||||
((cluster - CLUSTER_FIRST) * (sec_t)partition->sectorsPerCluster) + partition->dataStart :
|
||||
partition->rootDirStart;
|
||||
static inline sec_t _FAT_fat_clusterToSector ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
return ( cluster >= CLUSTER_FIRST ) ?
|
||||
( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart :
|
||||
partition->rootDirStart;
|
||||
}
|
||||
|
||||
static inline bool _FAT_fat_isValidCluster (PARTITION* partition, uint32_t cluster) {
|
||||
return (cluster >= CLUSTER_FIRST) && (cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */);
|
||||
static inline bool _FAT_fat_isValidCluster ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
return ( cluster >= CLUSTER_FIRST ) && ( cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ );
|
||||
}
|
||||
|
||||
#endif // _FAT_H
|
||||
|
@ -40,68 +40,73 @@
|
||||
#define MAX_DAY 31
|
||||
#define MIN_DAY 1
|
||||
|
||||
uint16_t _FAT_filetime_getTimeFromRTC (void) {
|
||||
uint16_t _FAT_filetime_getTimeFromRTC ( void )
|
||||
{
|
||||
#ifdef USE_RTC_TIME
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1) {
|
||||
return 0;
|
||||
}
|
||||
localtime_r(&epochTime, &timeParts);
|
||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
localtime_r( &epochTime, &timeParts );
|
||||
|
||||
// Check that the values are all in range.
|
||||
// If they are not, return 0 (no timestamp)
|
||||
if ((timeParts.tm_hour < 0) || (timeParts.tm_hour > MAX_HOUR)) return 0;
|
||||
if ((timeParts.tm_min < 0) || (timeParts.tm_min > MAX_MINUTE)) return 0;
|
||||
if ((timeParts.tm_sec < 0) || (timeParts.tm_sec > MAX_SECOND)) return 0;
|
||||
// Check that the values are all in range.
|
||||
// If they are not, return 0 (no timestamp)
|
||||
if ( ( timeParts.tm_hour < 0 ) || ( timeParts.tm_hour > MAX_HOUR ) ) return 0;
|
||||
if ( ( timeParts.tm_min < 0 ) || ( timeParts.tm_min > MAX_MINUTE ) ) return 0;
|
||||
if ( ( timeParts.tm_sec < 0 ) || ( timeParts.tm_sec > MAX_SECOND ) ) return 0;
|
||||
|
||||
return (
|
||||
((timeParts.tm_hour & 0x1F) << 11) |
|
||||
((timeParts.tm_min & 0x3F) << 5) |
|
||||
((timeParts.tm_sec >> 1) & 0x1F)
|
||||
);
|
||||
return (
|
||||
( ( timeParts.tm_hour & 0x1F ) << 11 ) |
|
||||
( ( timeParts.tm_min & 0x3F ) << 5 ) |
|
||||
( ( timeParts.tm_sec >> 1 ) & 0x1F )
|
||||
);
|
||||
#else
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint16_t _FAT_filetime_getDateFromRTC (void) {
|
||||
uint16_t _FAT_filetime_getDateFromRTC ( void )
|
||||
{
|
||||
#ifdef USE_RTC_TIME
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1) {
|
||||
return 0;
|
||||
}
|
||||
localtime_r(&epochTime, &timeParts);
|
||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
localtime_r( &epochTime, &timeParts );
|
||||
|
||||
if ((timeParts.tm_mon < MIN_MONTH) || (timeParts.tm_mon > MAX_MONTH)) return 0;
|
||||
if ((timeParts.tm_mday < MIN_DAY) || (timeParts.tm_mday > MAX_DAY)) return 0;
|
||||
if ( ( timeParts.tm_mon < MIN_MONTH ) || ( timeParts.tm_mon > MAX_MONTH ) ) return 0;
|
||||
if ( ( timeParts.tm_mday < MIN_DAY ) || ( timeParts.tm_mday > MAX_DAY ) ) return 0;
|
||||
|
||||
return (
|
||||
(((timeParts.tm_year - 80) & 0x7F) <<9) | // Adjust for MS-FAT base year (1980 vs 1900 for tm_year)
|
||||
(((timeParts.tm_mon + 1) & 0xF) << 5) |
|
||||
(timeParts.tm_mday & 0x1F)
|
||||
);
|
||||
return (
|
||||
( ( ( timeParts.tm_year - 80 ) & 0x7F ) << 9 ) | // Adjust for MS-FAT base year (1980 vs 1900 for tm_year)
|
||||
( ( ( timeParts.tm_mon + 1 ) & 0xF ) << 5 ) |
|
||||
( timeParts.tm_mday & 0x1F )
|
||||
);
|
||||
#else
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d) {
|
||||
struct tm timeParts;
|
||||
time_t _FAT_filetime_to_time_t ( uint16_t t, uint16_t d )
|
||||
{
|
||||
struct tm timeParts;
|
||||
|
||||
timeParts.tm_hour = t >> 11;
|
||||
timeParts.tm_min = (t >> 5) & 0x3F;
|
||||
timeParts.tm_sec = (t & 0x1F) << 1;
|
||||
timeParts.tm_hour = t >> 11;
|
||||
timeParts.tm_min = ( t >> 5 ) & 0x3F;
|
||||
timeParts.tm_sec = ( t & 0x1F ) << 1;
|
||||
|
||||
timeParts.tm_mday = d & 0x1F;
|
||||
timeParts.tm_mon = ((d >> 5) & 0x0F) - 1;
|
||||
timeParts.tm_year = (d >> 9) + 80;
|
||||
timeParts.tm_mday = d & 0x1F;
|
||||
timeParts.tm_mon = ( ( d >> 5 ) & 0x0F ) - 1;
|
||||
timeParts.tm_year = ( d >> 9 ) + 80;
|
||||
|
||||
timeParts.tm_isdst = 0;
|
||||
timeParts.tm_isdst = 0;
|
||||
|
||||
return mktime(&timeParts);
|
||||
return mktime( &timeParts );
|
||||
}
|
||||
|
@ -32,10 +32,10 @@
|
||||
#include "common.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
uint16_t _FAT_filetime_getTimeFromRTC (void);
|
||||
uint16_t _FAT_filetime_getDateFromRTC (void);
|
||||
uint16_t _FAT_filetime_getTimeFromRTC ( void );
|
||||
uint16_t _FAT_filetime_getDateFromRTC ( void );
|
||||
|
||||
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d);
|
||||
time_t _FAT_filetime_to_time_t ( uint16_t t, uint16_t d );
|
||||
|
||||
|
||||
#endif // _FILETIME_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
libfat.c
|
||||
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||
libfat.c
|
||||
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
@ -38,160 +38,178 @@
|
||||
#include "mem_allocate.h"
|
||||
#include "disc_fat.h"
|
||||
|
||||
static const devoptab_t dotab_fat = {
|
||||
"fat",
|
||||
sizeof (FILE_STRUCT),
|
||||
_FAT_open_r,
|
||||
_FAT_close_r,
|
||||
_FAT_write_r,
|
||||
_FAT_read_r,
|
||||
_FAT_seek_r,
|
||||
_FAT_fstat_r,
|
||||
_FAT_stat_r,
|
||||
_FAT_link_r,
|
||||
_FAT_unlink_r,
|
||||
_FAT_chdir_r,
|
||||
_FAT_rename_r,
|
||||
_FAT_mkdir_r,
|
||||
sizeof (DIR_STATE_STRUCT),
|
||||
_FAT_diropen_r,
|
||||
_FAT_dirreset_r,
|
||||
_FAT_dirnext_r,
|
||||
_FAT_dirclose_r,
|
||||
_FAT_statvfs_r,
|
||||
_FAT_ftruncate_r,
|
||||
_FAT_fsync_r,
|
||||
NULL /* Device data */
|
||||
static const devoptab_t dotab_fat =
|
||||
{
|
||||
"fat",
|
||||
sizeof ( FILE_STRUCT ),
|
||||
_FAT_open_r,
|
||||
_FAT_close_r,
|
||||
_FAT_write_r,
|
||||
_FAT_read_r,
|
||||
_FAT_seek_r,
|
||||
_FAT_fstat_r,
|
||||
_FAT_stat_r,
|
||||
_FAT_link_r,
|
||||
_FAT_unlink_r,
|
||||
_FAT_chdir_r,
|
||||
_FAT_rename_r,
|
||||
_FAT_mkdir_r,
|
||||
sizeof ( DIR_STATE_STRUCT ),
|
||||
_FAT_diropen_r,
|
||||
_FAT_dirreset_r,
|
||||
_FAT_dirnext_r,
|
||||
_FAT_dirclose_r,
|
||||
_FAT_statvfs_r,
|
||||
_FAT_ftruncate_r,
|
||||
_FAT_fsync_r,
|
||||
NULL /* Device data */
|
||||
};
|
||||
|
||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) {
|
||||
PARTITION* partition;
|
||||
devoptab_t* devops;
|
||||
char* nameCopy;
|
||||
bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage )
|
||||
{
|
||||
PARTITION* partition;
|
||||
devoptab_t* devops;
|
||||
char* nameCopy;
|
||||
|
||||
if(!interface->startup())
|
||||
return false;
|
||||
if ( !interface->startup() )
|
||||
return false;
|
||||
|
||||
if(!interface->isInserted()) {
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
devops = _FAT_mem_allocate (sizeof(devoptab_t) + strlen(name) + 1);
|
||||
if (!devops) {
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
// Use the space allocated at the end of the devoptab struct for storing the name
|
||||
nameCopy = (char*)(devops+1);
|
||||
devops = _FAT_mem_allocate ( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
||||
if ( !devops )
|
||||
{
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
// Use the space allocated at the end of the devoptab struct for storing the name
|
||||
nameCopy = ( char* )( devops + 1 );
|
||||
|
||||
// Initialize the file system
|
||||
partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector);
|
||||
if (!partition) {
|
||||
_FAT_mem_free (devops);
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
// Initialize the file system
|
||||
partition = _FAT_partition_constructor ( interface, cacheSize, SectorsPerPage, startSector );
|
||||
if ( !partition )
|
||||
{
|
||||
_FAT_mem_free ( devops );
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add an entry for this device to the devoptab table
|
||||
memcpy (devops, &dotab_fat, sizeof(dotab_fat));
|
||||
strcpy (nameCopy, name);
|
||||
devops->name = nameCopy;
|
||||
devops->deviceData = partition;
|
||||
// Add an entry for this device to the devoptab table
|
||||
memcpy ( devops, &dotab_fat, sizeof( dotab_fat ) );
|
||||
strcpy ( nameCopy, name );
|
||||
devops->name = nameCopy;
|
||||
devops->deviceData = partition;
|
||||
|
||||
AddDevice (devops);
|
||||
AddDevice ( devops );
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) {
|
||||
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE);
|
||||
bool fatMountSimple ( const char* name, const DISC_INTERFACE* interface )
|
||||
{
|
||||
return fatMount ( name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE );
|
||||
}
|
||||
|
||||
void fatUnmount (const char* name) {
|
||||
devoptab_t *devops;
|
||||
PARTITION* partition;
|
||||
const DISC_INTERFACE *disc;
|
||||
void fatUnmount ( const char* name )
|
||||
{
|
||||
devoptab_t *devops;
|
||||
PARTITION* partition;
|
||||
const DISC_INTERFACE *disc;
|
||||
|
||||
devops = (devoptab_t*)GetDeviceOpTab (name);
|
||||
if (!devops) {
|
||||
return;
|
||||
}
|
||||
devops = ( devoptab_t* )GetDeviceOpTab ( name );
|
||||
if ( !devops )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
||||
if (devops->open_r != dotab_fat.open_r) {
|
||||
return;
|
||||
}
|
||||
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
||||
if ( devops->open_r != dotab_fat.open_r )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (RemoveDevice (name) == -1) {
|
||||
return;
|
||||
}
|
||||
if ( RemoveDevice ( name ) == -1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
partition = (PARTITION*)devops->deviceData;
|
||||
disc = partition->disc;
|
||||
_FAT_partition_destructor (partition);
|
||||
_FAT_mem_free (devops);
|
||||
disc->shutdown();
|
||||
partition = ( PARTITION* )devops->deviceData;
|
||||
disc = partition->disc;
|
||||
_FAT_partition_destructor ( partition );
|
||||
_FAT_mem_free ( devops );
|
||||
disc->shutdown();
|
||||
}
|
||||
|
||||
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
||||
int i;
|
||||
int defaultDevice = -1;
|
||||
const DISC_INTERFACE *disc;
|
||||
bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
|
||||
{
|
||||
int i;
|
||||
int defaultDevice = -1;
|
||||
const DISC_INTERFACE *disc;
|
||||
|
||||
for (i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++)
|
||||
{
|
||||
disc = _FAT_disc_interfaces[i].getInterface();
|
||||
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) {
|
||||
// The first device to successfully mount is set as the default
|
||||
if (defaultDevice < 0) {
|
||||
defaultDevice = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++ )
|
||||
{
|
||||
disc = _FAT_disc_interfaces[i].getInterface();
|
||||
if ( fatMount ( _FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE ) )
|
||||
{
|
||||
// The first device to successfully mount is set as the default
|
||||
if ( defaultDevice < 0 )
|
||||
{
|
||||
defaultDevice = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultDevice < 0) {
|
||||
// None of our devices mounted
|
||||
return false;
|
||||
}
|
||||
if ( defaultDevice < 0 )
|
||||
{
|
||||
// None of our devices mounted
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setAsDefaultDevice) {
|
||||
char filePath[MAXPATHLEN * 2];
|
||||
strcpy (filePath, _FAT_disc_interfaces[defaultDevice].name);
|
||||
strcat (filePath, ":/");
|
||||
if ( setAsDefaultDevice )
|
||||
{
|
||||
char filePath[MAXPATHLEN * 2];
|
||||
strcpy ( filePath, _FAT_disc_interfaces[defaultDevice].name );
|
||||
strcat ( filePath, ":/" );
|
||||
#ifdef ARGV_MAGIC
|
||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL ) {
|
||||
// Check the app's path against each of our mounted devices, to see
|
||||
// if we can support it. If so, change to that path.
|
||||
for (i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++)
|
||||
{
|
||||
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
||||
strlen(_FAT_disc_interfaces[i].name)))
|
||||
{
|
||||
char *lastSlash;
|
||||
strcpy(filePath, __system_argv->argv[0]);
|
||||
lastSlash = strrchr( filePath, '/' );
|
||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' ) != NULL )
|
||||
{
|
||||
// Check the app's path against each of our mounted devices, to see
|
||||
// if we can support it. If so, change to that path.
|
||||
for ( i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++ )
|
||||
{
|
||||
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
||||
strlen( _FAT_disc_interfaces[i].name ) ) )
|
||||
{
|
||||
char *lastSlash;
|
||||
strcpy( filePath, __system_argv->argv[0] );
|
||||
lastSlash = strrchr( filePath, '/' );
|
||||
|
||||
if ( NULL != lastSlash) {
|
||||
if ( *(lastSlash - 1) == ':') lastSlash++;
|
||||
*lastSlash = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( NULL != lastSlash )
|
||||
{
|
||||
if ( *( lastSlash - 1 ) == ':' ) lastSlash++;
|
||||
*lastSlash = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
chdir (filePath);
|
||||
}
|
||||
chdir ( filePath );
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fatInitDefault (void) {
|
||||
return fatInit (DEFAULT_CACHE_PAGES, true);
|
||||
bool fatInitDefault ( void )
|
||||
{
|
||||
return fatInit ( DEFAULT_CACHE_PAGES, true );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef __LIBFATVERSION_H__
|
||||
#define __LIBFATVERSION_H__
|
||||
|
||||
#define _LIBFAT_MAJOR_ 1
|
||||
#define _LIBFAT_MINOR_ 0
|
||||
#define _LIBFAT_PATCH_ 7
|
||||
#define _LIBFAT_MAJOR_ 1
|
||||
#define _LIBFAT_MINOR_ 0
|
||||
#define _LIBFAT_PATCH_ 7
|
||||
|
||||
#define _LIBFAT_STRING "libFAT Release 1.0.7"
|
||||
|
||||
|
@ -33,24 +33,24 @@
|
||||
|
||||
#ifdef USE_LWP_LOCK
|
||||
|
||||
static inline void _FAT_lock_init(mutex_t *mutex)
|
||||
static inline void _FAT_lock_init( mutex_t *mutex )
|
||||
{
|
||||
LWP_MutexInit(mutex, false);
|
||||
LWP_MutexInit( mutex, false );
|
||||
}
|
||||
|
||||
static inline void _FAT_lock_deinit(mutex_t *mutex)
|
||||
static inline void _FAT_lock_deinit( mutex_t *mutex )
|
||||
{
|
||||
LWP_MutexDestroy(*mutex);
|
||||
LWP_MutexDestroy( *mutex );
|
||||
}
|
||||
|
||||
static inline void _FAT_lock(mutex_t *mutex)
|
||||
static inline void _FAT_lock( mutex_t *mutex )
|
||||
{
|
||||
LWP_MutexLock(*mutex);
|
||||
LWP_MutexLock( *mutex );
|
||||
}
|
||||
|
||||
static inline void _FAT_unlock(mutex_t *mutex)
|
||||
static inline void _FAT_unlock( mutex_t *mutex )
|
||||
{
|
||||
LWP_MutexUnlock(*mutex);
|
||||
LWP_MutexUnlock( *mutex );
|
||||
}
|
||||
|
||||
#else
|
||||
@ -60,24 +60,24 @@ static inline void _FAT_unlock(mutex_t *mutex)
|
||||
typedef int mutex_t;
|
||||
#endif
|
||||
|
||||
static inline void _FAT_lock_init(mutex_t *mutex)
|
||||
static inline void _FAT_lock_init( mutex_t *mutex )
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void _FAT_lock_deinit(mutex_t *mutex)
|
||||
static inline void _FAT_lock_deinit( mutex_t *mutex )
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void _FAT_lock(mutex_t *mutex)
|
||||
static inline void _FAT_lock( mutex_t *mutex )
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void _FAT_unlock(mutex_t *mutex)
|
||||
static inline void _FAT_unlock( mutex_t *mutex )
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // USE_LWP_LOCK
|
||||
|
@ -33,17 +33,20 @@
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static inline void* _FAT_mem_allocate (size_t size) {
|
||||
return malloc (size);
|
||||
static inline void* _FAT_mem_allocate ( size_t size )
|
||||
{
|
||||
return malloc ( size );
|
||||
}
|
||||
|
||||
static inline void* _FAT_mem_align (size_t size) {
|
||||
static inline void* _FAT_mem_align ( size_t size )
|
||||
{
|
||||
|
||||
return memalign (32, size);
|
||||
return memalign ( 32, size );
|
||||
}
|
||||
|
||||
static inline void _FAT_mem_free (void* mem) {
|
||||
free (mem);
|
||||
static inline void _FAT_mem_free ( void* mem )
|
||||
{
|
||||
free ( mem );
|
||||
}
|
||||
|
||||
#endif // _MEM_ALLOCATE_H
|
||||
|
@ -50,263 +50,298 @@ Data offsets
|
||||
*/
|
||||
|
||||
// BIOS Parameter Block offsets
|
||||
enum BPB {
|
||||
BPB_jmpBoot = 0x00,
|
||||
BPB_OEMName = 0x03,
|
||||
// BIOS Parameter Block
|
||||
BPB_bytesPerSector = 0x0B,
|
||||
BPB_sectorsPerCluster = 0x0D,
|
||||
BPB_reservedSectors = 0x0E,
|
||||
BPB_numFATs = 0x10,
|
||||
BPB_rootEntries = 0x11,
|
||||
BPB_numSectorsSmall = 0x13,
|
||||
BPB_mediaDesc = 0x15,
|
||||
BPB_sectorsPerFAT = 0x16,
|
||||
BPB_sectorsPerTrk = 0x18,
|
||||
BPB_numHeads = 0x1A,
|
||||
BPB_numHiddenSectors = 0x1C,
|
||||
BPB_numSectors = 0x20,
|
||||
// Ext BIOS Parameter Block for FAT16
|
||||
BPB_FAT16_driveNumber = 0x24,
|
||||
BPB_FAT16_reserved1 = 0x25,
|
||||
BPB_FAT16_extBootSig = 0x26,
|
||||
BPB_FAT16_volumeID = 0x27,
|
||||
BPB_FAT16_volumeLabel = 0x2B,
|
||||
BPB_FAT16_fileSysType = 0x36,
|
||||
// Bootcode
|
||||
BPB_FAT16_bootCode = 0x3E,
|
||||
// FAT32 extended block
|
||||
BPB_FAT32_sectorsPerFAT32 = 0x24,
|
||||
BPB_FAT32_extFlags = 0x28,
|
||||
BPB_FAT32_fsVer = 0x2A,
|
||||
BPB_FAT32_rootClus = 0x2C,
|
||||
BPB_FAT32_fsInfo = 0x30,
|
||||
BPB_FAT32_bkBootSec = 0x32,
|
||||
// Ext BIOS Parameter Block for FAT32
|
||||
BPB_FAT32_driveNumber = 0x40,
|
||||
BPB_FAT32_reserved1 = 0x41,
|
||||
BPB_FAT32_extBootSig = 0x42,
|
||||
BPB_FAT32_volumeID = 0x43,
|
||||
BPB_FAT32_volumeLabel = 0x47,
|
||||
BPB_FAT32_fileSysType = 0x52,
|
||||
// Bootcode
|
||||
BPB_FAT32_bootCode = 0x5A,
|
||||
BPB_bootSig_55 = 0x1FE,
|
||||
BPB_bootSig_AA = 0x1FF
|
||||
enum BPB
|
||||
{
|
||||
BPB_jmpBoot = 0x00,
|
||||
BPB_OEMName = 0x03,
|
||||
// BIOS Parameter Block
|
||||
BPB_bytesPerSector = 0x0B,
|
||||
BPB_sectorsPerCluster = 0x0D,
|
||||
BPB_reservedSectors = 0x0E,
|
||||
BPB_numFATs = 0x10,
|
||||
BPB_rootEntries = 0x11,
|
||||
BPB_numSectorsSmall = 0x13,
|
||||
BPB_mediaDesc = 0x15,
|
||||
BPB_sectorsPerFAT = 0x16,
|
||||
BPB_sectorsPerTrk = 0x18,
|
||||
BPB_numHeads = 0x1A,
|
||||
BPB_numHiddenSectors = 0x1C,
|
||||
BPB_numSectors = 0x20,
|
||||
// Ext BIOS Parameter Block for FAT16
|
||||
BPB_FAT16_driveNumber = 0x24,
|
||||
BPB_FAT16_reserved1 = 0x25,
|
||||
BPB_FAT16_extBootSig = 0x26,
|
||||
BPB_FAT16_volumeID = 0x27,
|
||||
BPB_FAT16_volumeLabel = 0x2B,
|
||||
BPB_FAT16_fileSysType = 0x36,
|
||||
// Bootcode
|
||||
BPB_FAT16_bootCode = 0x3E,
|
||||
// FAT32 extended block
|
||||
BPB_FAT32_sectorsPerFAT32 = 0x24,
|
||||
BPB_FAT32_extFlags = 0x28,
|
||||
BPB_FAT32_fsVer = 0x2A,
|
||||
BPB_FAT32_rootClus = 0x2C,
|
||||
BPB_FAT32_fsInfo = 0x30,
|
||||
BPB_FAT32_bkBootSec = 0x32,
|
||||
// Ext BIOS Parameter Block for FAT32
|
||||
BPB_FAT32_driveNumber = 0x40,
|
||||
BPB_FAT32_reserved1 = 0x41,
|
||||
BPB_FAT32_extBootSig = 0x42,
|
||||
BPB_FAT32_volumeID = 0x43,
|
||||
BPB_FAT32_volumeLabel = 0x47,
|
||||
BPB_FAT32_fileSysType = 0x52,
|
||||
// Bootcode
|
||||
BPB_FAT32_bootCode = 0x5A,
|
||||
BPB_bootSig_55 = 0x1FE,
|
||||
BPB_bootSig_AA = 0x1FF
|
||||
};
|
||||
|
||||
static const char FAT_SIG[3] = {'F', 'A', 'T'};
|
||||
|
||||
|
||||
sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
sec_t FindFirstValidPartition( const DISC_INTERFACE* disc )
|
||||
{
|
||||
uint8_t part_table[16*4];
|
||||
uint8_t *ptr;
|
||||
int i;
|
||||
uint8_t part_table[16*4];
|
||||
uint8_t *ptr;
|
||||
int i;
|
||||
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
|
||||
// Read first sector of disc
|
||||
if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) {
|
||||
return 0;
|
||||
}
|
||||
// Read first sector of disc
|
||||
if ( !_FAT_disc_readSectors ( disc, 0, 1, sectorBuffer ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(part_table,sectorBuffer+0x1BE,16*4);
|
||||
ptr = part_table;
|
||||
memcpy( part_table, sectorBuffer + 0x1BE, 16*4 );
|
||||
ptr = part_table;
|
||||
|
||||
for(i=0;i<4;i++,ptr+=16) {
|
||||
sec_t part_lba = u8array_to_u32(ptr, 0x8);
|
||||
for ( i = 0; i < 4; i++, ptr += 16 )
|
||||
{
|
||||
sec_t part_lba = u8array_to_u32( ptr, 0x8 );
|
||||
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
||||
return part_lba;
|
||||
}
|
||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
return part_lba;
|
||||
}
|
||||
|
||||
if(ptr[4]==0) continue;
|
||||
if ( ptr[4] == 0 ) continue;
|
||||
|
||||
if(ptr[4]==0x0F) {
|
||||
sec_t part_lba2=part_lba;
|
||||
sec_t next_lba2=0;
|
||||
int n;
|
||||
if ( ptr[4] == 0x0F )
|
||||
{
|
||||
sec_t part_lba2 = part_lba;
|
||||
sec_t next_lba2 = 0;
|
||||
int n;
|
||||
|
||||
for(n=0;n<8;n++) // max 8 logic partitions
|
||||
{
|
||||
if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer)) return 0;
|
||||
for ( n = 0; n < 8; n++ ) // max 8 logic partitions
|
||||
{
|
||||
if ( !_FAT_disc_readSectors ( disc, part_lba + next_lba2, 1, sectorBuffer ) ) return 0;
|
||||
|
||||
part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6) ;
|
||||
next_lba2 = u8array_to_u32(sectorBuffer, 0x1D6);
|
||||
part_lba2 = part_lba + next_lba2 + u8array_to_u32( sectorBuffer, 0x1C6 ) ;
|
||||
next_lba2 = u8array_to_u32( sectorBuffer, 0x1D6 );
|
||||
|
||||
if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer)) return 0;
|
||||
if ( !_FAT_disc_readSectors ( disc, part_lba2, 1, sectorBuffer ) ) return 0;
|
||||
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
{
|
||||
return part_lba2;
|
||||
}
|
||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
return part_lba2;
|
||||
}
|
||||
|
||||
if(next_lba2==0) break;
|
||||
}
|
||||
} else {
|
||||
if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer)) return 0;
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
||||
return part_lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
if ( next_lba2 == 0 ) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !_FAT_disc_readSectors ( disc, part_lba, 1, sectorBuffer ) ) return 0;
|
||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
return part_lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) {
|
||||
PARTITION* partition;
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector )
|
||||
{
|
||||
PARTITION* partition;
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
|
||||
// Read first sector of disc
|
||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
|
||||
return NULL;
|
||||
}
|
||||
// Read first sector of disc
|
||||
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Make sure it is a valid MBR or boot sector
|
||||
if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) {
|
||||
return NULL;
|
||||
}
|
||||
// Make sure it is a valid MBR or boot sector
|
||||
if ( ( sectorBuffer[BPB_bootSig_55] != 0x55 ) || ( sectorBuffer[BPB_bootSig_AA] != 0xAA ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (startSector != 0) {
|
||||
// We're told where to start the partition, so just accept it
|
||||
} else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
||||
// Check if there is a FAT string, which indicates this is a boot sector
|
||||
startSector = 0;
|
||||
} else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
|
||||
// Check for FAT32
|
||||
startSector = 0;
|
||||
} else {
|
||||
startSector = FindFirstValidPartition(disc);
|
||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if ( startSector != 0 )
|
||||
{
|
||||
// We're told where to start the partition, so just accept it
|
||||
}
|
||||
else if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
// Check if there is a FAT string, which indicates this is a boot sector
|
||||
startSector = 0;
|
||||
}
|
||||
else if ( !memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
// Check for FAT32
|
||||
startSector = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startSector = FindFirstValidPartition( disc );
|
||||
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Now verify that this is indeed a FAT partition
|
||||
if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) &&
|
||||
memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// Now verify that this is indeed a FAT partition
|
||||
if ( memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) &&
|
||||
memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check again for the last two cases to make sure that we really have a FAT filesystem here
|
||||
// and won't corrupt any data
|
||||
if(memcmp(sectorBuffer + BPB_FAT16_fileSysType, "FAT", 3) != 0 && memcmp(sectorBuffer + BPB_FAT32_fileSysType, "FAT32", 5) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// check again for the last two cases to make sure that we really have a FAT filesystem here
|
||||
// and won't corrupt any data
|
||||
if ( memcmp( sectorBuffer + BPB_FAT16_fileSysType, "FAT", 3 ) != 0 && memcmp( sectorBuffer + BPB_FAT32_fileSysType, "FAT32", 5 ) != 0 )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION));
|
||||
if (partition == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_FAT_startSector = startSector;
|
||||
_FAT_startSector = startSector;
|
||||
|
||||
// Init the partition lock
|
||||
_FAT_lock_init(&partition->lock);
|
||||
// Init the partition lock
|
||||
_FAT_lock_init( &partition->lock );
|
||||
|
||||
// Set partition's disc interface
|
||||
partition->disc = disc;
|
||||
// Set partition's disc interface
|
||||
partition->disc = disc;
|
||||
|
||||
// Store required information about the file system
|
||||
partition->fat.sectorsPerFat = u8array_to_u16(sectorBuffer, BPB_sectorsPerFAT);
|
||||
if (partition->fat.sectorsPerFat == 0) {
|
||||
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32);
|
||||
}
|
||||
// Store required information about the file system
|
||||
partition->fat.sectorsPerFat = u8array_to_u16( sectorBuffer, BPB_sectorsPerFAT );
|
||||
if ( partition->fat.sectorsPerFat == 0 )
|
||||
{
|
||||
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32 );
|
||||
}
|
||||
|
||||
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall);
|
||||
if (partition->numberOfSectors == 0) {
|
||||
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors);
|
||||
}
|
||||
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall );
|
||||
if ( partition->numberOfSectors == 0 )
|
||||
{
|
||||
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors );
|
||||
}
|
||||
|
||||
partition->bytesPerSector = BYTES_PER_READ; // Sector size is redefined to be 512 bytes
|
||||
partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster] * u8array_to_u16(sectorBuffer, BPB_bytesPerSector) / BYTES_PER_READ;
|
||||
partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster;
|
||||
partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors);
|
||||
partition->bytesPerSector = BYTES_PER_READ; // Sector size is redefined to be 512 bytes
|
||||
partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster] * u8array_to_u16( sectorBuffer, BPB_bytesPerSector ) / BYTES_PER_READ;
|
||||
partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster;
|
||||
partition->fat.fatStart = startSector + u8array_to_u16( sectorBuffer, BPB_reservedSectors );
|
||||
|
||||
partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat);
|
||||
partition->dataStart = partition->rootDirStart +
|
||||
(( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector);
|
||||
partition->rootDirStart = partition->fat.fatStart + ( sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat );
|
||||
partition->dataStart = partition->rootDirStart +
|
||||
( ( u8array_to_u16( sectorBuffer, BPB_rootEntries ) * DIR_ENTRY_DATA_SIZE ) / partition->bytesPerSector );
|
||||
|
||||
partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector;
|
||||
partition->totalSize = ( ( uint64_t )partition->numberOfSectors - ( partition->dataStart - startSector ) ) * ( uint64_t )partition->bytesPerSector;
|
||||
|
||||
// Store info about FAT
|
||||
uint32_t clusterCount = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster;
|
||||
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
||||
partition->fat.firstFree = CLUSTER_FIRST;
|
||||
// Store info about FAT
|
||||
uint32_t clusterCount = ( partition->numberOfSectors - ( uint32_t )( partition->dataStart - startSector ) ) / partition->sectorsPerCluster;
|
||||
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
||||
partition->fat.firstFree = CLUSTER_FIRST;
|
||||
|
||||
if (clusterCount < CLUSTERS_PER_FAT12) {
|
||||
partition->filesysType = FS_FAT12; // FAT12 volume
|
||||
} else if (clusterCount < CLUSTERS_PER_FAT16) {
|
||||
partition->filesysType = FS_FAT16; // FAT16 volume
|
||||
} else {
|
||||
partition->filesysType = FS_FAT32; // FAT32 volume
|
||||
}
|
||||
if ( clusterCount < CLUSTERS_PER_FAT12 )
|
||||
{
|
||||
partition->filesysType = FS_FAT12; // FAT12 volume
|
||||
}
|
||||
else if ( clusterCount < CLUSTERS_PER_FAT16 )
|
||||
{
|
||||
partition->filesysType = FS_FAT16; // FAT16 volume
|
||||
}
|
||||
else
|
||||
{
|
||||
partition->filesysType = FS_FAT32; // FAT32 volume
|
||||
}
|
||||
|
||||
if (partition->filesysType != FS_FAT32) {
|
||||
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
} else {
|
||||
// Set up for the FAT32 way
|
||||
partition->rootDirCluster = u8array_to_u32(sectorBuffer, BPB_FAT32_rootClus);
|
||||
// Check if FAT mirroring is enabled
|
||||
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) {
|
||||
// Use the active FAT
|
||||
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * (sectorBuffer[BPB_FAT32_extFlags] & 0x0F));
|
||||
}
|
||||
}
|
||||
if ( partition->filesysType != FS_FAT32 )
|
||||
{
|
||||
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set up for the FAT32 way
|
||||
partition->rootDirCluster = u8array_to_u32( sectorBuffer, BPB_FAT32_rootClus );
|
||||
// Check if FAT mirroring is enabled
|
||||
if ( !( sectorBuffer[BPB_FAT32_extFlags] & 0x80 ) )
|
||||
{
|
||||
// Use the active FAT
|
||||
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * ( sectorBuffer[BPB_FAT32_extFlags] & 0x0F ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Create a cache to use
|
||||
partition->cache = _FAT_cache_constructor (cacheSize, sectorsPerPage, partition->disc, startSector+partition->numberOfSectors);
|
||||
// Create a cache to use
|
||||
partition->cache = _FAT_cache_constructor ( cacheSize, sectorsPerPage, partition->disc, startSector + partition->numberOfSectors );
|
||||
|
||||
// Set current directory to the root
|
||||
partition->cwdCluster = partition->rootDirCluster;
|
||||
// Set current directory to the root
|
||||
partition->cwdCluster = partition->rootDirCluster;
|
||||
|
||||
// Check if this disc is writable, and set the readOnly property appropriately
|
||||
partition->readOnly = !(_FAT_disc_features(disc) & FEATURE_MEDIUM_CANWRITE);
|
||||
// Check if this disc is writable, and set the readOnly property appropriately
|
||||
partition->readOnly = !( _FAT_disc_features( disc ) & FEATURE_MEDIUM_CANWRITE );
|
||||
|
||||
// There are currently no open files on this partition
|
||||
partition->openFileCount = 0;
|
||||
partition->firstOpenFile = NULL;
|
||||
// There are currently no open files on this partition
|
||||
partition->openFileCount = 0;
|
||||
partition->firstOpenFile = NULL;
|
||||
|
||||
return partition;
|
||||
return partition;
|
||||
}
|
||||
|
||||
void _FAT_partition_destructor (PARTITION* partition) {
|
||||
FILE_STRUCT* nextFile;
|
||||
void _FAT_partition_destructor ( PARTITION* partition )
|
||||
{
|
||||
FILE_STRUCT* nextFile;
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Synchronize open files
|
||||
nextFile = partition->firstOpenFile;
|
||||
while (nextFile) {
|
||||
_FAT_syncToDisc (nextFile);
|
||||
nextFile = nextFile->nextOpenFile;
|
||||
}
|
||||
// Synchronize open files
|
||||
nextFile = partition->firstOpenFile;
|
||||
while ( nextFile )
|
||||
{
|
||||
_FAT_syncToDisc ( nextFile );
|
||||
nextFile = nextFile->nextOpenFile;
|
||||
}
|
||||
|
||||
// Free memory used by the cache, writing it to disc at the same time
|
||||
_FAT_cache_destructor (partition->cache);
|
||||
// Free memory used by the cache, writing it to disc at the same time
|
||||
_FAT_cache_destructor ( partition->cache );
|
||||
|
||||
// Unlock the partition and destroy the lock
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_lock_deinit(&partition->lock);
|
||||
// Unlock the partition and destroy the lock
|
||||
_FAT_unlock( &partition->lock );
|
||||
_FAT_lock_deinit( &partition->lock );
|
||||
|
||||
// Free memory used by the partition
|
||||
_FAT_mem_free (partition);
|
||||
// Free memory used by the partition
|
||||
_FAT_mem_free ( partition );
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_getPartitionFromPath (const char* path) {
|
||||
const devoptab_t *devops;
|
||||
PARTITION* _FAT_partition_getPartitionFromPath ( const char* path )
|
||||
{
|
||||
const devoptab_t *devops;
|
||||
|
||||
devops = GetDeviceOpTab (path);
|
||||
devops = GetDeviceOpTab ( path );
|
||||
|
||||
if (!devops) {
|
||||
return NULL;
|
||||
}
|
||||
if ( !devops )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PARTITION*)devops->deviceData;
|
||||
return ( PARTITION* )devops->deviceData;
|
||||
}
|
||||
|
@ -40,49 +40,51 @@ extern const char* DEVICE_NAME;
|
||||
// Filesystem type
|
||||
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
sec_t fatStart;
|
||||
uint32_t sectorsPerFat;
|
||||
uint32_t lastCluster;
|
||||
uint32_t firstFree;
|
||||
typedef struct
|
||||
{
|
||||
sec_t fatStart;
|
||||
uint32_t sectorsPerFat;
|
||||
uint32_t lastCluster;
|
||||
uint32_t firstFree;
|
||||
} FAT;
|
||||
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
CACHE* cache;
|
||||
// Info about the partition
|
||||
FS_TYPE filesysType;
|
||||
uint64_t totalSize;
|
||||
sec_t rootDirStart;
|
||||
uint32_t rootDirCluster;
|
||||
uint32_t numberOfSectors;
|
||||
sec_t dataStart;
|
||||
uint32_t bytesPerSector;
|
||||
uint32_t sectorsPerCluster;
|
||||
uint32_t bytesPerCluster;
|
||||
FAT fat;
|
||||
// Values that may change after construction
|
||||
uint32_t cwdCluster; // Current working directory cluster
|
||||
int openFileCount;
|
||||
struct _FILE_STRUCT* firstOpenFile; // The start of a linked list of files
|
||||
mutex_t lock; // A lock for partition operations
|
||||
bool readOnly; // If this is set, then do not try writing to the disc
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
CACHE* cache;
|
||||
// Info about the partition
|
||||
FS_TYPE filesysType;
|
||||
uint64_t totalSize;
|
||||
sec_t rootDirStart;
|
||||
uint32_t rootDirCluster;
|
||||
uint32_t numberOfSectors;
|
||||
sec_t dataStart;
|
||||
uint32_t bytesPerSector;
|
||||
uint32_t sectorsPerCluster;
|
||||
uint32_t bytesPerCluster;
|
||||
FAT fat;
|
||||
// Values that may change after construction
|
||||
uint32_t cwdCluster; // Current working directory cluster
|
||||
int openFileCount;
|
||||
struct _FILE_STRUCT* firstOpenFile; // The start of a linked list of files
|
||||
mutex_t lock; // A lock for partition operations
|
||||
bool readOnly; // If this is set, then do not try writing to the disc
|
||||
} PARTITION;
|
||||
|
||||
/*
|
||||
Mount the supplied device and return a pointer to the struct necessary to use it
|
||||
*/
|
||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector);
|
||||
PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector );
|
||||
|
||||
/*
|
||||
Dismount the device and free all structures used.
|
||||
Will also attempt to synchronise all open files to disc.
|
||||
*/
|
||||
void _FAT_partition_destructor (PARTITION* partition);
|
||||
void _FAT_partition_destructor ( PARTITION* partition );
|
||||
|
||||
/*
|
||||
Return the partition specified in a path, as taken from the devoptab.
|
||||
*/
|
||||
PARTITION* _FAT_partition_getPartitionFromPath (const char* path);
|
||||
PARTITION* _FAT_partition_getPartitionFromPath ( const char* path );
|
||||
|
||||
#endif // _PARTITION_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,30 +25,30 @@
|
||||
#define ACLS_H
|
||||
|
||||
/*
|
||||
* JPA configuration modes for security.c / acls.c
|
||||
* should be moved to some config file
|
||||
* JPA configuration modes for security.c / acls.c
|
||||
* should be moved to some config file
|
||||
*/
|
||||
|
||||
#define BUFSZ 1024 /* buffer size to read mapping file */
|
||||
#define BUFSZ 1024 /* buffer size to read mapping file */
|
||||
#define MAPPINGFILE ".NTFS-3G/UserMapping" /* default mapping file */
|
||||
#define LINESZ 120 /* maximum useful size of a mapping line */
|
||||
#define CACHE_PERMISSIONS_BITS 6 /* log2 of unitary allocation of permissions */
|
||||
#define CACHE_PERMISSIONS_SIZE 262144 /* max cacheable permissions */
|
||||
|
||||
/*
|
||||
* JPA The following must be in some library...
|
||||
* but did not found out where
|
||||
* JPA The following must be in some library...
|
||||
* but did not found out where
|
||||
*/
|
||||
|
||||
#define endian_rev16(x) (((x >> 8) & 255) | ((x & 255) << 8))
|
||||
#define endian_rev32(x) (((x >> 24) & 255) | ((x >> 8) & 0xff00) \
|
||||
| ((x & 0xff00) << 8) | ((x & 255) << 24))
|
||||
| ((x & 0xff00) << 8) | ((x & 255) << 24))
|
||||
|
||||
#define cpu_to_be16(x) endian_rev16(cpu_to_le16(x))
|
||||
#define cpu_to_be32(x) endian_rev32(cpu_to_le32(x))
|
||||
|
||||
/*
|
||||
* Macro definitions needed to share code with secaudit
|
||||
* Macro definitions needed to share code with secaudit
|
||||
*/
|
||||
|
||||
#define NTFS_FIND_USID(map,uid,buf) ntfs_find_usid(map,uid,buf)
|
||||
@ -58,25 +58,25 @@
|
||||
|
||||
|
||||
/*
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
* when setting, set them all
|
||||
* when checking, check one is present
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
* when setting, set them all
|
||||
* when checking, check one is present
|
||||
*/
|
||||
|
||||
/* flags which are set to mean exec, write or read */
|
||||
/* flags which are set to mean exec, write or read */
|
||||
|
||||
#define FILE_READ (FILE_READ_DATA)
|
||||
#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
#define FILE_EXEC (FILE_EXECUTE)
|
||||
#define DIR_READ FILE_LIST_DIRECTORY
|
||||
#define DIR_WRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD \
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
#define DIR_EXEC (FILE_TRAVERSE)
|
||||
|
||||
/* flags tested for meaning exec, write or read */
|
||||
/* tests for write allow for interpretation of a sticky bit */
|
||||
/* flags tested for meaning exec, write or read */
|
||||
/* tests for write allow for interpretation of a sticky bit */
|
||||
|
||||
#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ)
|
||||
#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)
|
||||
@ -85,115 +85,116 @@
|
||||
#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE)
|
||||
#define DIR_GEXEC (FILE_TRAVERSE | GENERIC_EXECUTE)
|
||||
|
||||
/* standard owner (and administrator) rights */
|
||||
/* standard owner (and administrator) rights */
|
||||
|
||||
#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \
|
||||
| SYNCHRONIZE \
|
||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
||||
| FILE_READ_EA | FILE_WRITE_EA)
|
||||
| SYNCHRONIZE \
|
||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
||||
| FILE_READ_EA | FILE_WRITE_EA)
|
||||
|
||||
/* standard world rights */
|
||||
/* standard world rights */
|
||||
|
||||
#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \
|
||||
| SYNCHRONIZE)
|
||||
| SYNCHRONIZE)
|
||||
|
||||
/* inheritance flags for files and directories */
|
||||
/* inheritance flags for files and directories */
|
||||
|
||||
#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE
|
||||
#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
|
||||
|
||||
/*
|
||||
* To identify NTFS ACL meaning Posix ACL granted to root
|
||||
* we use rights always granted to anybody, so they have no impact
|
||||
* either on Windows or on Linux.
|
||||
* To identify NTFS ACL meaning Posix ACL granted to root
|
||||
* we use rights always granted to anybody, so they have no impact
|
||||
* either on Windows or on Linux.
|
||||
*/
|
||||
|
||||
#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */
|
||||
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
|
||||
#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */
|
||||
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
|
||||
|
||||
/*
|
||||
* A type large enough to hold any SID
|
||||
* A type large enough to hold any SID
|
||||
*/
|
||||
|
||||
typedef char BIGSID[40];
|
||||
|
||||
/*
|
||||
* Struct to hold the input mapping file
|
||||
* (private to this module)
|
||||
* Struct to hold the input mapping file
|
||||
* (private to this module)
|
||||
*/
|
||||
|
||||
struct MAPLIST {
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
char *sidstr; /* sid text from the same record */
|
||||
char maptext[LINESZ + 1];
|
||||
struct MAPLIST
|
||||
{
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
char *sidstr; /* sid text from the same record */
|
||||
char maptext[LINESZ + 1];
|
||||
};
|
||||
|
||||
typedef int (*FILEREADER)(void *fileid, char *buf, size_t size, off_t pos);
|
||||
typedef int ( *FILEREADER )( void *fileid, char *buf, size_t size, off_t pos );
|
||||
|
||||
/*
|
||||
* Constants defined in acls.c
|
||||
* Constants defined in acls.c
|
||||
*/
|
||||
|
||||
extern const SID *adminsid;
|
||||
extern const SID *worldsid;
|
||||
|
||||
/*
|
||||
* Functions defined in acls.c
|
||||
* Functions defined in acls.c
|
||||
*/
|
||||
|
||||
BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz);
|
||||
BOOL ntfs_valid_pattern(const SID *sid);
|
||||
BOOL ntfs_valid_sid(const SID *sid);
|
||||
BOOL ntfs_same_sid(const SID *first, const SID *second);
|
||||
BOOL ntfs_valid_descr( const char *securattr, unsigned int attrsz );
|
||||
BOOL ntfs_valid_pattern( const SID *sid );
|
||||
BOOL ntfs_valid_sid( const SID *sid );
|
||||
BOOL ntfs_same_sid( const SID *first, const SID *second );
|
||||
|
||||
BOOL ntfs_is_user_sid(const SID *usid);
|
||||
BOOL ntfs_is_user_sid( const SID *usid );
|
||||
|
||||
|
||||
int ntfs_sid_size(const SID * sid);
|
||||
unsigned int ntfs_attr_size(const char *attr);
|
||||
int ntfs_sid_size( const SID * sid );
|
||||
unsigned int ntfs_attr_size( const char *attr );
|
||||
|
||||
const SID *ntfs_find_usid(const struct MAPPING *usermapping,
|
||||
uid_t uid, SID *pdefsid);
|
||||
const SID *ntfs_find_gsid(const struct MAPPING *groupmapping,
|
||||
gid_t gid, SID *pdefsid);
|
||||
uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid);
|
||||
gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
||||
const SID *ntfs_acl_owner(const char *secattr);
|
||||
const SID *ntfs_find_usid( const struct MAPPING *usermapping,
|
||||
uid_t uid, SID *pdefsid );
|
||||
const SID *ntfs_find_gsid( const struct MAPPING *groupmapping,
|
||||
gid_t gid, SID *pdefsid );
|
||||
uid_t ntfs_find_user( const struct MAPPING *usermapping, const SID *usid );
|
||||
gid_t ntfs_find_group( const struct MAPPING *groupmapping, const SID * gsid );
|
||||
const SID *ntfs_acl_owner( const char *secattr );
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc);
|
||||
void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc);
|
||||
int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode);
|
||||
BOOL ntfs_valid_posix( const struct POSIX_SECURITY *pxdesc );
|
||||
void ntfs_sort_posix( struct POSIX_SECURITY *pxdesc );
|
||||
int ntfs_merge_mode_posix( struct POSIX_SECURITY *pxdesc, mode_t mode );
|
||||
struct POSIX_SECURITY *ntfs_build_inherited_posix(
|
||||
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
||||
mode_t umask, BOOL isdir);
|
||||
struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc,
|
||||
const struct POSIX_ACL *newacl, int count, BOOL deflt);
|
||||
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
||||
mode_t umask, BOOL isdir );
|
||||
struct POSIX_SECURITY *ntfs_replace_acl( const struct POSIX_SECURITY *oldpxdesc,
|
||||
const struct POSIX_ACL *newacl, int count, BOOL deflt );
|
||||
struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
struct MAPPING* const mapping[],
|
||||
const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first,
|
||||
const struct POSIX_SECURITY *second);
|
||||
char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
||||
struct POSIX_SECURITY *pxdesc,
|
||||
int isdir, const SID *usid, const SID *gsid);
|
||||
struct MAPPING* const mapping[],
|
||||
const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir );
|
||||
struct POSIX_SECURITY *ntfs_merge_descr_posix( const struct POSIX_SECURITY *first,
|
||||
const struct POSIX_SECURITY *second );
|
||||
char *ntfs_build_descr_posix( struct MAPPING* const mapping[],
|
||||
struct POSIX_SECURITY *pxdesc,
|
||||
int isdir, const SID *usid, const SID *gsid );
|
||||
|
||||
#endif /* POSIXACLS */
|
||||
|
||||
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
const SID *usid, const SID *gsid, BOOL fordir);
|
||||
int ntfs_build_permissions(const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
char *ntfs_build_descr(mode_t mode,
|
||||
int isdir, const SID * usid, const SID * gsid);
|
||||
struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid);
|
||||
struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem);
|
||||
struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem);
|
||||
void ntfs_free_mapping(struct MAPPING *mapping[]);
|
||||
int ntfs_inherit_acl( const ACL *oldacl, ACL *newacl,
|
||||
const SID *usid, const SID *gsid, BOOL fordir );
|
||||
int ntfs_build_permissions( const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir );
|
||||
char *ntfs_build_descr( mode_t mode,
|
||||
int isdir, const SID * usid, const SID * gsid );
|
||||
struct MAPLIST *ntfs_read_mapping( FILEREADER reader, void *fileid );
|
||||
struct MAPPING *ntfs_do_user_mapping( struct MAPLIST *firstitem );
|
||||
struct MAPPING *ntfs_do_group_mapping( struct MAPLIST *firstitem );
|
||||
void ntfs_free_mapping( struct MAPPING *mapping[] );
|
||||
|
||||
#endif /* ACLS_H */
|
||||
|
||||
|
10592
source/libntfs/attrib.c
10592
source/libntfs/attrib.c
File diff suppressed because it is too large
Load Diff
@ -49,19 +49,20 @@ extern ntfschar TXF_DATA[10];
|
||||
*
|
||||
* TODO: Describe them.
|
||||
*/
|
||||
typedef enum {
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
LCN_EINVAL = -4,
|
||||
LCN_EIO = -5,
|
||||
typedef enum
|
||||
{
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
LCN_EINVAL = -4,
|
||||
LCN_EIO = -5,
|
||||
} ntfs_lcn_special_values;
|
||||
|
||||
/**
|
||||
* struct ntfs_attr_search_ctx - search context used in attribute search functions
|
||||
* @mrec: buffer containing mft record to search
|
||||
* @attr: attribute record in @mrec where to begin/continue search
|
||||
* @is_first: if true lookup_attr() begins search with @attr, else after @attr
|
||||
* @mrec: buffer containing mft record to search
|
||||
* @attr: attribute record in @mrec where to begin/continue search
|
||||
* @is_first: if true lookup_attr() begins search with @attr, else after @attr
|
||||
*
|
||||
* Structure must be initialized to zero before the first call to one of the
|
||||
* attribute search functions. Initialize @mrec to point to the mft record to
|
||||
@ -75,35 +76,36 @@ typedef enum {
|
||||
* any modification of the search context, to automagically get the next
|
||||
* matching attribute.
|
||||
*/
|
||||
struct _ntfs_attr_search_ctx {
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
BOOL is_first;
|
||||
ntfs_inode *ntfs_ino;
|
||||
ATTR_LIST_ENTRY *al_entry;
|
||||
ntfs_inode *base_ntfs_ino;
|
||||
MFT_RECORD *base_mrec;
|
||||
ATTR_RECORD *base_attr;
|
||||
struct _ntfs_attr_search_ctx
|
||||
{
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
BOOL is_first;
|
||||
ntfs_inode *ntfs_ino;
|
||||
ATTR_LIST_ENTRY *al_entry;
|
||||
ntfs_inode *base_ntfs_ino;
|
||||
MFT_RECORD *base_mrec;
|
||||
ATTR_RECORD *base_attr;
|
||||
};
|
||||
|
||||
extern void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
|
||||
MFT_RECORD *mrec);
|
||||
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
extern void ntfs_attr_reinit_search_ctx( ntfs_attr_search_ctx *ctx );
|
||||
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx( ntfs_inode *ni,
|
||||
MFT_RECORD *mrec );
|
||||
extern void ntfs_attr_put_search_ctx( ntfs_attr_search_ctx *ctx );
|
||||
|
||||
extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_attr_lookup( const ATTR_TYPES type, const ntfschar *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
||||
ntfs_attr_search_ctx *ctx );
|
||||
|
||||
extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_attr_position( const ATTR_TYPES type, ntfs_attr_search_ctx *ctx );
|
||||
|
||||
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
extern ATTR_DEF *ntfs_attr_find_in_attrdef( const ntfs_volume *vol,
|
||||
const ATTR_TYPES type );
|
||||
|
||||
/**
|
||||
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
||||
* @ctx: initialised attribute search context
|
||||
* @ctx: initialised attribute search context
|
||||
*
|
||||
* Syntactic sugar for walking attributes in an inode.
|
||||
*
|
||||
@ -111,42 +113,42 @@ extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||
* ntfs_attr_lookup().
|
||||
*
|
||||
* Example: When you want to enumerate all attributes in an open ntfs inode
|
||||
* @ni, you can simply do:
|
||||
* @ni, you can simply do:
|
||||
*
|
||||
* int err;
|
||||
* ntfs_attr_search_ctx *ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
* if (!ctx)
|
||||
* // Error code is in errno. Handle this case.
|
||||
* while (!(err = ntfs_attrs_walk(ctx))) {
|
||||
* ATTR_RECORD *attr = ctx->attr;
|
||||
* // attr now contains the next attribute. Do whatever you want
|
||||
* // with it and then just continue with the while loop.
|
||||
* }
|
||||
* if (err && errno != ENOENT)
|
||||
* // Ooops. An error occurred! You should handle this case.
|
||||
* // Now finished with all attributes in the inode.
|
||||
* int err;
|
||||
* ntfs_attr_search_ctx *ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
* if (!ctx)
|
||||
* // Error code is in errno. Handle this case.
|
||||
* while (!(err = ntfs_attrs_walk(ctx))) {
|
||||
* ATTR_RECORD *attr = ctx->attr;
|
||||
* // attr now contains the next attribute. Do whatever you want
|
||||
* // with it and then just continue with the while loop.
|
||||
* }
|
||||
* if (err && errno != ENOENT)
|
||||
* // Ooops. An error occurred! You should handle this case.
|
||||
* // Now finished with all attributes in the inode.
|
||||
*/
|
||||
static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
|
||||
static __inline__ int ntfs_attrs_walk( ntfs_attr_search_ctx *ctx )
|
||||
{
|
||||
return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
|
||||
NULL, 0, ctx);
|
||||
return ntfs_attr_lookup( AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
|
||||
NULL, 0, ctx );
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ntfs_attr - ntfs in memory non-resident attribute structure
|
||||
* @rl: if not NULL, the decompressed runlist
|
||||
* @ni: base ntfs inode to which this attribute belongs
|
||||
* @type: attribute type
|
||||
* @name: Unicode name of the attribute
|
||||
* @name_len: length of @name in Unicode characters
|
||||
* @state: NTFS attribute specific flags describing this attribute
|
||||
* @allocated_size: copy from the attribute record
|
||||
* @data_size: copy from the attribute record
|
||||
* @initialized_size: copy from the attribute record
|
||||
* @compressed_size: copy from the attribute record
|
||||
* @compression_block_size: size of a compression block (cb)
|
||||
* @compression_block_size_bits: log2 of the size of a cb
|
||||
* @compression_block_clusters: number of clusters per cb
|
||||
* @rl: if not NULL, the decompressed runlist
|
||||
* @ni: base ntfs inode to which this attribute belongs
|
||||
* @type: attribute type
|
||||
* @name: Unicode name of the attribute
|
||||
* @name_len: length of @name in Unicode characters
|
||||
* @state: NTFS attribute specific flags describing this attribute
|
||||
* @allocated_size: copy from the attribute record
|
||||
* @data_size: copy from the attribute record
|
||||
* @initialized_size: copy from the attribute record
|
||||
* @compressed_size: copy from the attribute record
|
||||
* @compression_block_size: size of a compression block (cb)
|
||||
* @compression_block_size_bits: log2 of the size of a cb
|
||||
* @compression_block_clusters: number of clusters per cb
|
||||
*
|
||||
* This structure exists purely to provide a mechanism of caching the runlist
|
||||
* of an attribute. If you want to operate on a particular attribute extent,
|
||||
@ -174,68 +176,70 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
|
||||
* @state contains NTFS attribute specific flags describing this attribute
|
||||
* structure. See ntfs_attr_state_bits above.
|
||||
*/
|
||||
struct _ntfs_attr {
|
||||
runlist_element *rl;
|
||||
ntfs_inode *ni;
|
||||
ATTR_TYPES type;
|
||||
ATTR_FLAGS data_flags;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
unsigned long state;
|
||||
s64 allocated_size;
|
||||
s64 data_size;
|
||||
s64 initialized_size;
|
||||
s64 compressed_size;
|
||||
u32 compression_block_size;
|
||||
u8 compression_block_size_bits;
|
||||
u8 compression_block_clusters;
|
||||
s8 unused_runs; /* pre-reserved entries available */
|
||||
struct _ntfs_attr
|
||||
{
|
||||
runlist_element *rl;
|
||||
ntfs_inode *ni;
|
||||
ATTR_TYPES type;
|
||||
ATTR_FLAGS data_flags;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
unsigned long state;
|
||||
s64 allocated_size;
|
||||
s64 data_size;
|
||||
s64 initialized_size;
|
||||
s64 compressed_size;
|
||||
u32 compression_block_size;
|
||||
u8 compression_block_size_bits;
|
||||
u8 compression_block_clusters;
|
||||
s8 unused_runs; /* pre-reserved entries available */
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
||||
* structure
|
||||
*/
|
||||
typedef enum {
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
NA_NonResident, /* 1: Attribute is not resident. */
|
||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
||||
NA_ComprClosing, /* 1: Compressed attribute is being closed */
|
||||
typedef enum
|
||||
{
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
NA_NonResident, /* 1: Attribute is not resident. */
|
||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
||||
NA_ComprClosing, /* 1: Compressed attribute is being closed */
|
||||
} ntfs_attr_state_bits;
|
||||
|
||||
#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
|
||||
#define set_nattr_flag(na, flag) set_bit(NA_##flag, (na)->state)
|
||||
#define clear_nattr_flag(na, flag) clear_bit(NA_##flag, (na)->state)
|
||||
#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
|
||||
#define set_nattr_flag(na, flag) set_bit(NA_##flag, (na)->state)
|
||||
#define clear_nattr_flag(na, flag) clear_bit(NA_##flag, (na)->state)
|
||||
|
||||
#define NAttrInitialized(na) test_nattr_flag(na, Initialized)
|
||||
#define NAttrSetInitialized(na) set_nattr_flag(na, Initialized)
|
||||
#define NAttrClearInitialized(na) clear_nattr_flag(na, Initialized)
|
||||
#define NAttrInitialized(na) test_nattr_flag(na, Initialized)
|
||||
#define NAttrSetInitialized(na) set_nattr_flag(na, Initialized)
|
||||
#define NAttrClearInitialized(na) clear_nattr_flag(na, Initialized)
|
||||
|
||||
#define NAttrNonResident(na) test_nattr_flag(na, NonResident)
|
||||
#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
|
||||
#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
|
||||
#define NAttrNonResident(na) test_nattr_flag(na, NonResident)
|
||||
#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
|
||||
#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
|
||||
|
||||
#define NAttrBeingNonResident(na) test_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrSetBeingNonResident(na) set_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrClearBeingNonResident(na) clear_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrBeingNonResident(na) test_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrSetBeingNonResident(na) set_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrClearBeingNonResident(na) clear_nattr_flag(na, BeingNonResident)
|
||||
|
||||
#define NAttrFullyMapped(na) test_nattr_flag(na, FullyMapped)
|
||||
#define NAttrSetFullyMapped(na) set_nattr_flag(na, FullyMapped)
|
||||
#define NAttrClearFullyMapped(na) clear_nattr_flag(na, FullyMapped)
|
||||
#define NAttrFullyMapped(na) test_nattr_flag(na, FullyMapped)
|
||||
#define NAttrSetFullyMapped(na) set_nattr_flag(na, FullyMapped)
|
||||
#define NAttrClearFullyMapped(na) clear_nattr_flag(na, FullyMapped)
|
||||
|
||||
#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
|
||||
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
|
||||
#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing)
|
||||
#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
|
||||
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
|
||||
#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing)
|
||||
|
||||
#define GenNAttrIno(func_name, flag) \
|
||||
extern int NAttr##func_name(ntfs_attr *na); \
|
||||
extern void NAttrSet##func_name(ntfs_attr *na); \
|
||||
#define GenNAttrIno(func_name, flag) \
|
||||
extern int NAttr##func_name(ntfs_attr *na); \
|
||||
extern void NAttrSet##func_name(ntfs_attr *na); \
|
||||
extern void NAttrClear##func_name(ntfs_attr *na);
|
||||
|
||||
GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED)
|
||||
GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED)
|
||||
GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
||||
GenNAttrIno( Compressed, FILE_ATTR_COMPRESSED )
|
||||
GenNAttrIno( Encrypted, FILE_ATTR_ENCRYPTED )
|
||||
GenNAttrIno( Sparse, FILE_ATTR_SPARSE_FILE )
|
||||
#undef GenNAttrIno
|
||||
|
||||
/**
|
||||
@ -243,99 +247,100 @@ GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
||||
*
|
||||
* For convenience. Used in the attr structure.
|
||||
*/
|
||||
typedef union {
|
||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||
a_val without specifying any of the below. */
|
||||
STANDARD_INFORMATION std_inf;
|
||||
ATTR_LIST_ENTRY al_entry;
|
||||
FILE_NAME_ATTR filename;
|
||||
OBJECT_ID_ATTR obj_id;
|
||||
SECURITY_DESCRIPTOR_ATTR sec_desc;
|
||||
VOLUME_NAME vol_name;
|
||||
VOLUME_INFORMATION vol_inf;
|
||||
DATA_ATTR data;
|
||||
INDEX_ROOT index_root;
|
||||
INDEX_BLOCK index_blk;
|
||||
BITMAP_ATTR bmp;
|
||||
REPARSE_POINT reparse;
|
||||
EA_INFORMATION ea_inf;
|
||||
EA_ATTR ea;
|
||||
PROPERTY_SET property_set;
|
||||
LOGGED_UTILITY_STREAM logged_util_stream;
|
||||
EFS_ATTR_HEADER efs;
|
||||
typedef union
|
||||
{
|
||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||
a_val without specifying any of the below. */
|
||||
STANDARD_INFORMATION std_inf;
|
||||
ATTR_LIST_ENTRY al_entry;
|
||||
FILE_NAME_ATTR filename;
|
||||
OBJECT_ID_ATTR obj_id;
|
||||
SECURITY_DESCRIPTOR_ATTR sec_desc;
|
||||
VOLUME_NAME vol_name;
|
||||
VOLUME_INFORMATION vol_inf;
|
||||
DATA_ATTR data;
|
||||
INDEX_ROOT index_root;
|
||||
INDEX_BLOCK index_blk;
|
||||
BITMAP_ATTR bmp;
|
||||
REPARSE_POINT reparse;
|
||||
EA_INFORMATION ea_inf;
|
||||
EA_ATTR ea;
|
||||
PROPERTY_SET property_set;
|
||||
LOGGED_UTILITY_STREAM logged_util_stream;
|
||||
EFS_ATTR_HEADER efs;
|
||||
} attr_val;
|
||||
|
||||
extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
|
||||
const ATTR_FLAGS data_flags, const BOOL encrypted,
|
||||
const BOOL sparse,
|
||||
const s64 allocated_size, const s64 data_size,
|
||||
const s64 initialized_size, const s64 compressed_size,
|
||||
const u8 compression_unit);
|
||||
extern void ntfs_attr_init( ntfs_attr *na, const BOOL non_resident,
|
||||
const ATTR_FLAGS data_flags, const BOOL encrypted,
|
||||
const BOOL sparse,
|
||||
const s64 allocated_size, const s64 data_size,
|
||||
const s64 initialized_size, const s64 compressed_size,
|
||||
const u8 compression_unit );
|
||||
|
||||
/* warning : in the following "name" has to be freeable */
|
||||
/* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */
|
||||
extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern void ntfs_attr_close(ntfs_attr *na);
|
||||
/* warning : in the following "name" has to be freeable */
|
||||
/* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */
|
||||
extern ntfs_attr *ntfs_attr_open( ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len );
|
||||
extern void ntfs_attr_close( ntfs_attr *na );
|
||||
|
||||
extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count,
|
||||
const void *b);
|
||||
extern int ntfs_attr_pclose(ntfs_attr *na);
|
||||
extern s64 ntfs_attr_pread( ntfs_attr *na, const s64 pos, s64 count,
|
||||
void *b );
|
||||
extern s64 ntfs_attr_pwrite( ntfs_attr *na, const s64 pos, s64 count,
|
||||
const void *b );
|
||||
extern int ntfs_attr_pclose( ntfs_attr *na );
|
||||
|
||||
extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len, s64 *data_size);
|
||||
extern void *ntfs_attr_readall( ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len, s64 *data_size );
|
||||
|
||||
extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos,
|
||||
const s64 bk_cnt, const u32 bk_size, void *dst);
|
||||
extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos,
|
||||
s64 bk_cnt, const u32 bk_size, void *src);
|
||||
extern s64 ntfs_attr_mst_pread( ntfs_attr *na, const s64 pos,
|
||||
const s64 bk_cnt, const u32 bk_size, void *dst );
|
||||
extern s64 ntfs_attr_mst_pwrite( ntfs_attr *na, const s64 pos,
|
||||
s64 bk_cnt, const u32 bk_size, void *src );
|
||||
|
||||
extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn);
|
||||
extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
||||
extern int ntfs_attr_map_runlist( ntfs_attr *na, VCN vcn );
|
||||
extern int ntfs_attr_map_whole_runlist( ntfs_attr *na );
|
||||
|
||||
extern LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn);
|
||||
extern runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
|
||||
extern LCN ntfs_attr_vcn_to_lcn( ntfs_attr *na, const VCN vcn );
|
||||
extern runlist_element *ntfs_attr_find_vcn( ntfs_attr *na, const VCN vcn );
|
||||
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type, const s64 size);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
int ntfs_attr_force_non_resident(ntfs_attr *na);
|
||||
extern int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
|
||||
extern int ntfs_attr_size_bounds_check( const ntfs_volume *vol,
|
||||
const ATTR_TYPES type, const s64 size );
|
||||
extern int ntfs_attr_can_be_resident( const ntfs_volume *vol,
|
||||
const ATTR_TYPES type );
|
||||
int ntfs_attr_make_non_resident( ntfs_attr *na,
|
||||
ntfs_attr_search_ctx *ctx );
|
||||
int ntfs_attr_force_non_resident( ntfs_attr *na );
|
||||
extern int ntfs_make_room_for_attr( MFT_RECORD *m, u8 *pos, u32 size );
|
||||
|
||||
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
||||
ATTR_FLAGS flags);
|
||||
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
||||
ATTR_FLAGS flags);
|
||||
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_resident_attr_record_add( ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
||||
ATTR_FLAGS flags );
|
||||
extern int ntfs_non_resident_attr_record_add( ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
||||
ATTR_FLAGS flags );
|
||||
extern int ntfs_attr_record_rm( ntfs_attr_search_ctx *ctx );
|
||||
|
||||
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, s64 size);
|
||||
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask);
|
||||
extern int ntfs_attr_rm(ntfs_attr *na);
|
||||
extern int ntfs_attr_add( ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, s64 size );
|
||||
extern int ntfs_attr_set_flags( ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask );
|
||||
extern int ntfs_attr_rm( ntfs_attr *na );
|
||||
|
||||
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
|
||||
extern int ntfs_attr_record_resize( MFT_RECORD *m, ATTR_RECORD *a, u32 new_size );
|
||||
|
||||
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 new_size);
|
||||
extern int ntfs_resident_attr_value_resize( MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 new_size );
|
||||
|
||||
extern int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni);
|
||||
extern int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra);
|
||||
extern int ntfs_attr_record_move_to( ntfs_attr_search_ctx *ctx, ntfs_inode *ni );
|
||||
extern int ntfs_attr_record_move_away( ntfs_attr_search_ctx *ctx, int extra );
|
||||
|
||||
extern int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn);
|
||||
extern int ntfs_attr_update_mapping_pairs( ntfs_attr *na, VCN from_vcn );
|
||||
|
||||
extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
|
||||
extern int ntfs_attr_truncate( ntfs_attr *na, const s64 newsize );
|
||||
|
||||
/**
|
||||
* get_attribute_value_length - return the length of the value of an attribute
|
||||
* @a: pointer to a buffer containing the attribute record
|
||||
* @a: pointer to a buffer containing the attribute record
|
||||
*
|
||||
* Return the byte size of the attribute value of the attribute @a (as it
|
||||
* would be after eventual decompression and filling in of holes if sparse).
|
||||
@ -344,13 +349,13 @@ extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
|
||||
*
|
||||
* FIXME: Describe possible errnos.
|
||||
*/
|
||||
extern s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a);
|
||||
extern s64 ntfs_get_attribute_value_length( const ATTR_RECORD *a );
|
||||
|
||||
/**
|
||||
* get_attribute_value - return the attribute value of an attribute
|
||||
* @vol: volume on which the attribute is present
|
||||
* @a: attribute to get the value of
|
||||
* @b: destination buffer for the attribute value
|
||||
* @vol: volume on which the attribute is present
|
||||
* @a: attribute to get the value of
|
||||
* @b: destination buffer for the attribute value
|
||||
*
|
||||
* Make a copy of the attribute value of the attribute @a into the destination
|
||||
* buffer @b. Note, that the size of @b has to be at least equal to the value
|
||||
@ -360,16 +365,16 @@ extern s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a);
|
||||
* then nothing was read due to a zero-length attribute value, otherwise
|
||||
* errno describes the error.
|
||||
*/
|
||||
extern s64 ntfs_get_attribute_value(const ntfs_volume *vol,
|
||||
const ATTR_RECORD *a, u8 *b);
|
||||
extern s64 ntfs_get_attribute_value( const ntfs_volume *vol,
|
||||
const ATTR_RECORD *a, u8 *b );
|
||||
|
||||
extern void ntfs_attr_name_free(char **name);
|
||||
extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len);
|
||||
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
|
||||
extern void ntfs_attr_name_free( char **name );
|
||||
extern char *ntfs_attr_name_get( const ntfschar *uname, const int uname_len );
|
||||
extern int ntfs_attr_exist( ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len );
|
||||
extern int ntfs_attr_remove( ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len );
|
||||
extern s64 ntfs_attr_get_free_bits( ntfs_attr *na );
|
||||
|
||||
#endif /* defined _NTFS_ATTRIB_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* attrlist.c - Attribute list attribute handling code. Originated from the Linux-NTFS
|
||||
* project.
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yura Pakhuchiy
|
||||
@ -47,7 +47,7 @@
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_need - check whether inode need attribute list
|
||||
* @ni: opened ntfs inode for which perform check
|
||||
* @ni: opened ntfs inode for which perform check
|
||||
*
|
||||
* Check whether all are attributes belong to one MFT record, in that case
|
||||
* attribute list is not needed.
|
||||
@ -55,260 +55,278 @@
|
||||
* Return 1 if inode need attribute list, 0 if not, -1 on error with errno set
|
||||
* to the error code. If function succeed errno set to 0. The following error
|
||||
* codes are defined:
|
||||
* EINVAL - Invalid arguments passed to function or attribute haven't got
|
||||
* attribute list.
|
||||
* EINVAL - Invalid arguments passed to function or attribute haven't got
|
||||
* attribute list.
|
||||
*/
|
||||
int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
int ntfs_attrlist_need( ntfs_inode *ni )
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
|
||||
if (!ni) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ( !ni )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
|
||||
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
ntfs_log_trace("Inode haven't got attribute list.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ( !NInoAttrList( ni ) )
|
||||
{
|
||||
ntfs_log_trace( "Inode haven't got attribute list.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ni->attr_list) {
|
||||
ntfs_log_trace("Corrupt in-memory struct.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ( !ni->attr_list )
|
||||
{
|
||||
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
ale = (ATTR_LIST_ENTRY *)ni->attr_list;
|
||||
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
||||
if (MREF_LE(ale->mft_reference) != ni->mft_no)
|
||||
return 1;
|
||||
ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));
|
||||
}
|
||||
return 0;
|
||||
errno = 0;
|
||||
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
|
||||
while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
|
||||
{
|
||||
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
|
||||
return 1;
|
||||
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_entry_add - add an attribute list attribute entry
|
||||
* @ni: opened ntfs inode, which contains that attribute
|
||||
* @attr: attribute record to add to attribute list
|
||||
* @ni: opened ntfs inode, which contains that attribute
|
||||
* @attr: attribute record to add to attribute list
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code. The
|
||||
* following error codes are defined:
|
||||
* EINVAL - Invalid arguments passed to function.
|
||||
* ENOMEM - Not enough memory to allocate necessary buffers.
|
||||
* EIO - I/O error occurred or damaged filesystem.
|
||||
* EEXIST - Such attribute already present in attribute list.
|
||||
* EINVAL - Invalid arguments passed to function.
|
||||
* ENOMEM - Not enough memory to allocate necessary buffers.
|
||||
* EIO - I/O error occurred or damaged filesystem.
|
||||
* EEXIST - Such attribute already present in attribute list.
|
||||
*/
|
||||
int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
int ntfs_attrlist_entry_add( ntfs_inode *ni, ATTR_RECORD *attr )
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
MFT_REF mref;
|
||||
ntfs_attr *na = NULL;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
u8 *new_al;
|
||||
int entry_len, entry_offset, err;
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
MFT_REF mref;
|
||||
ntfs_attr *na = NULL;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
u8 *new_al;
|
||||
int entry_len, entry_offset, err;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
|
||||
(long long) ni->mft_no,
|
||||
(unsigned) le32_to_cpu(attr->type));
|
||||
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x.\n",
|
||||
( long long ) ni->mft_no,
|
||||
( unsigned ) le32_to_cpu( attr->type ) );
|
||||
|
||||
if (!ni || !attr) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ( !ni || !attr )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mref = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
|
||||
mref = MK_LE_MREF( ni->mft_no, le16_to_cpu( ni->mrec->sequence_number ) );
|
||||
|
||||
if (ni->nr_extents == -1)
|
||||
ni = ni->base_ni;
|
||||
if ( ni->nr_extents == -1 )
|
||||
ni = ni->base_ni;
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
ntfs_log_trace("Attribute list isn't present.\n");
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
if ( !NInoAttrList( ni ) )
|
||||
{
|
||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Determine size and allocate memory for new attribute list. */
|
||||
entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
|
||||
attr->name_length + 7) & ~7;
|
||||
new_al = ntfs_calloc(ni->attr_list_size + entry_len);
|
||||
if (!new_al)
|
||||
return -1;
|
||||
/* Determine size and allocate memory for new attribute list. */
|
||||
entry_len = ( sizeof( ATTR_LIST_ENTRY ) + sizeof( ntfschar ) *
|
||||
attr->name_length + 7 ) & ~7;
|
||||
new_al = ntfs_calloc( ni->attr_list_size + entry_len );
|
||||
if ( !new_al )
|
||||
return -1;
|
||||
|
||||
/* Find place for the new entry. */
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
|
||||
((u8*)attr + le16_to_cpu(attr->name_offset)) :
|
||||
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
|
||||
(attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) :
|
||||
0, (attr->non_resident) ? NULL : ((u8*)attr +
|
||||
le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
|
||||
0 : le32_to_cpu(attr->value_length), ctx)) {
|
||||
/* Found some extent, check it to be before new extent. */
|
||||
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) {
|
||||
err = EEXIST;
|
||||
ntfs_log_trace("Such attribute already present in the "
|
||||
"attribute list.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto err_out;
|
||||
}
|
||||
/* Add new entry after this extent. */
|
||||
ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
|
||||
le16_to_cpu(ctx->al_entry->length));
|
||||
} else {
|
||||
/* Check for real errors. */
|
||||
if (errno != ENOENT) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto err_out;
|
||||
}
|
||||
/* No previous extents found. */
|
||||
ale = ctx->al_entry;
|
||||
}
|
||||
/* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
/* Find place for the new entry. */
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if ( !ctx )
|
||||
{
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
if ( !ntfs_attr_lookup( attr->type, ( attr->name_length ) ? ( ntfschar* )
|
||||
( ( u8* )attr + le16_to_cpu( attr->name_offset ) ) :
|
||||
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
|
||||
( attr->non_resident ) ? le64_to_cpu( attr->lowest_vcn ) :
|
||||
0, ( attr->non_resident ) ? NULL : ( ( u8* )attr +
|
||||
le16_to_cpu( attr->value_offset ) ), ( attr->non_resident ) ?
|
||||
0 : le32_to_cpu( attr->value_length ), ctx ) )
|
||||
{
|
||||
/* Found some extent, check it to be before new extent. */
|
||||
if ( ctx->al_entry->lowest_vcn == attr->lowest_vcn )
|
||||
{
|
||||
err = EEXIST;
|
||||
ntfs_log_trace( "Such attribute already present in the "
|
||||
"attribute list.\n" );
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
goto err_out;
|
||||
}
|
||||
/* Add new entry after this extent. */
|
||||
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
|
||||
le16_to_cpu( ctx->al_entry->length ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for real errors. */
|
||||
if ( errno != ENOENT )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "Attribute lookup failed.\n" );
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
goto err_out;
|
||||
}
|
||||
/* No previous extents found. */
|
||||
ale = ctx->al_entry;
|
||||
}
|
||||
/* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
|
||||
/* Determine new entry offset. */
|
||||
entry_offset = ((u8 *)ale - ni->attr_list);
|
||||
/* Set pointer to new entry. */
|
||||
ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset);
|
||||
/* Zero it to fix valgrind warning. */
|
||||
memset(ale, 0, entry_len);
|
||||
/* Form new entry. */
|
||||
ale->type = attr->type;
|
||||
ale->length = cpu_to_le16(entry_len);
|
||||
ale->name_length = attr->name_length;
|
||||
ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
|
||||
if (attr->non_resident)
|
||||
ale->lowest_vcn = attr->lowest_vcn;
|
||||
else
|
||||
ale->lowest_vcn = 0;
|
||||
ale->mft_reference = mref;
|
||||
ale->instance = attr->instance;
|
||||
memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
|
||||
attr->name_length * sizeof(ntfschar));
|
||||
/* Determine new entry offset. */
|
||||
entry_offset = ( ( u8 * )ale - ni->attr_list );
|
||||
/* Set pointer to new entry. */
|
||||
ale = ( ATTR_LIST_ENTRY * )( new_al + entry_offset );
|
||||
/* Zero it to fix valgrind warning. */
|
||||
memset( ale, 0, entry_len );
|
||||
/* Form new entry. */
|
||||
ale->type = attr->type;
|
||||
ale->length = cpu_to_le16( entry_len );
|
||||
ale->name_length = attr->name_length;
|
||||
ale->name_offset = offsetof( ATTR_LIST_ENTRY, name );
|
||||
if ( attr->non_resident )
|
||||
ale->lowest_vcn = attr->lowest_vcn;
|
||||
else
|
||||
ale->lowest_vcn = 0;
|
||||
ale->mft_reference = mref;
|
||||
ale->instance = attr->instance;
|
||||
memcpy( ale->name, ( u8 * )attr + le16_to_cpu( attr->name_offset ),
|
||||
attr->name_length * sizeof( ntfschar ) );
|
||||
|
||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||
if ( !na )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if ( ntfs_attr_truncate( na, ni->attr_list_size + entry_len ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Copy entries from old attribute list to new. */
|
||||
memcpy(new_al, ni->attr_list, entry_offset);
|
||||
memcpy(new_al + entry_offset + entry_len, ni->attr_list +
|
||||
entry_offset, ni->attr_list_size - entry_offset);
|
||||
/* Copy entries from old attribute list to new. */
|
||||
memcpy( new_al, ni->attr_list, entry_offset );
|
||||
memcpy( new_al + entry_offset + entry_len, ni->attr_list +
|
||||
entry_offset, ni->attr_list_size - entry_offset );
|
||||
|
||||
/* Set new runlist. */
|
||||
free(ni->attr_list);
|
||||
ni->attr_list = new_al;
|
||||
ni->attr_list_size = ni->attr_list_size + entry_len;
|
||||
NInoAttrListSetDirty(ni);
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
return 0;
|
||||
/* Set new runlist. */
|
||||
free( ni->attr_list );
|
||||
ni->attr_list = new_al;
|
||||
ni->attr_list_size = ni->attr_list_size + entry_len;
|
||||
NInoAttrListSetDirty( ni );
|
||||
/* Done! */
|
||||
ntfs_attr_close( na );
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
errno = err;
|
||||
return -1;
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
free( new_al );
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_entry_rm - remove an attribute list attribute entry
|
||||
* @ctx: attribute search context describing the attribute list entry
|
||||
* @ctx: attribute search context describing the attribute list entry
|
||||
*
|
||||
* Remove the attribute list entry @ctx->al_entry from the attribute list.
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code.
|
||||
*/
|
||||
int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
int ntfs_attrlist_entry_rm( ntfs_attr_search_ctx *ctx )
|
||||
{
|
||||
u8 *new_al;
|
||||
int new_al_len;
|
||||
ntfs_inode *base_ni;
|
||||
ntfs_attr *na;
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
int err;
|
||||
u8 *new_al;
|
||||
int new_al_len;
|
||||
ntfs_inode *base_ni;
|
||||
ntfs_attr *na;
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
int err;
|
||||
|
||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ( !ctx || !ctx->ntfs_ino || !ctx->al_entry )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->base_ntfs_ino)
|
||||
base_ni = ctx->base_ntfs_ino;
|
||||
else
|
||||
base_ni = ctx->ntfs_ino;
|
||||
ale = ctx->al_entry;
|
||||
if ( ctx->base_ntfs_ino )
|
||||
base_ni = ctx->base_ntfs_ino;
|
||||
else
|
||||
base_ni = ctx->ntfs_ino;
|
||||
ale = ctx->al_entry;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
||||
(long long) ctx->ntfs_ino->mft_no,
|
||||
(unsigned) le32_to_cpu(ctx->al_entry->type),
|
||||
(long long) le64_to_cpu(ctx->al_entry->lowest_vcn));
|
||||
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
||||
( long long ) ctx->ntfs_ino->mft_no,
|
||||
( unsigned ) le32_to_cpu( ctx->al_entry->type ),
|
||||
( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) );
|
||||
|
||||
if (!NInoAttrList(base_ni)) {
|
||||
ntfs_log_trace("Attribute list isn't present.\n");
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
if ( !NInoAttrList( base_ni ) )
|
||||
{
|
||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate memory for new attribute list. */
|
||||
new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
|
||||
new_al = ntfs_calloc(new_al_len);
|
||||
if (!new_al)
|
||||
return -1;
|
||||
/* Allocate memory for new attribute list. */
|
||||
new_al_len = base_ni->attr_list_size - le16_to_cpu( ale->length );
|
||||
new_al = ntfs_calloc( new_al_len );
|
||||
if ( !new_al )
|
||||
return -1;
|
||||
|
||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, new_al_len)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
||||
if ( !na )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if ( ntfs_attr_truncate( na, new_al_len ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Copy entries from old attribute list to new. */
|
||||
memcpy(new_al, base_ni->attr_list, (u8*)ale - base_ni->attr_list);
|
||||
memcpy(new_al + ((u8*)ale - base_ni->attr_list), (u8*)ale + le16_to_cpu(
|
||||
ale->length), new_al_len - ((u8*)ale - base_ni->attr_list));
|
||||
/* Copy entries from old attribute list to new. */
|
||||
memcpy( new_al, base_ni->attr_list, ( u8* )ale - base_ni->attr_list );
|
||||
memcpy( new_al + ( ( u8* )ale - base_ni->attr_list ), ( u8* )ale + le16_to_cpu(
|
||||
ale->length ), new_al_len - ( ( u8* )ale - base_ni->attr_list ) );
|
||||
|
||||
/* Set new runlist. */
|
||||
free(base_ni->attr_list);
|
||||
base_ni->attr_list = new_al;
|
||||
base_ni->attr_list_size = new_al_len;
|
||||
NInoAttrListSetDirty(base_ni);
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
return 0;
|
||||
/* Set new runlist. */
|
||||
free( base_ni->attr_list );
|
||||
base_ni->attr_list = new_al;
|
||||
base_ni->attr_list_size = new_al_len;
|
||||
NInoAttrListSetDirty( base_ni );
|
||||
/* Done! */
|
||||
ntfs_attr_close( na );
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
errno = err;
|
||||
return -1;
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
free( new_al );
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* attrlist.h - Exports for attribute list attribute handling.
|
||||
* Originated from Linux-NTFS project.
|
||||
* Originated from Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
@ -26,26 +26,26 @@
|
||||
|
||||
#include "attrib.h"
|
||||
|
||||
extern int ntfs_attrlist_need(ntfs_inode *ni);
|
||||
extern int ntfs_attrlist_need( ntfs_inode *ni );
|
||||
|
||||
extern int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr);
|
||||
extern int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_attrlist_entry_add( ntfs_inode *ni, ATTR_RECORD *attr );
|
||||
extern int ntfs_attrlist_entry_rm( ntfs_attr_search_ctx *ctx );
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_mark_dirty - set the attribute list dirty
|
||||
* @ni: ntfs inode which base inode contain dirty attribute list
|
||||
* @ni: ntfs inode which base inode contain dirty attribute list
|
||||
*
|
||||
* Set the attribute list dirty so it is written out later (at the latest at
|
||||
* ntfs_inode_close() time).
|
||||
*
|
||||
* This function cannot fail.
|
||||
*/
|
||||
static __inline__ void ntfs_attrlist_mark_dirty(ntfs_inode *ni)
|
||||
static __inline__ void ntfs_attrlist_mark_dirty( ntfs_inode *ni )
|
||||
{
|
||||
if (ni->nr_extents == -1)
|
||||
NInoAttrListSetDirty(ni->base_ni);
|
||||
else
|
||||
NInoAttrListSetDirty(ni);
|
||||
if ( ni->nr_extents == -1 )
|
||||
NInoAttrListSetDirty( ni->base_ni );
|
||||
else
|
||||
NInoAttrListSetDirty( ni );
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_ATTRLIST_H */
|
||||
|
@ -34,24 +34,28 @@
|
||||
/*-----------------------------------------------------------------
|
||||
Functions to deal with little endian values stored in uint8_t arrays
|
||||
-----------------------------------------------------------------*/
|
||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8));
|
||||
static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
||||
}
|
||||
|
||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
|
||||
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
||||
}
|
||||
|
||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
}
|
||||
|
||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
item[offset + 2] = (uint8_t)(value >> 16);
|
||||
item[offset + 3] = (uint8_t)(value >> 24);
|
||||
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
||||
item[offset + 3] = ( uint8_t )( value >> 24 );
|
||||
}
|
||||
|
||||
#endif // _BIT_OPS_H
|
||||
|
@ -47,254 +47,268 @@
|
||||
|
||||
/**
|
||||
* ntfs_bit_set - set a bit in a field of bits
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to set
|
||||
* @new_value: value to set bit to (0 or 1)
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to set
|
||||
* @new_value: value to set bit to (0 or 1)
|
||||
*
|
||||
* Set the bit @bit in the @bitmap to @new_value. Ignore all errors.
|
||||
*/
|
||||
void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
void ntfs_bit_set( u8 *bitmap, const u64 bit, const u8 new_value )
|
||||
{
|
||||
if (!bitmap || new_value > 1)
|
||||
return;
|
||||
if (!new_value)
|
||||
bitmap[bit >> 3] &= ~(1 << (bit & 7));
|
||||
else
|
||||
bitmap[bit >> 3] |= (1 << (bit & 7));
|
||||
if ( !bitmap || new_value > 1 )
|
||||
return;
|
||||
if ( !new_value )
|
||||
bitmap[bit >> 3] &= ~( 1 << ( bit & 7 ) );
|
||||
else
|
||||
bitmap[bit >> 3] |= ( 1 << ( bit & 7 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bit_get - get value of a bit in a field of bits
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to get
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to get
|
||||
*
|
||||
* Get and return the value of the bit @bit in @bitmap (0 or 1).
|
||||
* Return -1 on error.
|
||||
*/
|
||||
char ntfs_bit_get(const u8 *bitmap, const u64 bit)
|
||||
char ntfs_bit_get( const u8 *bitmap, const u64 bit )
|
||||
{
|
||||
if (!bitmap)
|
||||
return -1;
|
||||
return (bitmap[bit >> 3] >> (bit & 7)) & 1;
|
||||
if ( !bitmap )
|
||||
return -1;
|
||||
return ( bitmap[bit >> 3] >> ( bit & 7 ) ) & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bit_get_and_set - get value of a bit in a field of bits and set it
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to get/set
|
||||
* @new_value: value to set bit to (0 or 1)
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to get/set
|
||||
* @new_value: value to set bit to (0 or 1)
|
||||
*
|
||||
* Return the value of the bit @bit and set it to @new_value (0 or 1).
|
||||
* Return -1 on error.
|
||||
*/
|
||||
char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
char ntfs_bit_get_and_set( u8 *bitmap, const u64 bit, const u8 new_value )
|
||||
{
|
||||
register u8 old_bit, shift;
|
||||
register u8 old_bit, shift;
|
||||
|
||||
if (!bitmap || new_value > 1)
|
||||
return -1;
|
||||
shift = bit & 7;
|
||||
old_bit = (bitmap[bit >> 3] >> shift) & 1;
|
||||
if (new_value != old_bit)
|
||||
bitmap[bit >> 3] ^= 1 << shift;
|
||||
return old_bit;
|
||||
if ( !bitmap || new_value > 1 )
|
||||
return -1;
|
||||
shift = bit & 7;
|
||||
old_bit = ( bitmap[bit >> 3] >> shift ) & 1;
|
||||
if ( new_value != old_bit )
|
||||
bitmap[bit >> 3] ^= 1 << shift;
|
||||
return old_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
* @count: number of bits to set
|
||||
* @value: value to set the bits to (i.e. 0 or 1)
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
* @count: number of bits to set
|
||||
* @value: value to set the bits to (i.e. 0 or 1)
|
||||
*
|
||||
* Set @count bits starting at bit @start_bit in the bitmap described by the
|
||||
* attribute @na to @value, where @value is either 0 or 1.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
s64 count, int value)
|
||||
static int ntfs_bitmap_set_bits_in_run( ntfs_attr *na, s64 start_bit,
|
||||
s64 count, int value )
|
||||
{
|
||||
s64 bufsize, br;
|
||||
u8 *buf, *lastbyte_buf;
|
||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
||||
s64 bufsize, br;
|
||||
u8 *buf, *lastbyte_buf;
|
||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
||||
|
||||
if (!na || start_bit < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
|
||||
__FUNCTION__, na, (long long)start_bit, (long long)count);
|
||||
return -1;
|
||||
}
|
||||
if ( !na || start_bit < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)",
|
||||
__FUNCTION__, na, ( long long )start_bit, ( long long )count );
|
||||
return -1;
|
||||
}
|
||||
|
||||
bit = start_bit & 7;
|
||||
if (bit)
|
||||
firstbyte = 1;
|
||||
else
|
||||
firstbyte = 0;
|
||||
bit = start_bit & 7;
|
||||
if ( bit )
|
||||
firstbyte = 1;
|
||||
else
|
||||
firstbyte = 0;
|
||||
|
||||
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
||||
bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
|
||||
if (bufsize > 8192)
|
||||
bufsize = 8192;
|
||||
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
||||
bufsize = ( ( count - ( bit ? 8 - bit : 0 ) + 7 ) >> 3 ) + firstbyte;
|
||||
if ( bufsize > 8192 )
|
||||
bufsize = 8192;
|
||||
|
||||
buf = ntfs_malloc(bufsize);
|
||||
if (!buf)
|
||||
return -1;
|
||||
buf = ntfs_malloc( bufsize );
|
||||
if ( !buf )
|
||||
return -1;
|
||||
|
||||
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
||||
memset(buf, value ? 0xff : 0, bufsize);
|
||||
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
||||
memset( buf, value ? 0xff : 0, bufsize );
|
||||
|
||||
/* If there is a first partial byte... */
|
||||
if (bit) {
|
||||
/* read it in... */
|
||||
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
||||
if (br != 1) {
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set or clear the appropriate bits in it. */
|
||||
while ((bit & 7) && count--) {
|
||||
if (value)
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
*buf &= ~(1 << bit++);
|
||||
}
|
||||
/* Update @start_bit to the new position. */
|
||||
start_bit = (start_bit + 7) & ~7;
|
||||
}
|
||||
/* If there is a first partial byte... */
|
||||
if ( bit )
|
||||
{
|
||||
/* read it in... */
|
||||
br = ntfs_attr_pread( na, start_bit >> 3, 1, buf );
|
||||
if ( br != 1 )
|
||||
{
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set or clear the appropriate bits in it. */
|
||||
while ( ( bit & 7 ) && count-- )
|
||||
{
|
||||
if ( value )
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
*buf &= ~( 1 << bit++ );
|
||||
}
|
||||
/* Update @start_bit to the new position. */
|
||||
start_bit = ( start_bit + 7 ) & ~7;
|
||||
}
|
||||
|
||||
/* Loop until @count reaches zero. */
|
||||
lastbyte = 0;
|
||||
lastbyte_buf = NULL;
|
||||
bit = count & 7;
|
||||
do {
|
||||
/* If there is a last partial byte... */
|
||||
if (count > 0 && bit) {
|
||||
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||
if (!lastbyte_pos) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error("Lastbyte is zero. Leaving "
|
||||
"inconsistent metadata.\n");
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and it is in the currently loaded bitmap window... */
|
||||
if (lastbyte_pos <= bufsize) {
|
||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||
/* Loop until @count reaches zero. */
|
||||
lastbyte = 0;
|
||||
lastbyte_buf = NULL;
|
||||
bit = count & 7;
|
||||
do
|
||||
{
|
||||
/* If there is a last partial byte... */
|
||||
if ( count > 0 && bit )
|
||||
{
|
||||
lastbyte_pos = ( ( count + 7 ) >> 3 ) + firstbyte;
|
||||
if ( !lastbyte_pos )
|
||||
{
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error( "Lastbyte is zero. Leaving "
|
||||
"inconsistent metadata.\n" );
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and it is in the currently loaded bitmap window... */
|
||||
if ( lastbyte_pos <= bufsize )
|
||||
{
|
||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||
|
||||
/* read the byte in... */
|
||||
br = ntfs_attr_pread(na, (start_bit + count) >>
|
||||
3, 1, lastbyte_buf);
|
||||
if (br != 1) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Reading of last byte "
|
||||
"failed (%lld). Leaving inconsistent "
|
||||
"metadata", (long long)br);
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set/clear the appropriate bits in it. */
|
||||
while (bit && count--) {
|
||||
if (value)
|
||||
*lastbyte_buf |= 1 << --bit;
|
||||
else
|
||||
*lastbyte_buf &= ~(1 << --bit);
|
||||
}
|
||||
/* We don't want to come back here... */
|
||||
bit = 0;
|
||||
/* We have a last byte that we have handled. */
|
||||
lastbyte = 1;
|
||||
}
|
||||
}
|
||||
/* read the byte in... */
|
||||
br = ntfs_attr_pread( na, ( start_bit + count ) >>
|
||||
3, 1, lastbyte_buf );
|
||||
if ( br != 1 )
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Reading of last byte "
|
||||
"failed (%lld). Leaving inconsistent "
|
||||
"metadata", ( long long )br );
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set/clear the appropriate bits in it. */
|
||||
while ( bit && count-- )
|
||||
{
|
||||
if ( value )
|
||||
*lastbyte_buf |= 1 << --bit;
|
||||
else
|
||||
*lastbyte_buf &= ~( 1 << --bit );
|
||||
}
|
||||
/* We don't want to come back here... */
|
||||
bit = 0;
|
||||
/* We have a last byte that we have handled. */
|
||||
lastbyte = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the prepared buffer to disk. */
|
||||
tmp = (start_bit >> 3) - firstbyte;
|
||||
br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
|
||||
if (br != bufsize) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Failed to write buffer to bitmap "
|
||||
"(%lld != %lld). Leaving inconsistent metadata",
|
||||
(long long)br, (long long)bufsize);
|
||||
goto free_err_out;
|
||||
}
|
||||
/* Write the prepared buffer to disk. */
|
||||
tmp = ( start_bit >> 3 ) - firstbyte;
|
||||
br = ntfs_attr_pwrite( na, tmp, bufsize, buf );
|
||||
if ( br != bufsize )
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Failed to write buffer to bitmap "
|
||||
"(%lld != %lld). Leaving inconsistent metadata",
|
||||
( long long )br, ( long long )bufsize );
|
||||
goto free_err_out;
|
||||
}
|
||||
|
||||
/* Update counters. */
|
||||
tmp = (bufsize - firstbyte - lastbyte) << 3;
|
||||
if (firstbyte) {
|
||||
firstbyte = 0;
|
||||
/*
|
||||
* Re-set the partial first byte so a subsequent write
|
||||
* of the buffer does not have stale, incorrect bits.
|
||||
*/
|
||||
*buf = value ? 0xff : 0;
|
||||
}
|
||||
start_bit += tmp;
|
||||
count -= tmp;
|
||||
if (bufsize > (tmp = (count + 7) >> 3))
|
||||
bufsize = tmp;
|
||||
/* Update counters. */
|
||||
tmp = ( bufsize - firstbyte - lastbyte ) << 3;
|
||||
if ( firstbyte )
|
||||
{
|
||||
firstbyte = 0;
|
||||
/*
|
||||
* Re-set the partial first byte so a subsequent write
|
||||
* of the buffer does not have stale, incorrect bits.
|
||||
*/
|
||||
*buf = value ? 0xff : 0;
|
||||
}
|
||||
start_bit += tmp;
|
||||
count -= tmp;
|
||||
if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) )
|
||||
bufsize = tmp;
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error("Last buffer but count is not zero "
|
||||
"(%lld). Leaving inconsistent metadata.\n",
|
||||
(long long)count);
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
if ( lastbyte && count != 0 )
|
||||
{
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error( "Last buffer but count is not zero "
|
||||
"(%lld). Leaving inconsistent metadata.\n",
|
||||
( long long )count );
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
}
|
||||
while ( count > 0 );
|
||||
|
||||
ret = 0;
|
||||
ret = 0;
|
||||
|
||||
free_err_out:
|
||||
free(buf);
|
||||
return ret;
|
||||
free( buf );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_set_run - set a run of bits in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
* @count: number of bits to set
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
* @count: number of bits to set
|
||||
*
|
||||
* Set @count bits starting at bit @start_bit in the bitmap described by the
|
||||
* attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count)
|
||||
int ntfs_bitmap_set_run( ntfs_attr *na, s64 start_bit, s64 count )
|
||||
{
|
||||
int ret;
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter("Set from bit %lld, count %lld\n",
|
||||
(long long)start_bit, (long long)count);
|
||||
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
ntfs_log_enter( "Set from bit %lld, count %lld\n",
|
||||
( long long )start_bit, ( long long )count );
|
||||
ret = ntfs_bitmap_set_bits_in_run( na, start_bit, count, 1 );
|
||||
ntfs_log_leave( "\n" );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_clear_run - clear a run of bits in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to clear
|
||||
* @count: number of bits to clear
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to clear
|
||||
* @count: number of bits to clear
|
||||
*
|
||||
* Clear @count bits starting at bit @start_bit in the bitmap described by the
|
||||
* attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count)
|
||||
int ntfs_bitmap_clear_run( ntfs_attr *na, s64 start_bit, s64 count )
|
||||
{
|
||||
int ret;
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter("Clear from bit %lld, count %lld\n",
|
||||
(long long)start_bit, (long long)count);
|
||||
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
ntfs_log_enter( "Clear from bit %lld, count %lld\n",
|
||||
( long long )start_bit, ( long long )count );
|
||||
ret = ntfs_bitmap_set_bits_in_run( na, start_bit, count, 0 );
|
||||
ntfs_log_leave( "\n" );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -36,38 +36,38 @@
|
||||
* size of the bitmap.
|
||||
*/
|
||||
|
||||
extern void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value);
|
||||
extern char ntfs_bit_get(const u8 *bitmap, const u64 bit);
|
||||
extern char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value);
|
||||
extern int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count);
|
||||
extern int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count);
|
||||
extern void ntfs_bit_set( u8 *bitmap, const u64 bit, const u8 new_value );
|
||||
extern char ntfs_bit_get( const u8 *bitmap, const u64 bit );
|
||||
extern char ntfs_bit_get_and_set( u8 *bitmap, const u64 bit, const u8 new_value );
|
||||
extern int ntfs_bitmap_set_run( ntfs_attr *na, s64 start_bit, s64 count );
|
||||
extern int ntfs_bitmap_clear_run( ntfs_attr *na, s64 start_bit, s64 count );
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_set_bit - set a bit in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @bit: bit to set
|
||||
* @na: attribute containing the bitmap
|
||||
* @bit: bit to set
|
||||
*
|
||||
* Set the @bit in the bitmap described by the attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
static __inline__ int ntfs_bitmap_set_bit(ntfs_attr *na, s64 bit)
|
||||
static __inline__ int ntfs_bitmap_set_bit( ntfs_attr *na, s64 bit )
|
||||
{
|
||||
return ntfs_bitmap_set_run(na, bit, 1);
|
||||
return ntfs_bitmap_set_run( na, bit, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_clear_bit - clear a bit in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @bit: bit to clear
|
||||
* @na: attribute containing the bitmap
|
||||
* @bit: bit to clear
|
||||
*
|
||||
* Clear @bit in the bitmap described by the attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit)
|
||||
static __inline__ int ntfs_bitmap_clear_bit( ntfs_attr *na, s64 bit )
|
||||
{
|
||||
return ntfs_bitmap_clear_run(na, bit, 1);
|
||||
return ntfs_bitmap_clear_run( na, bit, 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -76,9 +76,9 @@ static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit)
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static __inline__ u32 ntfs_rol32(u32 word, unsigned int shift)
|
||||
static __inline__ u32 ntfs_rol32( u32 word, unsigned int shift )
|
||||
{
|
||||
return (word << shift) | (word >> (32 - shift));
|
||||
return ( word << shift ) | ( word >> ( 32 - shift ) );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -87,9 +87,9 @@ static __inline__ u32 ntfs_rol32(u32 word, unsigned int shift)
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static __inline__ u32 ntfs_ror32(u32 word, unsigned int shift)
|
||||
static __inline__ u32 ntfs_ror32( u32 word, unsigned int shift )
|
||||
{
|
||||
return (word >> shift) | (word << (32 - shift));
|
||||
return ( word >> shift ) | ( word << ( 32 - shift ) );
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_BITMAP_H */
|
||||
|
@ -45,8 +45,8 @@
|
||||
|
||||
/**
|
||||
* ntfs_boot_sector_is_ntfs - check if buffer contains a valid ntfs boot sector
|
||||
* @b: buffer containing putative boot sector to analyze
|
||||
* @silent: if zero, output progress messages to stderr
|
||||
* @b: buffer containing putative boot sector to analyze
|
||||
* @silent: if zero, output progress messages to stderr
|
||||
*
|
||||
* Check if the buffer @b contains a valid ntfs boot sector. The buffer @b
|
||||
* must be at least 512 bytes in size.
|
||||
@ -57,229 +57,244 @@
|
||||
*
|
||||
* Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
|
||||
*/
|
||||
BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
BOOL ntfs_boot_sector_is_ntfs( NTFS_BOOT_SECTOR *b )
|
||||
{
|
||||
u32 i;
|
||||
BOOL ret = FALSE;
|
||||
u32 i;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
ntfs_log_debug("Beginning bootsector check.\n");
|
||||
ntfs_log_debug( "Beginning bootsector check.\n" );
|
||||
|
||||
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
|
||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
||||
ntfs_log_error("NTFS signature is missing.\n");
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug( "Checking OEMid, NTFS signature.\n" );
|
||||
if ( b->oem_id != cpu_to_le64( 0x202020205346544eULL ) ) /* "NTFS " */
|
||||
{
|
||||
ntfs_log_error( "NTFS signature is missing.\n" );
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking bytes per sector.\n");
|
||||
if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 ||
|
||||
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
|
||||
ntfs_log_error("Unexpected bytes per sector value (%d).\n",
|
||||
le16_to_cpu(b->bpb.bytes_per_sector));
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug( "Checking bytes per sector.\n" );
|
||||
if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 ||
|
||||
le16_to_cpu( b->bpb.bytes_per_sector ) > 4096 )
|
||||
{
|
||||
ntfs_log_error( "Unexpected bytes per sector value (%d).\n",
|
||||
le16_to_cpu( b->bpb.bytes_per_sector ) );
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking sectors per cluster.\n");
|
||||
switch (b->bpb.sectors_per_cluster) {
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
|
||||
b->bpb.sectors_per_cluster);
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug( "Checking sectors per cluster.\n" );
|
||||
switch ( b->bpb.sectors_per_cluster )
|
||||
{
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error( "Unexpected sectors per cluster value (%d).\n",
|
||||
b->bpb.sectors_per_cluster );
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking cluster size.\n");
|
||||
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) *
|
||||
b->bpb.sectors_per_cluster;
|
||||
if (i > 65536) {
|
||||
ntfs_log_error("Unexpected cluster size (%d).\n", i);
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug( "Checking cluster size.\n" );
|
||||
i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) *
|
||||
b->bpb.sectors_per_cluster;
|
||||
if ( i > 65536 )
|
||||
{
|
||||
ntfs_log_error( "Unexpected cluster size (%d).\n", i );
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking reserved fields are zero.\n");
|
||||
if (le16_to_cpu(b->bpb.reserved_sectors) ||
|
||||
le16_to_cpu(b->bpb.root_entries) ||
|
||||
le16_to_cpu(b->bpb.sectors) ||
|
||||
le16_to_cpu(b->bpb.sectors_per_fat) ||
|
||||
le32_to_cpu(b->bpb.large_sectors) ||
|
||||
b->bpb.fats) {
|
||||
ntfs_log_error("Reserved fields aren't zero "
|
||||
"(%d, %d, %d, %d, %d, %d).\n",
|
||||
le16_to_cpu(b->bpb.reserved_sectors),
|
||||
le16_to_cpu(b->bpb.root_entries),
|
||||
le16_to_cpu(b->bpb.sectors),
|
||||
le16_to_cpu(b->bpb.sectors_per_fat),
|
||||
le32_to_cpu(b->bpb.large_sectors),
|
||||
b->bpb.fats);
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug( "Checking reserved fields are zero.\n" );
|
||||
if ( le16_to_cpu( b->bpb.reserved_sectors ) ||
|
||||
le16_to_cpu( b->bpb.root_entries ) ||
|
||||
le16_to_cpu( b->bpb.sectors ) ||
|
||||
le16_to_cpu( b->bpb.sectors_per_fat ) ||
|
||||
le32_to_cpu( b->bpb.large_sectors ) ||
|
||||
b->bpb.fats )
|
||||
{
|
||||
ntfs_log_error( "Reserved fields aren't zero "
|
||||
"(%d, %d, %d, %d, %d, %d).\n",
|
||||
le16_to_cpu( b->bpb.reserved_sectors ),
|
||||
le16_to_cpu( b->bpb.root_entries ),
|
||||
le16_to_cpu( b->bpb.sectors ),
|
||||
le16_to_cpu( b->bpb.sectors_per_fat ),
|
||||
le32_to_cpu( b->bpb.large_sectors ),
|
||||
b->bpb.fats );
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking clusters per mft record.\n");
|
||||
if ((u8)b->clusters_per_mft_record < 0xe1 ||
|
||||
(u8)b->clusters_per_mft_record > 0xf7) {
|
||||
switch (b->clusters_per_mft_record) {
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unexpected clusters per mft record "
|
||||
"(%d).\n", b->clusters_per_mft_record);
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
ntfs_log_debug( "Checking clusters per mft record.\n" );
|
||||
if ( ( u8 )b->clusters_per_mft_record < 0xe1 ||
|
||||
( u8 )b->clusters_per_mft_record > 0xf7 )
|
||||
{
|
||||
switch ( b->clusters_per_mft_record )
|
||||
{
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error( "Unexpected clusters per mft record "
|
||||
"(%d).\n", b->clusters_per_mft_record );
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking clusters per index block.\n");
|
||||
if ((u8)b->clusters_per_index_record < 0xe1 ||
|
||||
(u8)b->clusters_per_index_record > 0xf7) {
|
||||
switch (b->clusters_per_index_record) {
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unexpected clusters per index record "
|
||||
"(%d).\n", b->clusters_per_index_record);
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
ntfs_log_debug( "Checking clusters per index block.\n" );
|
||||
if ( ( u8 )b->clusters_per_index_record < 0xe1 ||
|
||||
( u8 )b->clusters_per_index_record > 0xf7 )
|
||||
{
|
||||
switch ( b->clusters_per_index_record )
|
||||
{
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error( "Unexpected clusters per index record "
|
||||
"(%d).\n", b->clusters_per_index_record );
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
|
||||
if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
|
||||
ntfs_log_debug("Warning: Bootsector has invalid end of sector "
|
||||
"marker.\n");
|
||||
if ( b->end_of_sector_marker != cpu_to_le16( 0xaa55 ) )
|
||||
ntfs_log_debug( "Warning: Bootsector has invalid end of sector "
|
||||
"marker.\n" );
|
||||
|
||||
ntfs_log_debug("Bootsector check completed successfully.\n");
|
||||
ntfs_log_debug( "Bootsector check completed successfully.\n" );
|
||||
|
||||
ret = TRUE;
|
||||
ret = TRUE;
|
||||
not_ntfs:
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *last_sector_error =
|
||||
"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n"
|
||||
" or it was not setup correctly (e.g. by not using mdadm --build ...),\n"
|
||||
" or a wrong device is tried to be mounted,\n"
|
||||
" or the partition table is corrupt (partition is smaller than NTFS),\n"
|
||||
" or the NTFS boot sector is corrupt (NTFS size is not valid).\n";
|
||||
"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n"
|
||||
" or it was not setup correctly (e.g. by not using mdadm --build ...),\n"
|
||||
" or a wrong device is tried to be mounted,\n"
|
||||
" or the partition table is corrupt (partition is smaller than NTFS),\n"
|
||||
" or the NTFS boot sector is corrupt (NTFS size is not valid).\n";
|
||||
|
||||
/**
|
||||
* ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
|
||||
* @vol: ntfs_volume to setup
|
||||
* @bs: buffer containing ntfs boot sector to parse
|
||||
* @vol: ntfs_volume to setup
|
||||
* @bs: buffer containing ntfs boot sector to parse
|
||||
*
|
||||
* Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the
|
||||
* obtained values.
|
||||
*
|
||||
* Return 0 on success or -1 on error with errno set to the error code EINVAL.
|
||||
*/
|
||||
int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
int ntfs_boot_sector_parse( ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs )
|
||||
{
|
||||
s64 sectors;
|
||||
u8 sectors_per_cluster;
|
||||
s8 c;
|
||||
s64 sectors;
|
||||
u8 sectors_per_cluster;
|
||||
s8 c;
|
||||
|
||||
/* We return -1 with errno = EINVAL on error. */
|
||||
errno = EINVAL;
|
||||
/* We return -1 with errno = EINVAL on error. */
|
||||
errno = EINVAL;
|
||||
|
||||
vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector);
|
||||
vol->sector_size_bits = ffs(vol->sector_size) - 1;
|
||||
ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size);
|
||||
ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits);
|
||||
/*
|
||||
* The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
|
||||
* below or equal the number_of_clusters) really belong in the
|
||||
* ntfs_boot_sector_is_ntfs but in this way we can just do this once.
|
||||
*/
|
||||
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
||||
ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
|
||||
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
|
||||
ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
|
||||
"\n", sectors_per_cluster);
|
||||
return -1;
|
||||
}
|
||||
vol->sector_size = le16_to_cpu( bs->bpb.bytes_per_sector );
|
||||
vol->sector_size_bits = ffs( vol->sector_size ) - 1;
|
||||
ntfs_log_debug( "SectorSize = 0x%x\n", vol->sector_size );
|
||||
ntfs_log_debug( "SectorSizeBits = %u\n", vol->sector_size_bits );
|
||||
/*
|
||||
* The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
|
||||
* below or equal the number_of_clusters) really belong in the
|
||||
* ntfs_boot_sector_is_ntfs but in this way we can just do this once.
|
||||
*/
|
||||
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
||||
ntfs_log_debug( "SectorsPerCluster = 0x%x\n", sectors_per_cluster );
|
||||
if ( sectors_per_cluster & ( sectors_per_cluster - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2."
|
||||
"\n", sectors_per_cluster );
|
||||
return -1;
|
||||
}
|
||||
|
||||
sectors = sle64_to_cpu(bs->number_of_sectors);
|
||||
ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
|
||||
if (!sectors) {
|
||||
ntfs_log_error("Volume size is set to zero.\n");
|
||||
return -1;
|
||||
}
|
||||
if (vol->dev->d_ops->seek(vol->dev,
|
||||
(sectors - 1) << vol->sector_size_bits,
|
||||
SEEK_SET) == -1) {
|
||||
ntfs_log_perror("Failed to read last sector (%lld)",
|
||||
(long long)sectors);
|
||||
ntfs_log_error("%s", last_sector_error);
|
||||
return -1;
|
||||
}
|
||||
sectors = sle64_to_cpu( bs->number_of_sectors );
|
||||
ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors );
|
||||
if ( !sectors )
|
||||
{
|
||||
ntfs_log_error( "Volume size is set to zero.\n" );
|
||||
return -1;
|
||||
}
|
||||
if ( vol->dev->d_ops->seek( vol->dev,
|
||||
( sectors - 1 ) << vol->sector_size_bits,
|
||||
SEEK_SET ) == -1 )
|
||||
{
|
||||
ntfs_log_perror( "Failed to read last sector (%lld)",
|
||||
( long long )sectors );
|
||||
ntfs_log_error( "%s", last_sector_error );
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol->nr_clusters = sectors >> (ffs(sectors_per_cluster) - 1);
|
||||
vol->nr_clusters = sectors >> ( ffs( sectors_per_cluster ) - 1 );
|
||||
|
||||
vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
|
||||
vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
|
||||
ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
|
||||
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
||||
if (vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
||||
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||
"greater than the number of clusters (%lld).\n",
|
||||
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
|
||||
(long long)vol->nr_clusters);
|
||||
return -1;
|
||||
}
|
||||
vol->mft_lcn = sle64_to_cpu( bs->mft_lcn );
|
||||
vol->mftmirr_lcn = sle64_to_cpu( bs->mftmirr_lcn );
|
||||
ntfs_log_debug( "MFT LCN = %lld\n", ( long long )vol->mft_lcn );
|
||||
ntfs_log_debug( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn );
|
||||
if ( vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters )
|
||||
{
|
||||
ntfs_log_error( "$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||
"greater than the number of clusters (%lld).\n",
|
||||
( long long )vol->mft_lcn, ( long long )vol->mftmirr_lcn,
|
||||
( long long )vol->nr_clusters );
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||
if (vol->cluster_size & (vol->cluster_size - 1)) {
|
||||
ntfs_log_error("cluster_size (%d) is not a power of 2.\n",
|
||||
vol->cluster_size);
|
||||
return -1;
|
||||
}
|
||||
vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
|
||||
/*
|
||||
* Need to get the clusters per mft record and handle it if it is
|
||||
* negative. Then calculate the mft_record_size. A value of 0x80 is
|
||||
* illegal, thus signed char is actually ok!
|
||||
*/
|
||||
c = bs->clusters_per_mft_record;
|
||||
ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size);
|
||||
ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits);
|
||||
ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c);
|
||||
/*
|
||||
* When clusters_per_mft_record is negative, it means that it is to
|
||||
* be taken to be the negative base 2 logarithm of the mft_record_size
|
||||
* min bytes. Then:
|
||||
* mft_record_size = 2^(-clusters_per_mft_record) bytes.
|
||||
*/
|
||||
if (c < 0)
|
||||
vol->mft_record_size = 1 << -c;
|
||||
else
|
||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
||||
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
|
||||
ntfs_log_error("mft_record_size (%d) is not a power of 2.\n",
|
||||
vol->mft_record_size);
|
||||
return -1;
|
||||
}
|
||||
vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
|
||||
ntfs_log_debug("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size);
|
||||
ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
|
||||
/* Same as above for INDX record. */
|
||||
c = bs->clusters_per_index_record;
|
||||
ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
|
||||
if (c < 0)
|
||||
vol->indx_record_size = 1 << -c;
|
||||
else
|
||||
vol->indx_record_size = c << vol->cluster_size_bits;
|
||||
vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
|
||||
ntfs_log_debug("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
|
||||
ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
|
||||
/*
|
||||
* Work out the size of the MFT mirror in number of mft records. If the
|
||||
* cluster size is less than or equal to the size taken by four mft
|
||||
* records, the mft mirror stores the first four mft records. If the
|
||||
* cluster size is bigger than the size taken by four mft records, the
|
||||
* mft mirror contains as many mft records as will fit into one
|
||||
* cluster.
|
||||
*/
|
||||
if (vol->cluster_size <= 4 * vol->mft_record_size)
|
||||
vol->mftmirr_size = 4;
|
||||
else
|
||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||
return 0;
|
||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||
if ( vol->cluster_size & ( vol->cluster_size - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "cluster_size (%d) is not a power of 2.\n",
|
||||
vol->cluster_size );
|
||||
return -1;
|
||||
}
|
||||
vol->cluster_size_bits = ffs( vol->cluster_size ) - 1;
|
||||
/*
|
||||
* Need to get the clusters per mft record and handle it if it is
|
||||
* negative. Then calculate the mft_record_size. A value of 0x80 is
|
||||
* illegal, thus signed char is actually ok!
|
||||
*/
|
||||
c = bs->clusters_per_mft_record;
|
||||
ntfs_log_debug( "ClusterSize = 0x%x\n", ( unsigned )vol->cluster_size );
|
||||
ntfs_log_debug( "ClusterSizeBits = %u\n", vol->cluster_size_bits );
|
||||
ntfs_log_debug( "ClustersPerMftRecord = 0x%x\n", c );
|
||||
/*
|
||||
* When clusters_per_mft_record is negative, it means that it is to
|
||||
* be taken to be the negative base 2 logarithm of the mft_record_size
|
||||
* min bytes. Then:
|
||||
* mft_record_size = 2^(-clusters_per_mft_record) bytes.
|
||||
*/
|
||||
if ( c < 0 )
|
||||
vol->mft_record_size = 1 << -c;
|
||||
else
|
||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
||||
if ( vol->mft_record_size & ( vol->mft_record_size - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "mft_record_size (%d) is not a power of 2.\n",
|
||||
vol->mft_record_size );
|
||||
return -1;
|
||||
}
|
||||
vol->mft_record_size_bits = ffs( vol->mft_record_size ) - 1;
|
||||
ntfs_log_debug( "MftRecordSize = 0x%x\n", ( unsigned )vol->mft_record_size );
|
||||
ntfs_log_debug( "MftRecordSizeBits = %u\n", vol->mft_record_size_bits );
|
||||
/* Same as above for INDX record. */
|
||||
c = bs->clusters_per_index_record;
|
||||
ntfs_log_debug( "ClustersPerINDXRecord = 0x%x\n", c );
|
||||
if ( c < 0 )
|
||||
vol->indx_record_size = 1 << -c;
|
||||
else
|
||||
vol->indx_record_size = c << vol->cluster_size_bits;
|
||||
vol->indx_record_size_bits = ffs( vol->indx_record_size ) - 1;
|
||||
ntfs_log_debug( "INDXRecordSize = 0x%x\n", ( unsigned )vol->indx_record_size );
|
||||
ntfs_log_debug( "INDXRecordSizeBits = %u\n", vol->indx_record_size_bits );
|
||||
/*
|
||||
* Work out the size of the MFT mirror in number of mft records. If the
|
||||
* cluster size is less than or equal to the size taken by four mft
|
||||
* records, the mft mirror stores the first four mft records. If the
|
||||
* cluster size is bigger than the size taken by four mft records, the
|
||||
* mft mirror contains as many mft records as will fit into one
|
||||
* cluster.
|
||||
*/
|
||||
if ( vol->cluster_size <= 4 * vol->mft_record_size )
|
||||
vol->mftmirr_size = 4;
|
||||
else
|
||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* bootsect.h - Exports for bootsector record handling.
|
||||
* Originated from the Linux-NTFS project.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 Anton Altaparmakov
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
@ -30,13 +30,13 @@
|
||||
|
||||
/**
|
||||
* ntfs_boot_sector_is_ntfs - check a boot sector for describing an ntfs volume
|
||||
* @b: buffer containing the boot sector
|
||||
* @b: buffer containing the boot sector
|
||||
*
|
||||
* This function checks the boot sector in @b for describing a valid ntfs
|
||||
* volume. Return TRUE if @b is a valid NTFS boot sector or FALSE otherwise.
|
||||
*/
|
||||
extern BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b);
|
||||
extern int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs);
|
||||
extern BOOL ntfs_boot_sector_is_ntfs( NTFS_BOOT_SECTOR *b );
|
||||
extern int ntfs_boot_sector_parse( ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs );
|
||||
|
||||
#endif /* defined _NTFS_BOOTSECT_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,96 +24,104 @@
|
||||
|
||||
#include "volume.h"
|
||||
|
||||
struct CACHED_GENERIC {
|
||||
struct CACHED_GENERIC *next;
|
||||
struct CACHED_GENERIC *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
union {
|
||||
/* force alignment for pointers and u64 */
|
||||
u64 u64align;
|
||||
void *ptralign;
|
||||
} fixed[0];
|
||||
struct CACHED_GENERIC
|
||||
{
|
||||
struct CACHED_GENERIC *next;
|
||||
struct CACHED_GENERIC *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
union
|
||||
{
|
||||
/* force alignment for pointers and u64 */
|
||||
u64 u64align;
|
||||
void *ptralign;
|
||||
} fixed[0];
|
||||
} ;
|
||||
|
||||
struct CACHED_INODE {
|
||||
struct CACHED_INODE *next;
|
||||
struct CACHED_INODE *previous;
|
||||
const char *pathname;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
struct CACHED_INODE
|
||||
{
|
||||
struct CACHED_INODE *next;
|
||||
struct CACHED_INODE *previous;
|
||||
const char *pathname;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
struct CACHED_NIDATA {
|
||||
struct CACHED_NIDATA *next;
|
||||
struct CACHED_NIDATA *previous;
|
||||
const char *pathname; /* not used */
|
||||
size_t varsize; /* not used */
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
ntfs_inode *ni;
|
||||
struct CACHED_NIDATA
|
||||
{
|
||||
struct CACHED_NIDATA *next;
|
||||
struct CACHED_NIDATA *previous;
|
||||
const char *pathname; /* not used */
|
||||
size_t varsize; /* not used */
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
ntfs_inode *ni;
|
||||
} ;
|
||||
|
||||
struct CACHED_LOOKUP {
|
||||
struct CACHED_LOOKUP *next;
|
||||
struct CACHED_LOOKUP *previous;
|
||||
const char *name;
|
||||
size_t namesize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 parent;
|
||||
u64 inum;
|
||||
struct CACHED_LOOKUP
|
||||
{
|
||||
struct CACHED_LOOKUP *next;
|
||||
struct CACHED_LOOKUP *previous;
|
||||
const char *name;
|
||||
size_t namesize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 parent;
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
enum {
|
||||
CACHE_FREE = 1,
|
||||
CACHE_NOHASH = 2
|
||||
enum
|
||||
{
|
||||
CACHE_FREE = 1,
|
||||
CACHE_NOHASH = 2
|
||||
} ;
|
||||
|
||||
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
|
||||
const struct CACHED_GENERIC *item);
|
||||
typedef void (*cache_free)(const struct CACHED_GENERIC *cached);
|
||||
typedef int (*cache_hash)(const struct CACHED_GENERIC *cached);
|
||||
typedef int ( *cache_compare )( const struct CACHED_GENERIC *cached,
|
||||
const struct CACHED_GENERIC *item );
|
||||
typedef void ( *cache_free )( const struct CACHED_GENERIC *cached );
|
||||
typedef int ( *cache_hash )( const struct CACHED_GENERIC *cached );
|
||||
|
||||
struct HASH_ENTRY {
|
||||
struct HASH_ENTRY *next;
|
||||
struct CACHED_GENERIC *entry;
|
||||
struct HASH_ENTRY
|
||||
{
|
||||
struct HASH_ENTRY *next;
|
||||
struct CACHED_GENERIC *entry;
|
||||
} ;
|
||||
|
||||
struct CACHE_HEADER {
|
||||
const char *name;
|
||||
struct CACHED_GENERIC *most_recent_entry;
|
||||
struct CACHED_GENERIC *oldest_entry;
|
||||
struct CACHED_GENERIC *free_entry;
|
||||
struct HASH_ENTRY *free_hash;
|
||||
struct HASH_ENTRY **first_hash;
|
||||
cache_free dofree;
|
||||
cache_hash dohash;
|
||||
unsigned long reads;
|
||||
unsigned long writes;
|
||||
unsigned long hits;
|
||||
int fixed_size;
|
||||
int max_hash;
|
||||
struct CACHED_GENERIC entry[0];
|
||||
struct CACHE_HEADER
|
||||
{
|
||||
const char *name;
|
||||
struct CACHED_GENERIC *most_recent_entry;
|
||||
struct CACHED_GENERIC *oldest_entry;
|
||||
struct CACHED_GENERIC *free_entry;
|
||||
struct HASH_ENTRY *free_hash;
|
||||
struct HASH_ENTRY **first_hash;
|
||||
cache_free dofree;
|
||||
cache_hash dohash;
|
||||
unsigned long reads;
|
||||
unsigned long writes;
|
||||
unsigned long hits;
|
||||
int fixed_size;
|
||||
int max_hash;
|
||||
struct CACHED_GENERIC entry[0];
|
||||
} ;
|
||||
|
||||
/* cast to generic, avoiding gcc warnings */
|
||||
/* cast to generic, avoiding gcc warnings */
|
||||
#define GENERIC(pstr) ((const struct CACHED_GENERIC*)(const void*)(pstr))
|
||||
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted,
|
||||
cache_compare compare);
|
||||
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare);
|
||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare, int flags);
|
||||
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags);
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted,
|
||||
cache_compare compare );
|
||||
struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare );
|
||||
int ntfs_invalidate_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare, int flags );
|
||||
int ntfs_remove_cache( struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags );
|
||||
|
||||
void ntfs_create_lru_caches(ntfs_volume *vol);
|
||||
void ntfs_free_lru_caches(ntfs_volume *vol);
|
||||
void ntfs_create_lru_caches( ntfs_volume *vol );
|
||||
void ntfs_free_lru_caches( ntfs_volume *vol );
|
||||
|
||||
#endif /* _NTFS_CACHE_H_ */
|
||||
|
||||
|
@ -45,330 +45,365 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize) {
|
||||
NTFS_CACHE* cache;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize )
|
||||
{
|
||||
NTFS_CACHE* cache;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if(numberOfPages==0 || sectorsPerPage==0) return NULL;
|
||||
if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL;
|
||||
|
||||
if (numberOfPages < 4) {
|
||||
numberOfPages = 4;
|
||||
}
|
||||
if ( numberOfPages < 4 )
|
||||
{
|
||||
numberOfPages = 4;
|
||||
}
|
||||
|
||||
if (sectorsPerPage < 32) {
|
||||
sectorsPerPage = 32;
|
||||
}
|
||||
if ( sectorsPerPage < 32 )
|
||||
{
|
||||
sectorsPerPage = 32;
|
||||
}
|
||||
|
||||
cache = (NTFS_CACHE*) ntfs_alloc (sizeof(NTFS_CACHE));
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
|
||||
if ( cache == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache->disc = discInterface;
|
||||
cache->endOfPartition = endOfPartition;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
cache->sectorSize = sectorSize;
|
||||
cache->disc = discInterface;
|
||||
cache->endOfPartition = endOfPartition;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
cache->sectorSize = sectorSize;
|
||||
|
||||
|
||||
cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc ( sizeof(NTFS_CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL) {
|
||||
ntfs_free (cache);
|
||||
return NULL;
|
||||
}
|
||||
cacheEntries = ( NTFS_CACHE_ENTRY* ) ntfs_alloc ( sizeof( NTFS_CACHE_ENTRY ) * numberOfPages );
|
||||
if ( cacheEntries == NULL )
|
||||
{
|
||||
ntfs_free ( cache );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numberOfPages; i++) {
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = (uint8_t*) ntfs_align ( sectorsPerPage * cache->sectorSize );
|
||||
}
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = ( uint8_t* ) ntfs_align ( sectorsPerPage * cache->sectorSize );
|
||||
}
|
||||
|
||||
cache->cacheEntries = cacheEntries;
|
||||
cache->cacheEntries = cacheEntries;
|
||||
|
||||
return cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
void _NTFS_cache_destructor ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if(cache==NULL) return;
|
||||
if ( cache == NULL ) return;
|
||||
|
||||
// Clear out cache before destroying it
|
||||
_NTFS_cache_flush(cache);
|
||||
// Clear out cache before destroying it
|
||||
_NTFS_cache_flush( cache );
|
||||
|
||||
// Free memory in reverse allocation order
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
ntfs_free (cache->cacheEntries[i].cache);
|
||||
}
|
||||
ntfs_free (cache->cacheEntries);
|
||||
ntfs_free (cache);
|
||||
// Free memory in reverse allocation order
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
ntfs_free ( cache->cacheEntries[i].cache );
|
||||
}
|
||||
ntfs_free ( cache->cacheEntries );
|
||||
ntfs_free ( cache );
|
||||
}
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
static u32 accessTime()
|
||||
{
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &(cacheEntries[i]);
|
||||
}
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||
if(!cache->disc->writeSectors(cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
sector = (sector/sectorsPerPage)*sectorsPerPage; // align base sector to page size
|
||||
sec_t next_page = sector + sectorsPerPage;
|
||||
if(next_page > cache->endOfPartition) next_page = cache->endOfPartition;
|
||||
|
||||
if(!cache->disc->readSectors(sector,next_page-sector,cacheEntries[oldUsed].cache)) return NULL;
|
||||
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = next_page-sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
|
||||
return &(cacheEntries[oldUsed]);
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
|
||||
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_getPage( NTFS_CACHE *cache, sec_t sector )
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_read;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
|
||||
while(numSectors>0) {
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_read = entry->count - sec;
|
||||
if(secs_to_read>numSectors) secs_to_read = numSectors;
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
||||
{
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &( cacheEntries[i] );
|
||||
}
|
||||
|
||||
memcpy(dest,entry->cache + (sec*cache->sectorSize),(secs_to_read*cache->sectorSize));
|
||||
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
||||
{
|
||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
dest += (secs_to_read*cache->sectorSize);
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
||||
{
|
||||
if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
sector = ( sector / sectorsPerPage ) * sectorsPerPage; // align base sector to page size
|
||||
sec_t next_page = sector + sectorsPerPage;
|
||||
if ( next_page > cache->endOfPartition ) next_page = cache->endOfPartition;
|
||||
|
||||
return true;
|
||||
if ( !cache->disc->readSectors( sector, next_page - sector, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = next_page - sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
|
||||
return &( cacheEntries[oldUsed] );
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage( NTFS_CACHE *cache, sec_t sector, sec_t count )
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||
{
|
||||
bool intersect;
|
||||
if ( sector > cacheEntries[i].sector )
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readSectors( NTFS_CACHE *cache, sec_t sector, sec_t numSectors, void *buffer )
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_read;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_read = entry->count - sec;
|
||||
if ( secs_to_read > numSectors ) secs_to_read = numSectors;
|
||||
|
||||
memcpy( dest, entry->cache + ( sec*cache->sectorSize ), ( secs_to_read*cache->sectorSize ) );
|
||||
|
||||
dest += ( secs_to_read * cache->sectorSize );
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Reads some data from a cache page, determined by the sector number
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _NTFS_cache_readPartialSector ( NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > cache->sectorSize) return false;
|
||||
if ( offset + size > cache->sectorSize ) return false;
|
||||
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy(buffer,entry->cache + ((sec*cache->sectorSize) + offset),size);
|
||||
sec = sector - entry->sector;
|
||||
memcpy( buffer, entry->cache + ( ( sec*cache->sectorSize ) + offset ), size );
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
uint8_t buf[4];
|
||||
if (!_NTFS_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||
bool _NTFS_cache_readLittleEndianValue ( NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||
|
||||
switch(num_bytes) {
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16(buf,0); break;
|
||||
case 4: *value = u8array_to_u32(buf,0); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
switch ( num_bytes )
|
||||
{
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _NTFS_cache_writePartialSector ( NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > cache->sectorSize) return false;
|
||||
if ( offset + size > cache->sectorSize ) return false;
|
||||
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy(entry->cache + ((sec*cache->sectorSize) + offset),buffer,size);
|
||||
sec = sector - entry->sector;
|
||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
bool _NTFS_cache_writeLittleEndianValue ( NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
||||
{
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
|
||||
switch(size) {
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array(buf, 0, value); break;
|
||||
case 4: u32_to_u8array(buf, 0, value); break;
|
||||
default: return false;
|
||||
}
|
||||
switch ( size )
|
||||
{
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return _NTFS_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
return _NTFS_cache_writePartialSector( cache, buf, sector, offset, size );
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, zeroing out the page first
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _NTFS_cache_eraseWritePartialSector ( NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > cache->sectorSize) return false;
|
||||
if ( offset + size > cache->sectorSize ) return false;
|
||||
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memset(entry->cache + (sec*cache->sectorSize),0,cache->sectorSize);
|
||||
memcpy(entry->cache + ((sec*cache->sectorSize) + offset),buffer,size);
|
||||
sec = sector - entry->sector;
|
||||
memset( entry->cache + ( sec*cache->sectorSize ), 0, cache->sectorSize );
|
||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
bool _NTFS_cache_writeSectors ( NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
NTFS_CACHE_ENTRY* entry;
|
||||
const uint8_t *src = buffer;
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
NTFS_CACHE_ENTRY* entry;
|
||||
const uint8_t *src = buffer;
|
||||
|
||||
while(numSectors>0)
|
||||
{
|
||||
entry = _NTFS_cache_findPage(cache,sector,numSectors);
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _NTFS_cache_findPage( cache, sector, numSectors );
|
||||
|
||||
if(entry!=NULL) {
|
||||
if ( entry != NULL )
|
||||
{
|
||||
|
||||
if ( entry->sector > sector) {
|
||||
if ( entry->sector > sector )
|
||||
{
|
||||
|
||||
secs_to_write = entry->sector - sector;
|
||||
secs_to_write = entry->sector - sector;
|
||||
|
||||
cache->disc->writeSectors(sector,secs_to_write,src);
|
||||
src += (secs_to_write*cache->sectorSize);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
cache->disc->writeSectors( sector, secs_to_write, src );
|
||||
src += ( secs_to_write * cache->sectorSize );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
|
||||
if(secs_to_write>numSectors) secs_to_write = numSectors;
|
||||
if ( secs_to_write > numSectors ) secs_to_write = numSectors;
|
||||
|
||||
memcpy(entry->cache + (sec*cache->sectorSize),src,(secs_to_write*cache->sectorSize));
|
||||
memcpy( entry->cache + ( sec*cache->sectorSize ), src, ( secs_to_write*cache->sectorSize ) );
|
||||
|
||||
src += (secs_to_write*cache->sectorSize);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
src += ( secs_to_write * cache->sectorSize );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
cache->disc->writeSectors(sector,numSectors,src);
|
||||
numSectors=0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->disc->writeSectors( sector, numSectors, src );
|
||||
numSectors = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
if(cache==NULL) return true;
|
||||
bool _NTFS_cache_flush ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if ( cache == NULL ) return true;
|
||||
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
if (cache->cacheEntries[i].dirty) {
|
||||
if (!cache->disc->writeSectors (cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
if ( cache->cacheEntries[i].dirty )
|
||||
{
|
||||
if ( !cache->disc->writeSectors ( cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
if(cache==NULL)
|
||||
void _NTFS_cache_invalidate ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if ( cache == NULL )
|
||||
return;
|
||||
|
||||
_NTFS_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
_NTFS_cache_flush( cache );
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -46,21 +46,23 @@
|
||||
#include <ogc/disc_io.h>
|
||||
#include <gccore.h>
|
||||
|
||||
typedef struct {
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
u64 last_access;
|
||||
bool dirty;
|
||||
u8* cache;
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
u64 last_access;
|
||||
bool dirty;
|
||||
u8* cache;
|
||||
} NTFS_CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
sec_t sectorSize;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
sec_t sectorSize;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
} NTFS_CACHE;
|
||||
|
||||
/*
|
||||
@ -99,37 +101,37 @@ Precondition: offset + size <= BYTES_PER_READ
|
||||
/*
|
||||
Read several sectors from the NTFS_CACHE
|
||||
*/
|
||||
bool _NTFS_cache_readSectors (NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, void* buffer);
|
||||
bool _NTFS_cache_readSectors ( NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, void* buffer );
|
||||
|
||||
/*
|
||||
Read a full sector from the NTFS_CACHE
|
||||
*/
|
||||
//static inline bool _NTFS_cache_readSector (NTFS_CACHE* NTFS_CACHE, void* buffer, sec_t sector) {
|
||||
// return _NTFS_cache_readPartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
// return _NTFS_cache_readPartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
//}
|
||||
|
||||
/*
|
||||
Write a full sector to the NTFS_CACHE
|
||||
*/
|
||||
//static inline bool _NTFS_cache_writeSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector) {
|
||||
// return _NTFS_cache_writePartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
// return _NTFS_cache_writePartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
//}
|
||||
|
||||
bool _NTFS_cache_writeSectors (NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
bool _NTFS_cache_writeSectors ( NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, const void* buffer );
|
||||
|
||||
/*
|
||||
Write any dirty sectors back to disc and clear out the contents of the NTFS_CACHE
|
||||
*/
|
||||
bool _NTFS_cache_flush (NTFS_CACHE* NTFS_CACHE);
|
||||
bool _NTFS_cache_flush ( NTFS_CACHE* NTFS_CACHE );
|
||||
|
||||
/*
|
||||
Clear out the contents of the NTFS_CACHE without writing any dirty sectors first
|
||||
*/
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* NTFS_CACHE);
|
||||
void _NTFS_cache_invalidate ( NTFS_CACHE* NTFS_CACHE );
|
||||
|
||||
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize);
|
||||
NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize );
|
||||
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* NTFS_CACHE);
|
||||
void _NTFS_cache_destructor ( NTFS_CACHE* NTFS_CACHE );
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
||||
|
@ -52,22 +52,23 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
static int ntfs_collate_binary( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
int rc;
|
||||
int rc;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
rc = memcmp(data1, data2, min(data1_len, data2_len));
|
||||
if (!rc && (data1_len != data2_len)) {
|
||||
if (data1_len < data2_len)
|
||||
rc = -1;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
rc = memcmp( data1, data2, min( data1_len, data2_len ) );
|
||||
if ( !rc && ( data1_len != data2_len ) )
|
||||
{
|
||||
if ( data1_len < data2_len )
|
||||
rc = -1;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,30 +83,32 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
static int ntfs_collate_ntofs_ulong( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (data1_len != data2_len || data1_len != 4) {
|
||||
ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
d1 = le32_to_cpup(data1);
|
||||
d2 = le32_to_cpup(data2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 == d2)
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if ( data1_len != data2_len || data1_len != 4 )
|
||||
{
|
||||
ntfs_log_error( "data1_len or/and data2_len not equal to 4.\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
d1 = le32_to_cpup( data1 );
|
||||
d2 = le32_to_cpup( data2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
if ( d1 == d2 )
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,39 +117,43 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
* Returns: -1, 0 or 1 depending of how the arrays compare
|
||||
*/
|
||||
|
||||
static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
static int ntfs_collate_ntofs_ulongs( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
int rc;
|
||||
int len;
|
||||
const le32 *p1, *p2;
|
||||
u32 d1, d2;
|
||||
int rc;
|
||||
int len;
|
||||
const le32 *p1, *p2;
|
||||
u32 d1, d2;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) {
|
||||
ntfs_log_error("data1_len or data2_len not valid\n");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = (const le32*)data1;
|
||||
p2 = (const le32*)data2;
|
||||
len = data1_len;
|
||||
do {
|
||||
d1 = le32_to_cpup(p1);
|
||||
p1++;
|
||||
d2 = le32_to_cpup(p2);
|
||||
p2++;
|
||||
} while ((d1 == d2) && ((len -= 4) > 0));
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 == d2)
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if ( ( data1_len != data2_len ) || ( data1_len <= 0 ) || ( data1_len & 3 ) )
|
||||
{
|
||||
ntfs_log_error( "data1_len or data2_len not valid\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = ( const le32* )data1;
|
||||
p2 = ( const le32* )data2;
|
||||
len = data1_len;
|
||||
do
|
||||
{
|
||||
d1 = le32_to_cpup( p1 );
|
||||
p1++;
|
||||
d2 = le32_to_cpup( p2 );
|
||||
p2++;
|
||||
}
|
||||
while ( ( d1 == d2 ) && ( ( len -= 4 ) > 0 ) );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
if ( d1 == d2 )
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,45 +169,49 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
||||
*
|
||||
* Returns: -1, 0 or 1 depending of how the keys compare
|
||||
*/
|
||||
static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
static int ntfs_collate_ntofs_security_hash( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
const le32 *p1, *p2;
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
const le32 *p1, *p2;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (data1_len != data2_len || data1_len != 8) {
|
||||
ntfs_log_error("data1_len or/and data2_len not equal to 8.\n");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = (const le32*)data1;
|
||||
p2 = (const le32*)data2;
|
||||
d1 = le32_to_cpup(p1);
|
||||
d2 = le32_to_cpup(p2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 > d2)
|
||||
rc = 1;
|
||||
else {
|
||||
p1++;
|
||||
p2++;
|
||||
d1 = le32_to_cpup(p1);
|
||||
d2 = le32_to_cpup(p2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 > d2)
|
||||
rc = 1;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if ( data1_len != data2_len || data1_len != 8 )
|
||||
{
|
||||
ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = ( const le32* )data1;
|
||||
p2 = ( const le32* )data2;
|
||||
d1 = le32_to_cpup( p1 );
|
||||
d2 = le32_to_cpup( p2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else
|
||||
{
|
||||
p1++;
|
||||
p2++;
|
||||
d1 = le32_to_cpup( p1 );
|
||||
d2 = le32_to_cpup( p2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,57 +226,58 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_file_name(ntfs_volume *vol,
|
||||
const void *data1, const int data1_len __attribute__((unused)),
|
||||
const void *data2, const int data2_len __attribute__((unused)))
|
||||
static int ntfs_collate_file_name( ntfs_volume *vol,
|
||||
const void *data1, const int data1_len __attribute__( ( unused ) ),
|
||||
const void *data2, const int data2_len __attribute__( ( unused ) ) )
|
||||
{
|
||||
const FILE_NAME_ATTR *file_name_attr1;
|
||||
const FILE_NAME_ATTR *file_name_attr2;
|
||||
int rc;
|
||||
const FILE_NAME_ATTR *file_name_attr1;
|
||||
const FILE_NAME_ATTR *file_name_attr2;
|
||||
int rc;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
file_name_attr1 = (const FILE_NAME_ATTR*)data1;
|
||||
file_name_attr2 = (const FILE_NAME_ATTR*)data2;
|
||||
rc = ntfs_names_full_collate(
|
||||
(ntfschar*)&file_name_attr1->file_name,
|
||||
file_name_attr1->file_name_length,
|
||||
(ntfschar*)&file_name_attr2->file_name,
|
||||
file_name_attr2->file_name_length,
|
||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len);
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
file_name_attr1 = ( const FILE_NAME_ATTR* )data1;
|
||||
file_name_attr2 = ( const FILE_NAME_ATTR* )data2;
|
||||
rc = ntfs_names_full_collate(
|
||||
( ntfschar* ) & file_name_attr1->file_name,
|
||||
file_name_attr1->file_name_length,
|
||||
( ntfschar* ) & file_name_attr2->file_name,
|
||||
file_name_attr2->file_name_length,
|
||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len );
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a pointer to appropriate collation function.
|
||||
* Get a pointer to appropriate collation function.
|
||||
*
|
||||
* Returns NULL if the needed function is not implemented
|
||||
* Returns NULL if the needed function is not implemented
|
||||
*/
|
||||
|
||||
COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
|
||||
COLLATE ntfs_get_collate_function( COLLATION_RULES cr )
|
||||
{
|
||||
COLLATE collate;
|
||||
COLLATE collate;
|
||||
|
||||
switch (cr) {
|
||||
case COLLATION_BINARY :
|
||||
collate = ntfs_collate_binary;
|
||||
break;
|
||||
case COLLATION_FILE_NAME :
|
||||
collate = ntfs_collate_file_name;
|
||||
break;
|
||||
case COLLATION_NTOFS_SECURITY_HASH :
|
||||
collate = ntfs_collate_ntofs_security_hash;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONG :
|
||||
collate = ntfs_collate_ntofs_ulong;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONGS :
|
||||
collate = ntfs_collate_ntofs_ulongs;
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
collate = (COLLATE)NULL;
|
||||
break;
|
||||
}
|
||||
return (collate);
|
||||
switch ( cr )
|
||||
{
|
||||
case COLLATION_BINARY :
|
||||
collate = ntfs_collate_binary;
|
||||
break;
|
||||
case COLLATION_FILE_NAME :
|
||||
collate = ntfs_collate_file_name;
|
||||
break;
|
||||
case COLLATION_NTOFS_SECURITY_HASH :
|
||||
collate = ntfs_collate_ntofs_security_hash;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONG :
|
||||
collate = ntfs_collate_ntofs_ulong;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONGS :
|
||||
collate = ntfs_collate_ntofs_ulongs;
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
collate = ( COLLATE )NULL;
|
||||
break;
|
||||
}
|
||||
return ( collate );
|
||||
}
|
||||
|
@ -29,6 +29,6 @@
|
||||
|
||||
#define NTFS_COLLATION_ERROR -2
|
||||
|
||||
extern COLLATE ntfs_get_collate_function(COLLATION_RULES);
|
||||
extern COLLATE ntfs_get_collate_function( COLLATION_RULES );
|
||||
|
||||
#endif /* _NTFS_COLLATE_H */
|
||||
|
@ -35,33 +35,38 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ffs(int x)
|
||||
int ffs( int x )
|
||||
{
|
||||
int r = 1;
|
||||
int r = 1;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff)) {
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (!(x & 0xff)) {
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (!(x & 0xf)) {
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (!(x & 3)) {
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
if ( !x )
|
||||
return 0;
|
||||
if ( !( x & 0xffff ) )
|
||||
{
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if ( !( x & 0xff ) )
|
||||
{
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if ( !( x & 0xf ) )
|
||||
{
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if ( !( x & 3 ) )
|
||||
{
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if ( !( x & 1 ) )
|
||||
{
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif /* HAVE_FFS */
|
||||
|
||||
@ -82,7 +87,7 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -94,8 +99,8 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
@ -120,32 +125,35 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
int daemon(int nochdir, int noclose) {
|
||||
int fd;
|
||||
int daemon( int nochdir, int noclose )
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
_exit(0);
|
||||
}
|
||||
switch ( fork() )
|
||||
{
|
||||
case -1:
|
||||
return ( -1 );
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
_exit( 0 );
|
||||
}
|
||||
|
||||
if (setsid() == -1)
|
||||
return (-1);
|
||||
if ( setsid() == -1 )
|
||||
return ( -1 );
|
||||
|
||||
if (!nochdir)
|
||||
(void)chdir("/");
|
||||
if ( !nochdir )
|
||||
( void )chdir( "/" );
|
||||
|
||||
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
(void)dup2(fd, 0);
|
||||
(void)dup2(fd, 1);
|
||||
(void)dup2(fd, 2);
|
||||
if (fd > 2)
|
||||
(void)close (fd);
|
||||
}
|
||||
return (0);
|
||||
if ( !noclose && ( fd = open( "/dev/null", O_RDWR, 0 ) ) != -1 )
|
||||
{
|
||||
( void )dup2( fd, 0 );
|
||||
( void )dup2( fd, 1 );
|
||||
( void )dup2( fd, 2 );
|
||||
if ( fd > 2 )
|
||||
( void )close ( fd );
|
||||
}
|
||||
return ( 0 );
|
||||
}
|
||||
/*
|
||||
* End: src/lib/libresolv2/common/bsd/daemon.c
|
||||
@ -169,7 +177,7 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -181,8 +189,8 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
@ -218,29 +226,34 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
*
|
||||
* If *stringp is NULL, strsep returns NULL.
|
||||
*/
|
||||
char *strsep(char **stringp, const char *delim) {
|
||||
char *s;
|
||||
const char *spanp;
|
||||
int c, sc;
|
||||
char *tok;
|
||||
char *strsep( char **stringp, const char *delim )
|
||||
{
|
||||
char *s;
|
||||
const char *spanp;
|
||||
int c, sc;
|
||||
char *tok;
|
||||
|
||||
if ((s = *stringp) == NULL)
|
||||
return (NULL);
|
||||
for (tok = s;;) {
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
if (c == 0)
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
*stringp = s;
|
||||
return (tok);
|
||||
}
|
||||
} while (sc != 0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
if ( ( s = *stringp ) == NULL )
|
||||
return ( NULL );
|
||||
for ( tok = s;; )
|
||||
{
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do
|
||||
{
|
||||
if ( ( sc = *spanp++ ) == c )
|
||||
{
|
||||
if ( c == 0 )
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
*stringp = s;
|
||||
return ( tok );
|
||||
}
|
||||
}
|
||||
while ( sc != 0 );
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -36,31 +36,31 @@
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FFS
|
||||
extern int ffs(int i);
|
||||
extern int ffs( int i );
|
||||
#endif /* HAVE_FFS */
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
extern int daemon(int nochdir, int noclose);
|
||||
extern int daemon( int nochdir, int noclose );
|
||||
#endif /* HAVE_DAEMON */
|
||||
|
||||
#ifndef HAVE_STRSEP
|
||||
extern char *strsep(char **stringp, const char *delim);
|
||||
extern char *strsep( char **stringp, const char *delim );
|
||||
#endif /* HAVE_STRSEP */
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
#define HAVE_STDIO_H /* mimic config.h */
|
||||
#define HAVE_STDIO_H /* mimic config.h */
|
||||
#define HAVE_STDARG_H
|
||||
|
||||
#define atoll _atoi64
|
||||
#define fdatasync commit
|
||||
#define __inline__ inline
|
||||
#define __attribute__(X) /*nothing*/
|
||||
#define atoll _atoi64
|
||||
#define fdatasync commit
|
||||
#define __inline__ inline
|
||||
#define __attribute__(X) /*nothing*/
|
||||
|
||||
#else /* !defined WINDOWS */
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0 /* unix is binary by default */
|
||||
#define O_BINARY 0 /* unix is binary by default */
|
||||
#endif
|
||||
|
||||
#ifdef GEKKO
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* compress.h - Exports for compressed attribute handling.
|
||||
* Originated from the Linux-NTFS project.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
*
|
||||
@ -26,16 +26,16 @@
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
|
||||
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_compressed_attr_pread( ntfs_attr *na, s64 pos, s64 count,
|
||||
void *b );
|
||||
|
||||
extern s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *brl, s64 wpos,
|
||||
s64 offs, s64 to_write, s64 rounded,
|
||||
const void *b, int compressed_part,
|
||||
VCN *update_from);
|
||||
extern s64 ntfs_compressed_pwrite( ntfs_attr *na, runlist_element *brl, s64 wpos,
|
||||
s64 offs, s64 to_write, s64 rounded,
|
||||
const void *b, int compressed_part,
|
||||
VCN *update_from );
|
||||
|
||||
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl,
|
||||
s64 offs, VCN *update_from);
|
||||
extern int ntfs_compressed_close( ntfs_attr *na, runlist_element *brl,
|
||||
s64 offs, VCN *update_from );
|
||||
|
||||
#endif /* defined _NTFS_COMPRESS_H */
|
||||
|
||||
|
@ -42,37 +42,43 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||
void ntfs_debug_runlist_dump( const runlist_element *rl )
|
||||
{
|
||||
int i = 0;
|
||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||
"LCN_unknown " };
|
||||
int i = 0;
|
||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||
"LCN_unknown "
|
||||
};
|
||||
|
||||
ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
|
||||
if (!rl) {
|
||||
ntfs_log_debug("Run list not present.\n");
|
||||
return;
|
||||
}
|
||||
ntfs_log_debug("VCN LCN Run length\n");
|
||||
do {
|
||||
LCN lcn = (rl + i)->lcn;
|
||||
ntfs_log_debug( "NTFS-fs DEBUG: Dumping runlist (values in hex):\n" );
|
||||
if ( !rl )
|
||||
{
|
||||
ntfs_log_debug( "Run list not present.\n" );
|
||||
return;
|
||||
}
|
||||
ntfs_log_debug( "VCN LCN Run length\n" );
|
||||
do
|
||||
{
|
||||
LCN lcn = ( rl + i )->lcn;
|
||||
|
||||
if (lcn < (LCN)0) {
|
||||
int idx = -lcn - 1;
|
||||
if ( lcn < ( LCN )0 )
|
||||
{
|
||||
int idx = -lcn - 1;
|
||||
|
||||
if (idx > -LCN_EINVAL - 1)
|
||||
idx = 4;
|
||||
ntfs_log_debug("%-16lld %s %-16lld%s\n",
|
||||
(long long)rl[i].vcn, lcn_str[idx],
|
||||
(long long)rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)");
|
||||
} else
|
||||
ntfs_log_debug("%-16lld %-16lld %-16lld%s\n",
|
||||
(long long)rl[i].vcn, (long long)rl[i].lcn,
|
||||
(long long)rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)");
|
||||
} while (rl[i++].length);
|
||||
if ( idx > -LCN_EINVAL - 1 )
|
||||
idx = 4;
|
||||
ntfs_log_debug( "%-16lld %s %-16lld%s\n",
|
||||
( long long )rl[i].vcn, lcn_str[idx],
|
||||
( long long )rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)" );
|
||||
}
|
||||
else
|
||||
ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n",
|
||||
( long long )rl[i].vcn, ( long long )rl[i].lcn,
|
||||
( long long )rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)" );
|
||||
}
|
||||
while ( rl[i++].length );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -31,17 +31,17 @@
|
||||
struct _runlist_element;
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl);
|
||||
extern void ntfs_debug_runlist_dump( const struct _runlist_element *rl );
|
||||
#else
|
||||
static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {}
|
||||
static __inline__ void ntfs_debug_runlist_dump( const struct _runlist_element *rl __attribute__( ( unused ) ) ) {}
|
||||
#endif
|
||||
|
||||
#define NTFS_BUG(msg) \
|
||||
{ \
|
||||
int ___i; \
|
||||
ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \
|
||||
ntfs_log_debug("Forcing segmentation fault!"); \
|
||||
___i = ((int*)NULL)[1]; \
|
||||
#define NTFS_BUG(msg) \
|
||||
{ \
|
||||
int ___i; \
|
||||
ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \
|
||||
ntfs_log_debug("Forcing segmentation fault!"); \
|
||||
___i = ((int*)NULL)[1]; \
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_DEBUG_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,32 +36,33 @@
|
||||
*
|
||||
* Defined bits for the state field in the ntfs_device structure.
|
||||
*/
|
||||
typedef enum {
|
||||
ND_Open, /* 1: Device is open. */
|
||||
ND_ReadOnly, /* 1: Device is read-only. */
|
||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||
ND_Block, /* 1: Device is a block device. */
|
||||
typedef enum
|
||||
{
|
||||
ND_Open, /* 1: Device is open. */
|
||||
ND_ReadOnly, /* 1: Device is read-only. */
|
||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||
ND_Block, /* 1: Device is a block device. */
|
||||
} ntfs_device_state_bits;
|
||||
|
||||
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
|
||||
#define set_ndev_flag(nd, flag) set_bit(ND_##flag, (nd)->d_state)
|
||||
#define clear_ndev_flag(nd, flag) clear_bit(ND_##flag, (nd)->d_state)
|
||||
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
|
||||
#define set_ndev_flag(nd, flag) set_bit(ND_##flag, (nd)->d_state)
|
||||
#define clear_ndev_flag(nd, flag) clear_bit(ND_##flag, (nd)->d_state)
|
||||
|
||||
#define NDevOpen(nd) test_ndev_flag(nd, Open)
|
||||
#define NDevSetOpen(nd) set_ndev_flag(nd, Open)
|
||||
#define NDevClearOpen(nd) clear_ndev_flag(nd, Open)
|
||||
#define NDevOpen(nd) test_ndev_flag(nd, Open)
|
||||
#define NDevSetOpen(nd) set_ndev_flag(nd, Open)
|
||||
#define NDevClearOpen(nd) clear_ndev_flag(nd, Open)
|
||||
|
||||
#define NDevReadOnly(nd) test_ndev_flag(nd, ReadOnly)
|
||||
#define NDevSetReadOnly(nd) set_ndev_flag(nd, ReadOnly)
|
||||
#define NDevClearReadOnly(nd) clear_ndev_flag(nd, ReadOnly)
|
||||
#define NDevReadOnly(nd) test_ndev_flag(nd, ReadOnly)
|
||||
#define NDevSetReadOnly(nd) set_ndev_flag(nd, ReadOnly)
|
||||
#define NDevClearReadOnly(nd) clear_ndev_flag(nd, ReadOnly)
|
||||
|
||||
#define NDevDirty(nd) test_ndev_flag(nd, Dirty)
|
||||
#define NDevSetDirty(nd) set_ndev_flag(nd, Dirty)
|
||||
#define NDevClearDirty(nd) clear_ndev_flag(nd, Dirty)
|
||||
#define NDevDirty(nd) test_ndev_flag(nd, Dirty)
|
||||
#define NDevSetDirty(nd) set_ndev_flag(nd, Dirty)
|
||||
#define NDevClearDirty(nd) clear_ndev_flag(nd, Dirty)
|
||||
|
||||
#define NDevBlock(nd) test_ndev_flag(nd, Block)
|
||||
#define NDevSetBlock(nd) set_ndev_flag(nd, Block)
|
||||
#define NDevClearBlock(nd) clear_ndev_flag(nd, Block)
|
||||
#define NDevBlock(nd) test_ndev_flag(nd, Block)
|
||||
#define NDevSetBlock(nd) set_ndev_flag(nd, Block)
|
||||
#define NDevClearBlock(nd) clear_ndev_flag(nd, Block)
|
||||
|
||||
/**
|
||||
* struct ntfs_device -
|
||||
@ -69,12 +70,13 @@ typedef enum {
|
||||
* The ntfs device structure defining all operations needed to access the low
|
||||
* level device underlying the ntfs volume.
|
||||
*/
|
||||
struct ntfs_device {
|
||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||
unsigned long d_state; /* State of the device. */
|
||||
char *d_name; /* Name of device. */
|
||||
void *d_private; /* Private data used by the
|
||||
device operations. */
|
||||
struct ntfs_device
|
||||
{
|
||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||
unsigned long d_state; /* State of the device. */
|
||||
char *d_name; /* Name of device. */
|
||||
void *d_private; /* Private data used by the
|
||||
device operations. */
|
||||
};
|
||||
|
||||
struct stat;
|
||||
@ -85,44 +87,45 @@ struct stat;
|
||||
* The ntfs device operations defining all operations that can be performed on
|
||||
* the low level device described by an ntfs device structure.
|
||||
*/
|
||||
struct ntfs_device_operations {
|
||||
int (*open)(struct ntfs_device *dev, int flags);
|
||||
int (*close)(struct ntfs_device *dev);
|
||||
s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence);
|
||||
s64 (*read)(struct ntfs_device *dev, void *buf, s64 count);
|
||||
s64 (*write)(struct ntfs_device *dev, const void *buf, s64 count);
|
||||
s64 (*pread)(struct ntfs_device *dev, void *buf, s64 count, s64 offset);
|
||||
s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count,
|
||||
s64 offset);
|
||||
int (*sync)(struct ntfs_device *dev);
|
||||
int (*stat)(struct ntfs_device *dev, struct stat *buf);
|
||||
int (*ioctl)(struct ntfs_device *dev, int request, void *argp);
|
||||
struct ntfs_device_operations
|
||||
{
|
||||
int ( *open )( struct ntfs_device *dev, int flags );
|
||||
int ( *close )( struct ntfs_device *dev );
|
||||
s64 ( *seek )( struct ntfs_device *dev, s64 offset, int whence );
|
||||
s64 ( *read )( struct ntfs_device *dev, void *buf, s64 count );
|
||||
s64 ( *write )( struct ntfs_device *dev, const void *buf, s64 count );
|
||||
s64 ( *pread )( struct ntfs_device *dev, void *buf, s64 count, s64 offset );
|
||||
s64 ( *pwrite )( struct ntfs_device *dev, const void *buf, s64 count,
|
||||
s64 offset );
|
||||
int ( *sync )( struct ntfs_device *dev );
|
||||
int ( *stat )( struct ntfs_device *dev, struct stat *buf );
|
||||
int ( *ioctl )( struct ntfs_device *dev, int request, void *argp );
|
||||
};
|
||||
|
||||
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
struct ntfs_device_operations *dops, void *priv_data);
|
||||
extern int ntfs_device_free(struct ntfs_device *dev);
|
||||
extern struct ntfs_device *ntfs_device_alloc( const char *name, const long state,
|
||||
struct ntfs_device_operations *dops, void *priv_data );
|
||||
extern int ntfs_device_free( struct ntfs_device *dev );
|
||||
|
||||
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b);
|
||||
extern s64 ntfs_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
void *b );
|
||||
extern s64 ntfs_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b );
|
||||
|
||||
extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b);
|
||||
extern s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b);
|
||||
extern s64 ntfs_mst_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b );
|
||||
extern s64 ntfs_mst_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b );
|
||||
|
||||
extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, void *b);
|
||||
extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b);
|
||||
extern s64 ntfs_cluster_read( const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, void *b );
|
||||
extern s64 ntfs_cluster_write( const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b );
|
||||
|
||||
extern s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size);
|
||||
extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_heads_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_sectors_per_track_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_sector_size_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size);
|
||||
extern s64 ntfs_device_size_get( struct ntfs_device *dev, int block_size );
|
||||
extern s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev );
|
||||
extern int ntfs_device_heads_get( struct ntfs_device *dev );
|
||||
extern int ntfs_device_sectors_per_track_get( struct ntfs_device *dev );
|
||||
extern int ntfs_device_sector_size_get( struct ntfs_device *dev );
|
||||
extern int ntfs_device_block_size_set( struct ntfs_device *dev, int block_size );
|
||||
|
||||
#endif /* defined _NTFS_DEVICE_H */
|
||||
|
@ -41,28 +41,29 @@
|
||||
#else /* __CYGWIN32__ */
|
||||
|
||||
#ifndef HDIO_GETGEO
|
||||
# define HDIO_GETGEO 0x301
|
||||
# define HDIO_GETGEO 0x301
|
||||
/**
|
||||
* struct hd_geometry -
|
||||
*/
|
||||
struct hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
struct hd_geometry
|
||||
{
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
};
|
||||
#endif
|
||||
#ifndef BLKGETSIZE
|
||||
# define BLKGETSIZE 0x1260
|
||||
# define BLKGETSIZE 0x1260
|
||||
#endif
|
||||
#ifndef BLKSSZGET
|
||||
# define BLKSSZGET 0x1268
|
||||
# define BLKSSZGET 0x1268
|
||||
#endif
|
||||
#ifndef BLKGETSIZE64
|
||||
# define BLKGETSIZE64 0x80041272
|
||||
# define BLKGETSIZE64 0x80041272
|
||||
#endif
|
||||
#ifndef BLKBSZSET
|
||||
# define BLKBSZSET 0x40041271
|
||||
# define BLKBSZSET 0x40041271
|
||||
#endif
|
||||
|
||||
/* On Cygwin; use Win32 low level device operations. */
|
||||
|
4437
source/libntfs/dir.c
4437
source/libntfs/dir.c
File diff suppressed because it is too large
Load Diff
@ -59,40 +59,40 @@ extern ntfschar NTFS_INDEX_O[3];
|
||||
extern ntfschar NTFS_INDEX_Q[3];
|
||||
extern ntfschar NTFS_INDEX_R[3];
|
||||
|
||||
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
|
||||
const ntfschar *uname, const int uname_len);
|
||||
extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name);
|
||||
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name,
|
||||
u64 inum);
|
||||
extern u64 ntfs_inode_lookup_by_name( ntfs_inode *dir_ni,
|
||||
const ntfschar *uname, const int uname_len );
|
||||
extern u64 ntfs_inode_lookup_by_mbsname( ntfs_inode *dir_ni, const char *name );
|
||||
extern void ntfs_inode_update_mbsname( ntfs_inode *dir_ni, const char *name,
|
||||
u64 inum );
|
||||
|
||||
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
const char *pathname);
|
||||
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type);
|
||||
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev);
|
||||
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len);
|
||||
extern int ntfs_check_empty_dir(ntfs_inode *ni);
|
||||
extern int ntfs_delete(ntfs_volume *vol, const char *path,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
extern ntfs_inode *ntfs_pathname_to_inode( ntfs_volume *vol, ntfs_inode *parent,
|
||||
const char *pathname );
|
||||
extern ntfs_inode *ntfs_create( ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type );
|
||||
extern ntfs_inode *ntfs_create_device( ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev );
|
||||
extern ntfs_inode *ntfs_create_symlink( ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len );
|
||||
extern int ntfs_check_empty_dir( ntfs_inode *ni );
|
||||
extern int ntfs_delete( ntfs_volume *vol, const char *path,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len );
|
||||
|
||||
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
extern int ntfs_link( ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len );
|
||||
|
||||
/*
|
||||
* File types (adapted from include <linux/fs.h>)
|
||||
*/
|
||||
#define NTFS_DT_UNKNOWN 0
|
||||
#define NTFS_DT_FIFO 1
|
||||
#define NTFS_DT_CHR 2
|
||||
#define NTFS_DT_DIR 4
|
||||
#define NTFS_DT_BLK 6
|
||||
#define NTFS_DT_REG 8
|
||||
#define NTFS_DT_LNK 10
|
||||
#define NTFS_DT_SOCK 12
|
||||
#define NTFS_DT_WHT 14
|
||||
#define NTFS_DT_UNKNOWN 0
|
||||
#define NTFS_DT_FIFO 1
|
||||
#define NTFS_DT_CHR 2
|
||||
#define NTFS_DT_DIR 4
|
||||
#define NTFS_DT_BLK 6
|
||||
#define NTFS_DT_REG 8
|
||||
#define NTFS_DT_LNK 10
|
||||
#define NTFS_DT_SOCK 12
|
||||
#define NTFS_DT_WHT 14
|
||||
|
||||
/*
|
||||
* This is the "ntfs_filldir" function type, used by ntfs_readdir() to let
|
||||
@ -100,27 +100,27 @@ extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
* This allows the caller to read directories into their application or
|
||||
* to have different dirent layouts depending on the binary type.
|
||||
*/
|
||||
typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name,
|
||||
const int name_len, const int name_type, const s64 pos,
|
||||
const MFT_REF mref, const unsigned dt_type);
|
||||
typedef int ( *ntfs_filldir_t )( void *dirent, const ntfschar *name,
|
||||
const int name_len, const int name_type, const s64 pos,
|
||||
const MFT_REF mref, const unsigned dt_type );
|
||||
|
||||
extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
void *dirent, ntfs_filldir_t filldir);
|
||||
extern int ntfs_readdir( ntfs_inode *dir_ni, s64 *pos,
|
||||
void *dirent, ntfs_filldir_t filldir );
|
||||
|
||||
ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni);
|
||||
ntfs_inode *ntfs_dir_parent_inode( ntfs_inode *ni );
|
||||
|
||||
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size);
|
||||
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
const char *value, size_t size, int flags);
|
||||
int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||
int ntfs_get_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size );
|
||||
int ntfs_set_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
const char *value, size_t size, int flags );
|
||||
int ntfs_remove_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni );
|
||||
|
||||
#if CACHE_INODE_SIZE
|
||||
|
||||
struct CACHED_GENERIC;
|
||||
|
||||
extern int ntfs_dir_inode_hash(const struct CACHED_GENERIC *cached);
|
||||
extern int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached);
|
||||
extern int ntfs_dir_inode_hash( const struct CACHED_GENERIC *cached );
|
||||
extern int ntfs_dir_lookup_hash( const struct CACHED_GENERIC *cached );
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* efs.c - Limited processing of encrypted files
|
||||
*
|
||||
* This module is part of ntfs-3g library
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2009 Martin Bene
|
||||
* Copyright (c) 2009-2010 Jean-Pierre Andre
|
||||
@ -58,256 +58,305 @@
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
static ntfschar logged_utility_stream_name[] = {
|
||||
const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('E'),
|
||||
const_cpu_to_le16('F'),
|
||||
const_cpu_to_le16('S'),
|
||||
const_cpu_to_le16(0)
|
||||
static ntfschar logged_utility_stream_name[] =
|
||||
{
|
||||
const_cpu_to_le16( '$' ),
|
||||
const_cpu_to_le16( 'E' ),
|
||||
const_cpu_to_le16( 'F' ),
|
||||
const_cpu_to_le16( 'S' ),
|
||||
const_cpu_to_le16( 0 )
|
||||
} ;
|
||||
|
||||
|
||||
/*
|
||||
* Get the ntfs EFS info into an extended attribute
|
||||
* Get the ntfs EFS info into an extended attribute
|
||||
*/
|
||||
|
||||
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
||||
int ntfs_get_efs_info( ntfs_inode *ni, char *value, size_t size )
|
||||
{
|
||||
EFS_ATTR_HEADER *efs_info;
|
||||
s64 attr_size = 0;
|
||||
EFS_ATTR_HEADER *efs_info;
|
||||
s64 attr_size = 0;
|
||||
|
||||
if (ni) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
|
||||
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
|
||||
&attr_size);
|
||||
if (efs_info
|
||||
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
||||
if (attr_size <= (s64)size) {
|
||||
if (value)
|
||||
memcpy(value,efs_info,attr_size);
|
||||
else {
|
||||
errno = EFAULT;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else
|
||||
if (size) {
|
||||
errno = ERANGE;
|
||||
attr_size = 0;
|
||||
}
|
||||
free (efs_info);
|
||||
} else {
|
||||
if (efs_info) {
|
||||
free(efs_info);
|
||||
ntfs_log_error("Bad efs_info for inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
} else {
|
||||
ntfs_log_error("Could not get efsinfo"
|
||||
" for inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
ntfs_log_trace("Inode %lld is not encrypted\n",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
}
|
||||
return (attr_size ? (int)attr_size : -errno);
|
||||
if ( ni )
|
||||
{
|
||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||
{
|
||||
efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni,
|
||||
AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0,
|
||||
&attr_size );
|
||||
if ( efs_info
|
||||
&& ( le32_to_cpu( efs_info->length ) == attr_size ) )
|
||||
{
|
||||
if ( attr_size <= ( s64 )size )
|
||||
{
|
||||
if ( value )
|
||||
memcpy( value, efs_info, attr_size );
|
||||
else
|
||||
{
|
||||
errno = EFAULT;
|
||||
attr_size = 0;
|
||||
}
|
||||
}
|
||||
else if ( size )
|
||||
{
|
||||
errno = ERANGE;
|
||||
attr_size = 0;
|
||||
}
|
||||
free ( efs_info );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( efs_info )
|
||||
{
|
||||
free( efs_info );
|
||||
ntfs_log_error( "Bad efs_info for inode %lld\n",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Could not get efsinfo"
|
||||
" for inode %lld\n",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
ntfs_log_trace( "Inode %lld is not encrypted\n",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
}
|
||||
return ( attr_size ? ( int )attr_size : -errno );
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix all encrypted AT_DATA attributes of an inode
|
||||
* Fix all encrypted AT_DATA attributes of an inode
|
||||
*
|
||||
* The fix may require making an attribute non resident, which
|
||||
* requires more space in the MFT record, and may cause some
|
||||
* attribute to be expelled and the full record to be reorganized.
|
||||
* When this happens, the search for data attributes has to be
|
||||
* reinitialized.
|
||||
* The fix may require making an attribute non resident, which
|
||||
* requires more space in the MFT record, and may cause some
|
||||
* attribute to be expelled and the full record to be reorganized.
|
||||
* When this happens, the search for data attributes has to be
|
||||
* reinitialized.
|
||||
*
|
||||
* Returns zero if successful.
|
||||
* -1 if there is a problem.
|
||||
* Returns zero if successful.
|
||||
* -1 if there is a problem.
|
||||
*/
|
||||
|
||||
static int fixup_loop(ntfs_inode *ni)
|
||||
static int fixup_loop( ntfs_inode *ni )
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ntfs_attr *na;
|
||||
ATTR_RECORD *a;
|
||||
BOOL restart;
|
||||
BOOL first;
|
||||
int cnt;
|
||||
int maxcnt;
|
||||
int res = 0;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ntfs_attr *na;
|
||||
ATTR_RECORD *a;
|
||||
BOOL restart;
|
||||
BOOL first;
|
||||
int cnt;
|
||||
int maxcnt;
|
||||
int res = 0;
|
||||
|
||||
maxcnt = 0;
|
||||
do {
|
||||
restart = FALSE;
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
res = -1;
|
||||
}
|
||||
cnt = 0;
|
||||
while (!restart && !res
|
||||
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
cnt++;
|
||||
a = ctx->attr;
|
||||
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
|
||||
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length);
|
||||
if (!na) {
|
||||
ntfs_log_error("can't open DATA Attribute\n");
|
||||
res = -1;
|
||||
}
|
||||
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
|
||||
if (!NAttrNonResident(na)
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
/*
|
||||
* ntfs_attr_make_non_resident fails if there
|
||||
* is not enough space in the MFT record.
|
||||
* When this happens, force making non-resident
|
||||
* so that some other attribute is expelled.
|
||||
*/
|
||||
if (ntfs_attr_force_non_resident(na)) {
|
||||
res = -1;
|
||||
} else {
|
||||
/* make sure there is some progress */
|
||||
if (cnt <= maxcnt) {
|
||||
errno = EIO;
|
||||
ntfs_log_error("Multiple failure"
|
||||
" making non resident\n");
|
||||
res = -1;
|
||||
} else {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||
restart = TRUE;
|
||||
maxcnt = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!restart && !res
|
||||
&& ntfs_efs_fixup_attribute(ctx, na)) {
|
||||
ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
first = FALSE;
|
||||
} while (restart && !res);
|
||||
if (ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (res);
|
||||
maxcnt = 0;
|
||||
do
|
||||
{
|
||||
restart = FALSE;
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if ( !ctx )
|
||||
{
|
||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||
res = -1;
|
||||
}
|
||||
cnt = 0;
|
||||
while ( !restart && !res
|
||||
&& !ntfs_attr_lookup( AT_DATA, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
cnt++;
|
||||
a = ctx->attr;
|
||||
na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA,
|
||||
( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ),
|
||||
a->name_length );
|
||||
if ( !na )
|
||||
{
|
||||
ntfs_log_error( "can't open DATA Attribute\n" );
|
||||
res = -1;
|
||||
}
|
||||
if ( na && !( ctx->attr->flags & ATTR_IS_ENCRYPTED ) )
|
||||
{
|
||||
if ( !NAttrNonResident( na )
|
||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||
{
|
||||
/*
|
||||
* ntfs_attr_make_non_resident fails if there
|
||||
* is not enough space in the MFT record.
|
||||
* When this happens, force making non-resident
|
||||
* so that some other attribute is expelled.
|
||||
*/
|
||||
if ( ntfs_attr_force_non_resident( na ) )
|
||||
{
|
||||
res = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* make sure there is some progress */
|
||||
if ( cnt <= maxcnt )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_error( "Multiple failure"
|
||||
" making non resident\n" );
|
||||
res = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
ctx = ( ntfs_attr_search_ctx* )NULL;
|
||||
restart = TRUE;
|
||||
maxcnt = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !restart && !res
|
||||
&& ntfs_efs_fixup_attribute( ctx, na ) )
|
||||
{
|
||||
ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" );
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
first = FALSE;
|
||||
}
|
||||
while ( restart && !res );
|
||||
if ( ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
return ( res );
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the efs data from an extended attribute
|
||||
* Warning : the new data is not checked
|
||||
* Returns 0, or -1 if there is a problem
|
||||
* Set the efs data from an extended attribute
|
||||
* Warning : the new data is not checked
|
||||
* Returns 0, or -1 if there is a problem
|
||||
*/
|
||||
|
||||
int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
int flags)
|
||||
int ntfs_set_efs_info( ntfs_inode *ni, const char *value, size_t size,
|
||||
int flags )
|
||||
|
||||
{
|
||||
int res;
|
||||
int written;
|
||||
ntfs_attr *na;
|
||||
const EFS_ATTR_HEADER *info_header;
|
||||
int res;
|
||||
int written;
|
||||
ntfs_attr *na;
|
||||
const EFS_ATTR_HEADER *info_header;
|
||||
|
||||
res = 0;
|
||||
if (ni && value && size) {
|
||||
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
ntfs_log_trace("Inode %lld already encrypted\n",
|
||||
(long long)ni->mft_no);
|
||||
errno = EEXIST;
|
||||
} else {
|
||||
/*
|
||||
* Possible problem : if encrypted file was
|
||||
* restored in a compressed directory, it was
|
||||
* restored as compressed.
|
||||
* TODO : decompress first.
|
||||
*/
|
||||
ntfs_log_error("Inode %lld cannot be encrypted and compressed\n",
|
||||
(long long)ni->mft_no);
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
info_header = (const EFS_ATTR_HEADER*)value;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if (le32_to_cpu(info_header->length) != size) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
(ntfschar*)NULL,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
/*
|
||||
* no logged_utility_stream attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
*/
|
||||
res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name,4,
|
||||
(u8*)NULL,(s64)size);
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
/*
|
||||
* open and update the existing efs data
|
||||
*/
|
||||
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4);
|
||||
if (na) {
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate(na, (s64)size);
|
||||
/* overwrite value if any */
|
||||
if (!res && value) {
|
||||
written = (int)ntfs_attr_pwrite(na,
|
||||
(s64)0, (s64)size, value);
|
||||
if (written != (s64)size) {
|
||||
ntfs_log_error("Failed to "
|
||||
"update efs data\n");
|
||||
errno = EIO;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
/* iterate over AT_DATA attributes */
|
||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||
res = 0;
|
||||
if ( ni && value && size )
|
||||
{
|
||||
if ( ni->flags & ( FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED ) )
|
||||
{
|
||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||
{
|
||||
ntfs_log_trace( "Inode %lld already encrypted\n",
|
||||
( long long )ni->mft_no );
|
||||
errno = EEXIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Possible problem : if encrypted file was
|
||||
* restored in a compressed directory, it was
|
||||
* restored as compressed.
|
||||
* TODO : decompress first.
|
||||
*/
|
||||
ntfs_log_error( "Inode %lld cannot be encrypted and compressed\n",
|
||||
( long long )ni->mft_no );
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
info_header = ( const EFS_ATTR_HEADER* )value;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if ( le32_to_cpu( info_header->length ) != size )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return ( -1 );
|
||||
}
|
||||
if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
( ntfschar* )NULL, 0 ) )
|
||||
{
|
||||
if ( !( flags & XATTR_REPLACE ) )
|
||||
{
|
||||
/*
|
||||
* no logged_utility_stream attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
*/
|
||||
res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4,
|
||||
( u8* )NULL, ( s64 )size );
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if ( !res )
|
||||
{
|
||||
/*
|
||||
* open and update the existing efs data
|
||||
*/
|
||||
na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4 );
|
||||
if ( na )
|
||||
{
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate( na, ( s64 )size );
|
||||
/* overwrite value if any */
|
||||
if ( !res && value )
|
||||
{
|
||||
written = ( int )ntfs_attr_pwrite( na,
|
||||
( s64 )0, ( s64 )size, value );
|
||||
if ( written != ( s64 )size )
|
||||
{
|
||||
ntfs_log_error( "Failed to "
|
||||
"update efs data\n" );
|
||||
errno = EIO;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
else
|
||||
res = -1;
|
||||
}
|
||||
if ( !res )
|
||||
{
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if ( !( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
/* iterate over AT_DATA attributes */
|
||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||
|
||||
if (fixup_loop(ni))
|
||||
return -1;
|
||||
}
|
||||
ni->flags |= FILE_ATTR_ENCRYPTED;
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
return (res ? -1 : 0);
|
||||
if ( fixup_loop( ni ) )
|
||||
return -1;
|
||||
}
|
||||
ni->flags |= FILE_ATTR_ENCRYPTED;
|
||||
NInoSetDirty( ni );
|
||||
NInoFileNameSetDirty( ni );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
return ( res ? -1 : 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -317,123 +366,142 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
* set data size to match padding length
|
||||
* set ATTR_IS_ENCRYPTED flag on attribute
|
||||
*
|
||||
* Return 0 if successful
|
||||
* -1 if failed (errno tells why)
|
||||
* Return 0 if successful
|
||||
* -1 if failed (errno tells why)
|
||||
*/
|
||||
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
int ntfs_efs_fixup_attribute( ntfs_attr_search_ctx *ctx, ntfs_attr *na )
|
||||
{
|
||||
u64 newsize;
|
||||
u64 oldsize;
|
||||
le16 appended_bytes;
|
||||
u16 padding_length;
|
||||
ntfs_inode *ni;
|
||||
BOOL close_ctx = FALSE;
|
||||
u64 newsize;
|
||||
u64 oldsize;
|
||||
le16 appended_bytes;
|
||||
u16 padding_length;
|
||||
ntfs_inode *ni;
|
||||
BOOL close_ctx = FALSE;
|
||||
|
||||
if (!na) {
|
||||
ntfs_log_error("no na specified for efs_fixup_attribute\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (!ctx) {
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
goto err_out;
|
||||
}
|
||||
close_ctx = TRUE;
|
||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
if (!NAttrNonResident(na)) {
|
||||
ntfs_log_error("Cannot make non resident"
|
||||
" when a context has been allocated\n");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
if ( !na )
|
||||
{
|
||||
ntfs_log_error( "no na specified for efs_fixup_attribute\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if ( !ctx )
|
||||
{
|
||||
ctx = ntfs_attr_get_search_ctx( na->ni, NULL );
|
||||
if ( !ctx )
|
||||
{
|
||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||
goto err_out;
|
||||
}
|
||||
close_ctx = TRUE;
|
||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !NAttrNonResident( na ) )
|
||||
{
|
||||
ntfs_log_error( "Cannot make non resident"
|
||||
" when a context has been allocated\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* no extra bytes are added to void attributes */
|
||||
oldsize = na->data_size;
|
||||
if (oldsize) {
|
||||
/* make sure size is valid for a raw encrypted stream */
|
||||
if ((oldsize & 511) != 2) {
|
||||
ntfs_log_error("Bad raw encrypted stream\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* read padding length from last two bytes of attribute */
|
||||
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
|
||||
ntfs_log_error("Error reading padding length\n");
|
||||
goto err_out;
|
||||
}
|
||||
padding_length = le16_to_cpu(appended_bytes);
|
||||
if (padding_length > 511 || padding_length > na->data_size-2) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_error("invalid padding length %d for data_size %lld\n",
|
||||
padding_length, (long long)oldsize);
|
||||
goto err_out;
|
||||
}
|
||||
newsize = oldsize - padding_length - 2;
|
||||
/*
|
||||
* truncate attribute to possibly free clusters allocated
|
||||
* for the last two bytes, but do not truncate to new size
|
||||
* to avoid losing useful data
|
||||
*/
|
||||
if (ntfs_attr_truncate(na, oldsize - 2)) {
|
||||
ntfs_log_error("Error truncating attribute\n");
|
||||
goto err_out;
|
||||
}
|
||||
} else
|
||||
newsize = 0;
|
||||
/* no extra bytes are added to void attributes */
|
||||
oldsize = na->data_size;
|
||||
if ( oldsize )
|
||||
{
|
||||
/* make sure size is valid for a raw encrypted stream */
|
||||
if ( ( oldsize & 511 ) != 2 )
|
||||
{
|
||||
ntfs_log_error( "Bad raw encrypted stream\n" );
|
||||
goto err_out;
|
||||
}
|
||||
/* read padding length from last two bytes of attribute */
|
||||
if ( ntfs_attr_pread( na, oldsize - 2, 2, &appended_bytes ) != 2 )
|
||||
{
|
||||
ntfs_log_error( "Error reading padding length\n" );
|
||||
goto err_out;
|
||||
}
|
||||
padding_length = le16_to_cpu( appended_bytes );
|
||||
if ( padding_length > 511 || padding_length > na->data_size - 2 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_error( "invalid padding length %d for data_size %lld\n",
|
||||
padding_length, ( long long )oldsize );
|
||||
goto err_out;
|
||||
}
|
||||
newsize = oldsize - padding_length - 2;
|
||||
/*
|
||||
* truncate attribute to possibly free clusters allocated
|
||||
* for the last two bytes, but do not truncate to new size
|
||||
* to avoid losing useful data
|
||||
*/
|
||||
if ( ntfs_attr_truncate( na, oldsize - 2 ) )
|
||||
{
|
||||
ntfs_log_error( "Error truncating attribute\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
else
|
||||
newsize = 0;
|
||||
|
||||
/*
|
||||
* Encrypted AT_DATA Attributes MUST be non-resident
|
||||
* This has to be done after the attribute is resized, as
|
||||
* resizing down to zero may cause the attribute to be made
|
||||
* resident.
|
||||
*/
|
||||
if (!NAttrNonResident(na)
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
if (!close_ctx
|
||||
|| ntfs_attr_force_non_resident(na)) {
|
||||
ntfs_log_error("Error making DATA attribute non-resident\n");
|
||||
goto err_out;
|
||||
} else {
|
||||
/*
|
||||
* must reinitialize context after forcing
|
||||
* non-resident. We need a context for updating
|
||||
* the state, and at this point, we are sure
|
||||
* the context is not used elsewhere.
|
||||
*/
|
||||
ntfs_attr_reinit_search_ctx(ctx);
|
||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
ni = na->ni;
|
||||
if (!na->name_len) {
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
/*
|
||||
* Encrypted AT_DATA Attributes MUST be non-resident
|
||||
* This has to be done after the attribute is resized, as
|
||||
* resizing down to zero may cause the attribute to be made
|
||||
* resident.
|
||||
*/
|
||||
if ( !NAttrNonResident( na )
|
||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||
{
|
||||
if ( !close_ctx
|
||||
|| ntfs_attr_force_non_resident( na ) )
|
||||
{
|
||||
ntfs_log_error( "Error making DATA attribute non-resident\n" );
|
||||
goto err_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* must reinitialize context after forcing
|
||||
* non-resident. We need a context for updating
|
||||
* the state, and at this point, we are sure
|
||||
* the context is not used elsewhere.
|
||||
*/
|
||||
ntfs_attr_reinit_search_ctx( ctx );
|
||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
ni = na->ni;
|
||||
if ( !na->name_len )
|
||||
{
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
NInoSetDirty( ni );
|
||||
NInoFileNameSetDirty( ni );
|
||||
|
||||
ctx->attr->data_size = cpu_to_le64(newsize);
|
||||
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
|
||||
ctx->attr->initialized_size = ctx->attr->data_size;
|
||||
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
||||
if (close_ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx->attr->data_size = cpu_to_le64( newsize );
|
||||
if ( le64_to_cpu( ctx->attr->initialized_size ) > newsize )
|
||||
ctx->attr->initialized_size = ctx->attr->data_size;
|
||||
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
||||
if ( close_ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
|
||||
return (0);
|
||||
return ( 0 );
|
||||
err_out:
|
||||
if (close_ctx && ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (-1);
|
||||
if ( close_ctx && ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
return ( -1 );
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
@ -21,10 +21,10 @@
|
||||
#ifndef EFS_H
|
||||
#define EFS_H
|
||||
|
||||
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size);
|
||||
int ntfs_get_efs_info( ntfs_inode *ni, char *value, size_t size );
|
||||
|
||||
int ntfs_set_efs_info(ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags);
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na);
|
||||
int ntfs_set_efs_info( ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags );
|
||||
int ntfs_efs_fixup_attribute( ntfs_attr_search_ctx *ctx, ntfs_attr *na );
|
||||
|
||||
#endif /* EFS_H */
|
||||
|
@ -29,9 +29,9 @@
|
||||
|
||||
/*
|
||||
* Notes:
|
||||
* We define the conversion functions including typecasts since the
|
||||
* We define the conversion functions including typecasts since the
|
||||
* defaults don't necessarily perform appropriate typecasts.
|
||||
* Also, using our own functions means that we can change them if it
|
||||
* Also, using our own functions means that we can change them if it
|
||||
* turns out that we do need to use the unaligned access macros on
|
||||
* architectures requiring aligned memory accesses...
|
||||
*/
|
||||
@ -53,59 +53,59 @@
|
||||
#endif
|
||||
|
||||
#ifndef __BYTE_ORDER
|
||||
# if defined(_BYTE_ORDER)
|
||||
# define __BYTE_ORDER _BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN _BIG_ENDIAN
|
||||
# elif defined(BYTE_ORDER)
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# elif defined(__BYTE_ORDER__)
|
||||
# define __BYTE_ORDER __BYTE_ORDER__
|
||||
# define __LITTLE_ENDIAN __LITTLE_ENDIAN__
|
||||
# define __BIG_ENDIAN __BIG_ENDIAN__
|
||||
# elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
|
||||
defined(WORDS_LITTLEENDIAN)
|
||||
# define __BYTE_ORDER 1
|
||||
# define __LITTLE_ENDIAN 1
|
||||
# define __BIG_ENDIAN 0
|
||||
# elif (!defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)) || \
|
||||
defined(WORDS_BIGENDIAN)
|
||||
# define __BYTE_ORDER 0
|
||||
# define __LITTLE_ENDIAN 1
|
||||
# define __BIG_ENDIAN 0
|
||||
# else
|
||||
# error "__BYTE_ORDER is not defined."
|
||||
# endif
|
||||
# if defined(_BYTE_ORDER)
|
||||
# define __BYTE_ORDER _BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN _BIG_ENDIAN
|
||||
# elif defined(BYTE_ORDER)
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# elif defined(__BYTE_ORDER__)
|
||||
# define __BYTE_ORDER __BYTE_ORDER__
|
||||
# define __LITTLE_ENDIAN __LITTLE_ENDIAN__
|
||||
# define __BIG_ENDIAN __BIG_ENDIAN__
|
||||
# elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
|
||||
defined(WORDS_LITTLEENDIAN)
|
||||
# define __BYTE_ORDER 1
|
||||
# define __LITTLE_ENDIAN 1
|
||||
# define __BIG_ENDIAN 0
|
||||
# elif (!defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)) || \
|
||||
defined(WORDS_BIGENDIAN)
|
||||
# define __BYTE_ORDER 0
|
||||
# define __LITTLE_ENDIAN 1
|
||||
# define __BIG_ENDIAN 0
|
||||
# else
|
||||
# error "__BYTE_ORDER is not defined."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define __ntfs_bswap_constant_16(x) \
|
||||
(u16)((((u16)(x) & 0xff00) >> 8) | \
|
||||
(((u16)(x) & 0x00ff) << 8))
|
||||
#define __ntfs_bswap_constant_16(x) \
|
||||
(u16)((((u16)(x) & 0xff00) >> 8) | \
|
||||
(((u16)(x) & 0x00ff) << 8))
|
||||
|
||||
#define __ntfs_bswap_constant_32(x) \
|
||||
(u32)((((u32)(x) & 0xff000000u) >> 24) | \
|
||||
(((u32)(x) & 0x00ff0000u) >> 8) | \
|
||||
(((u32)(x) & 0x0000ff00u) << 8) | \
|
||||
(((u32)(x) & 0x000000ffu) << 24))
|
||||
#define __ntfs_bswap_constant_32(x) \
|
||||
(u32)((((u32)(x) & 0xff000000u) >> 24) | \
|
||||
(((u32)(x) & 0x00ff0000u) >> 8) | \
|
||||
(((u32)(x) & 0x0000ff00u) << 8) | \
|
||||
(((u32)(x) & 0x000000ffu) << 24))
|
||||
|
||||
#define __ntfs_bswap_constant_64(x) \
|
||||
(u64)((((u64)(x) & 0xff00000000000000ull) >> 56) | \
|
||||
(((u64)(x) & 0x00ff000000000000ull) >> 40) | \
|
||||
(((u64)(x) & 0x0000ff0000000000ull) >> 24) | \
|
||||
(((u64)(x) & 0x000000ff00000000ull) >> 8) | \
|
||||
(((u64)(x) & 0x00000000ff000000ull) << 8) | \
|
||||
(((u64)(x) & 0x0000000000ff0000ull) << 24) | \
|
||||
(((u64)(x) & 0x000000000000ff00ull) << 40) | \
|
||||
(((u64)(x) & 0x00000000000000ffull) << 56))
|
||||
#define __ntfs_bswap_constant_64(x) \
|
||||
(u64)((((u64)(x) & 0xff00000000000000ull) >> 56) | \
|
||||
(((u64)(x) & 0x00ff000000000000ull) >> 40) | \
|
||||
(((u64)(x) & 0x0000ff0000000000ull) >> 24) | \
|
||||
(((u64)(x) & 0x000000ff00000000ull) >> 8) | \
|
||||
(((u64)(x) & 0x00000000ff000000ull) << 8) | \
|
||||
(((u64)(x) & 0x0000000000ff0000ull) << 24) | \
|
||||
(((u64)(x) & 0x000000000000ff00ull) << 40) | \
|
||||
(((u64)(x) & 0x00000000000000ffull) << 56))
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
# include <byteswap.h>
|
||||
# include <byteswap.h>
|
||||
#else
|
||||
# define bswap_16(x) __ntfs_bswap_constant_16(x)
|
||||
# define bswap_32(x) __ntfs_bswap_constant_32(x)
|
||||
# define bswap_64(x) __ntfs_bswap_constant_64(x)
|
||||
# define bswap_16(x) __ntfs_bswap_constant_16(x)
|
||||
# define bswap_32(x) __ntfs_bswap_constant_32(x)
|
||||
# define bswap_64(x) __ntfs_bswap_constant_64(x)
|
||||
#endif
|
||||
|
||||
#if defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
@ -152,52 +152,52 @@
|
||||
|
||||
/* Unsigned from LE to CPU conversion. */
|
||||
|
||||
#define le16_to_cpu(x) (u16)__le16_to_cpu((u16)(x))
|
||||
#define le32_to_cpu(x) (u32)__le32_to_cpu((u32)(x))
|
||||
#define le64_to_cpu(x) (u64)__le64_to_cpu((u64)(x))
|
||||
#define le16_to_cpu(x) (u16)__le16_to_cpu((u16)(x))
|
||||
#define le32_to_cpu(x) (u32)__le32_to_cpu((u32)(x))
|
||||
#define le64_to_cpu(x) (u64)__le64_to_cpu((u64)(x))
|
||||
|
||||
#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const u16*)(x))
|
||||
#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const u32*)(x))
|
||||
#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const u64*)(x))
|
||||
#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const u16*)(x))
|
||||
#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const u32*)(x))
|
||||
#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const u64*)(x))
|
||||
|
||||
/* Signed from LE to CPU conversion. */
|
||||
|
||||
#define sle16_to_cpu(x) (s16)__le16_to_cpu((s16)(x))
|
||||
#define sle32_to_cpu(x) (s32)__le32_to_cpu((s32)(x))
|
||||
#define sle64_to_cpu(x) (s64)__le64_to_cpu((s64)(x))
|
||||
#define sle16_to_cpu(x) (s16)__le16_to_cpu((s16)(x))
|
||||
#define sle32_to_cpu(x) (s32)__le32_to_cpu((s32)(x))
|
||||
#define sle64_to_cpu(x) (s64)__le64_to_cpu((s64)(x))
|
||||
|
||||
#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(s16*)(x))
|
||||
#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(s32*)(x))
|
||||
#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(s64*)(x))
|
||||
#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(s16*)(x))
|
||||
#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(s32*)(x))
|
||||
#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(s64*)(x))
|
||||
|
||||
/* Unsigned from CPU to LE conversion. */
|
||||
|
||||
#define cpu_to_le16(x) (u16)__cpu_to_le16((u16)(x))
|
||||
#define cpu_to_le32(x) (u32)__cpu_to_le32((u32)(x))
|
||||
#define cpu_to_le64(x) (u64)__cpu_to_le64((u64)(x))
|
||||
#define cpu_to_le16(x) (u16)__cpu_to_le16((u16)(x))
|
||||
#define cpu_to_le32(x) (u32)__cpu_to_le32((u32)(x))
|
||||
#define cpu_to_le64(x) (u64)__cpu_to_le64((u64)(x))
|
||||
|
||||
#define cpu_to_le16p(x) (u16)__cpu_to_le16(*(u16*)(x))
|
||||
#define cpu_to_le32p(x) (u32)__cpu_to_le32(*(u32*)(x))
|
||||
#define cpu_to_le64p(x) (u64)__cpu_to_le64(*(u64*)(x))
|
||||
#define cpu_to_le16p(x) (u16)__cpu_to_le16(*(u16*)(x))
|
||||
#define cpu_to_le32p(x) (u32)__cpu_to_le32(*(u32*)(x))
|
||||
#define cpu_to_le64p(x) (u64)__cpu_to_le64(*(u64*)(x))
|
||||
|
||||
/* Signed from CPU to LE conversion. */
|
||||
|
||||
#define cpu_to_sle16(x) (s16)__cpu_to_le16((s16)(x))
|
||||
#define cpu_to_sle32(x) (s32)__cpu_to_le32((s32)(x))
|
||||
#define cpu_to_sle64(x) (s64)__cpu_to_le64((s64)(x))
|
||||
#define cpu_to_sle16(x) (s16)__cpu_to_le16((s16)(x))
|
||||
#define cpu_to_sle32(x) (s32)__cpu_to_le32((s32)(x))
|
||||
#define cpu_to_sle64(x) (s64)__cpu_to_le64((s64)(x))
|
||||
|
||||
#define cpu_to_sle16p(x) (s16)__cpu_to_le16(*(s16*)(x))
|
||||
#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x))
|
||||
#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x))
|
||||
#define cpu_to_sle16p(x) (s16)__cpu_to_le16(*(s16*)(x))
|
||||
#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x))
|
||||
#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x))
|
||||
|
||||
/* Constant endianness conversion defines. */
|
||||
|
||||
#define const_le16_to_cpu(x) __constant_le16_to_cpu(x)
|
||||
#define const_le32_to_cpu(x) __constant_le32_to_cpu(x)
|
||||
#define const_le64_to_cpu(x) __constant_le64_to_cpu(x)
|
||||
#define const_le16_to_cpu(x) __constant_le16_to_cpu(x)
|
||||
#define const_le32_to_cpu(x) __constant_le32_to_cpu(x)
|
||||
#define const_le64_to_cpu(x) __constant_le64_to_cpu(x)
|
||||
|
||||
#define const_cpu_to_le16(x) __constant_cpu_to_le16(x)
|
||||
#define const_cpu_to_le32(x) __constant_cpu_to_le32(x)
|
||||
#define const_cpu_to_le64(x) __constant_cpu_to_le64(x)
|
||||
#define const_cpu_to_le16(x) __constant_cpu_to_le16(x)
|
||||
#define const_cpu_to_le32(x) __constant_cpu_to_le32(x)
|
||||
#define const_cpu_to_le64(x) __constant_cpu_to_le64(x)
|
||||
|
||||
#endif /* defined _NTFS_ENDIANS_H */
|
||||
|
@ -66,83 +66,93 @@
|
||||
#define DEV_FD(dev) ((gekko_fd *)dev->d_private)
|
||||
|
||||
/* Prototypes */
|
||||
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf);
|
||||
static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer);
|
||||
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf);
|
||||
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
static s64 ntfs_device_gekko_io_readbytes( struct ntfs_device *dev, s64 offset, s64 count, void *buf );
|
||||
static bool ntfs_device_gekko_io_readsectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer );
|
||||
static s64 ntfs_device_gekko_io_writebytes( struct ntfs_device *dev, s64 offset, s64 count, const void *buf );
|
||||
static bool ntfs_device_gekko_io_writesectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer );
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
static int ntfs_device_gekko_io_open( struct ntfs_device *dev, int flags )
|
||||
{
|
||||
ntfs_log_trace("dev %p, flags %i\n", dev, flags);
|
||||
ntfs_log_trace( "dev %p, flags %i\n", dev, flags );
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Start the device interface and ensure that it is inserted
|
||||
if (!interface->startup()) {
|
||||
ntfs_log_perror("device failed to start\n");
|
||||
if ( !interface->startup() )
|
||||
{
|
||||
ntfs_log_perror( "device failed to start\n" );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (!interface->isInserted()) {
|
||||
ntfs_log_perror("device media is not inserted\n");
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
ntfs_log_perror( "device media is not inserted\n" );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device isn't already open (used by another volume?)
|
||||
if (NDevOpen(dev)) {
|
||||
ntfs_log_perror("device is busy (already open)\n");
|
||||
if ( NDevOpen( dev ) )
|
||||
{
|
||||
ntfs_log_perror( "device is busy (already open)\n" );
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that there is a valid NTFS boot sector at the start of the device
|
||||
NTFS_BOOT_SECTOR boot;
|
||||
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
||||
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
||||
if ( interface->readSectors( fd->startSector, 1, &boot ) )
|
||||
{
|
||||
if ( !ntfs_boot_sector_is_ntfs( &boot ) )
|
||||
{
|
||||
errno = EINVALPART;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ntfs_log_perror("read failure @ sector %d\n", fd->startSector);
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", fd->startSector );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the boot sector
|
||||
fd->hiddenSectors = le32_to_cpu(boot.bpb.hidden_sectors);
|
||||
fd->sectorSize = le16_to_cpu(boot.bpb.bytes_per_sector);
|
||||
fd->sectorCount = sle64_to_cpu(boot.number_of_sectors);
|
||||
fd->hiddenSectors = le32_to_cpu( boot.bpb.hidden_sectors );
|
||||
fd->sectorSize = le16_to_cpu( boot.bpb.bytes_per_sector );
|
||||
fd->sectorCount = sle64_to_cpu( boot.number_of_sectors );
|
||||
fd->pos = 0;
|
||||
fd->len = (fd->sectorCount * fd->sectorSize);
|
||||
fd->ino = le64_to_cpu(boot.volume_serial_number);
|
||||
fd->len = ( fd->sectorCount * fd->sectorSize );
|
||||
fd->ino = le64_to_cpu( boot.volume_serial_number );
|
||||
|
||||
// Mark the device as read-only (if required)
|
||||
if (flags & O_RDONLY) {
|
||||
NDevSetReadOnly(dev);
|
||||
if ( flags & O_RDONLY )
|
||||
{
|
||||
NDevSetReadOnly( dev );
|
||||
}
|
||||
|
||||
// Create the cache
|
||||
fd->cache = _NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize);
|
||||
fd->cache = _NTFS_cache_constructor( fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize );
|
||||
|
||||
// Mark the device as open
|
||||
NDevSetBlock(dev);
|
||||
NDevSetOpen(dev);
|
||||
NDevSetBlock( dev );
|
||||
NDevSetOpen( dev );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -150,43 +160,47 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
static int ntfs_device_gekko_io_close( struct ntfs_device *dev )
|
||||
{
|
||||
ntfs_log_trace("dev %p\n", dev);
|
||||
ntfs_log_trace( "dev %p\n", dev );
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device is actually open
|
||||
if (!NDevOpen(dev)) {
|
||||
ntfs_log_perror("device is not open\n");
|
||||
if ( !NDevOpen( dev ) )
|
||||
{
|
||||
ntfs_log_perror( "device is not open\n" );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Mark the device as closed
|
||||
NDevClearOpen(dev);
|
||||
NDevClearBlock(dev);
|
||||
NDevClearOpen( dev );
|
||||
NDevClearBlock( dev );
|
||||
|
||||
// Flush the device (if dirty and not read-only)
|
||||
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
||||
ntfs_log_debug("device is dirty, will now sync\n");
|
||||
if ( NDevDirty( dev ) && !NDevReadOnly( dev ) )
|
||||
{
|
||||
ntfs_log_debug( "device is dirty, will now sync\n" );
|
||||
|
||||
// ...?
|
||||
|
||||
// Mark the device as clean
|
||||
NDevClearDirty(dev);
|
||||
NDevClearDirty( dev );
|
||||
|
||||
}
|
||||
|
||||
// Flush and destroy the cache (if required)
|
||||
if (fd->cache) {
|
||||
_NTFS_cache_flush(fd->cache);
|
||||
_NTFS_cache_destructor(fd->cache);
|
||||
if ( fd->cache )
|
||||
{
|
||||
_NTFS_cache_flush( fd->cache );
|
||||
_NTFS_cache_destructor( fd->cache );
|
||||
}
|
||||
|
||||
// Shutdown the device interface
|
||||
@ -196,7 +210,7 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
}*/
|
||||
|
||||
// Free the device driver private data
|
||||
ntfs_free(dev->d_private);
|
||||
ntfs_free( dev->d_private );
|
||||
dev->d_private = NULL;
|
||||
|
||||
return 0;
|
||||
@ -205,22 +219,24 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int whence)
|
||||
static s64 ntfs_device_gekko_io_seek( struct ntfs_device *dev, s64 offset, int whence )
|
||||
{
|
||||
ntfs_log_trace("dev %p, offset %Li, whence %i\n", dev, offset, whence);
|
||||
ntfs_log_trace( "dev %p, offset %Li, whence %i\n", dev, offset, whence );
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the current position on the device (in bytes)
|
||||
switch(whence) {
|
||||
case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
|
||||
case SEEK_CUR: fd->pos = MIN(MAX(fd->pos + offset, 0), fd->len); break;
|
||||
case SEEK_END: fd->pos = MIN(MAX(fd->len + offset, 0), fd->len); break;
|
||||
switch ( whence )
|
||||
{
|
||||
case SEEK_SET: fd->pos = MIN( MAX( offset, 0 ), fd->len ); break;
|
||||
case SEEK_CUR: fd->pos = MIN( MAX( fd->pos + offset, 0 ), fd->len ); break;
|
||||
case SEEK_END: fd->pos = MIN( MAX( fd->len + offset, 0 ), fd->len ); break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -229,115 +245,123 @@ static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int wh
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_read(struct ntfs_device *dev, void *buf, s64 count)
|
||||
static s64 ntfs_device_gekko_io_read( struct ntfs_device *dev, void *buf, s64 count )
|
||||
{
|
||||
return ntfs_device_gekko_io_readbytes(dev, DEV_FD(dev)->pos, count, buf);
|
||||
return ntfs_device_gekko_io_readbytes( dev, DEV_FD( dev )->pos, count, buf );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_write(struct ntfs_device *dev, const void *buf, s64 count)
|
||||
static s64 ntfs_device_gekko_io_write( struct ntfs_device *dev, const void *buf, s64 count )
|
||||
{
|
||||
return ntfs_device_gekko_io_writebytes(dev, DEV_FD(dev)->pos, count, buf);
|
||||
return ntfs_device_gekko_io_writebytes( dev, DEV_FD( dev )->pos, count, buf );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_pread(struct ntfs_device *dev, void *buf, s64 count, s64 offset)
|
||||
static s64 ntfs_device_gekko_io_pread( struct ntfs_device *dev, void *buf, s64 count, s64 offset )
|
||||
{
|
||||
return ntfs_device_gekko_io_readbytes(dev, offset, count, buf);
|
||||
return ntfs_device_gekko_io_readbytes( dev, offset, count, buf );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_pwrite(struct ntfs_device *dev, const void *buf, s64 count, s64 offset)
|
||||
static s64 ntfs_device_gekko_io_pwrite( struct ntfs_device *dev, const void *buf, s64 count, s64 offset )
|
||||
{
|
||||
return ntfs_device_gekko_io_writebytes(dev, offset, count, buf);
|
||||
return ntfs_device_gekko_io_writebytes( dev, offset, count, buf );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf)
|
||||
static s64 ntfs_device_gekko_io_readbytes( struct ntfs_device *dev, s64 offset, s64 count, void *buf )
|
||||
{
|
||||
ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
|
||||
ntfs_log_trace( "dev %p, offset %Li, count %Li\n", dev, offset, count );
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(offset < 0)
|
||||
if ( offset < 0 )
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!count)
|
||||
if ( !count )
|
||||
return 0;
|
||||
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
sec_t sec_start = ( sec_t ) fd->startSector;
|
||||
sec_t sec_count = 1;
|
||||
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
||||
u32 buffer_offset = ( u32 ) ( offset % fd->sectorSize );
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this read
|
||||
if (offset > 0) {
|
||||
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||
if ( offset > 0 )
|
||||
{
|
||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
if (buffer_offset+count > fd->sectorSize) {
|
||||
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize);
|
||||
if ( buffer_offset + count > fd->sectorSize )
|
||||
{
|
||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
|
||||
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
||||
|
||||
if((buffer_offset == 0) && (count % fd->sectorSize == 0)) {
|
||||
if ( ( buffer_offset == 0 ) && ( count % fd->sectorSize == 0 ) )
|
||||
{
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
||||
ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_log_trace( "direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buf ) )
|
||||
{
|
||||
ntfs_log_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Else read into a buffer and copy over only what was requested
|
||||
// Else read into a buffer and copy over only what was requested
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
|
||||
// Allocate a buffer to hold the read data
|
||||
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize );
|
||||
if ( !buffer )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
|
||||
ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_free(buffer);
|
||||
ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_log_trace( "count: %d sec_count:%d fd->sectorSize: %d )\n", ( u32 )count, ( u32 )sec_count, ( u32 )fd->sectorSize );
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy what was requested to the destination buffer
|
||||
memcpy(buf, buffer + buffer_offset, count);
|
||||
ntfs_free(buffer);
|
||||
memcpy( buf, buffer + buffer_offset, count );
|
||||
ntfs_free( buffer );
|
||||
|
||||
}
|
||||
|
||||
@ -347,146 +371,159 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf)
|
||||
static s64 ntfs_device_gekko_io_writebytes( struct ntfs_device *dev, s64 offset, s64 count, const void *buf )
|
||||
{
|
||||
ntfs_log_trace("dev %p, offset %lli, count %lli\n", dev, offset, count);
|
||||
ntfs_log_trace( "dev %p, offset %lli, count %lli\n", dev, offset, count );
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if ( !interface )
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(count < 0 || offset < 0) {
|
||||
if ( count < 0 || offset < 0 )
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(count == 0)
|
||||
if ( count == 0 )
|
||||
return 0;
|
||||
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
sec_t sec_start = ( sec_t ) fd->startSector;
|
||||
sec_t sec_count = 1;
|
||||
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
||||
u32 buffer_offset = ( u32 ) ( offset % fd->sectorSize );
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this write
|
||||
if (offset > 0) {
|
||||
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||
if ( offset > 0 )
|
||||
{
|
||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
if ((buffer_offset+count) > fd->sectorSize) {
|
||||
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize);
|
||||
if ( ( buffer_offset + count ) > fd->sectorSize )
|
||||
{
|
||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||
}
|
||||
|
||||
// If this write happens to be on the sector boundaries then do the write straight to disc
|
||||
if((buffer_offset == 0) && (count % fd->sectorSize == 0))
|
||||
if ( ( buffer_offset == 0 ) && ( count % fd->sectorSize == 0 ) )
|
||||
{
|
||||
// Write to the device
|
||||
ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
|
||||
ntfs_log_perror("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_log_trace( "direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buf ) )
|
||||
{
|
||||
ntfs_log_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
// Else write from a buffer aligned to the sector boundaries
|
||||
// Else write from a buffer aligned to the sector boundaries
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocate a buffer to hold the write data
|
||||
buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize );
|
||||
if ( !buffer )
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
// Read the first and last sectors of the buffer from disc (if required)
|
||||
// NOTE: This is done because the data does not line up with the sector boundaries,
|
||||
// we just read in the buffer edges where the data overlaps with the rest of the disc
|
||||
if(buffer_offset != 0)
|
||||
if ( buffer_offset != 0 )
|
||||
{
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
||||
ntfs_log_perror("read failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, 1, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if((buffer_offset+count) % fd->sectorSize != 0)
|
||||
if ( ( buffer_offset + count ) % fd->sectorSize != 0 )
|
||||
{
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) {
|
||||
ntfs_log_perror("read failure @ sector %d\n", sec_start + sec_count - 1);
|
||||
ntfs_free(buffer);
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start + sec_count - 1, 1, buffer + ( ( sec_count - 1 ) * fd->sectorSize ) ) )
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the data into the write buffer
|
||||
memcpy(buffer + buffer_offset, buf, count);
|
||||
memcpy( buffer + buffer_offset, buf, count );
|
||||
|
||||
// Write to the device
|
||||
ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
||||
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start );
|
||||
ntfs_free( buffer );
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Free the buffer
|
||||
ntfs_free(buffer);
|
||||
ntfs_free( buffer );
|
||||
}
|
||||
|
||||
// Mark the device as dirty (if we actually wrote anything)
|
||||
NDevSetDirty(dev);
|
||||
NDevSetDirty( dev );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer)
|
||||
static bool ntfs_device_gekko_io_readsectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer )
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
// Read the sectors from disc (or cache, if enabled)
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
||||
if ( fd->cache )
|
||||
return _NTFS_cache_readSectors( fd->cache, sector, numSectors, buffer );
|
||||
else
|
||||
return fd->interface->readSectors(sector, numSectors, buffer);
|
||||
return fd->interface->readSectors( sector, numSectors, buffer );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
static bool ntfs_device_gekko_io_writesectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the sectors to disc (or cache, if enabled)
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
||||
if ( fd->cache )
|
||||
return _NTFS_cache_writeSectors( fd->cache, sector, numSectors, buffer );
|
||||
else
|
||||
return fd->interface->writeSectors(sector, numSectors, buffer);
|
||||
return fd->interface->writeSectors( sector, numSectors, buffer );
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -494,23 +531,26 @@ static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sec
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
static int ntfs_device_gekko_io_sync( struct ntfs_device *dev )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
ntfs_log_trace("dev %p\n", dev);
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
ntfs_log_trace( "dev %p\n", dev );
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Mark the device as clean
|
||||
NDevClearDirty(dev);
|
||||
NDevClearDirty( dev );
|
||||
|
||||
// Flush any sectors in the disc cache (if required)
|
||||
if (fd->cache) {
|
||||
if (!_NTFS_cache_flush(fd->cache)) {
|
||||
if ( fd->cache )
|
||||
{
|
||||
if ( !_NTFS_cache_flush( fd->cache ) )
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
@ -522,28 +562,29 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
static int ntfs_device_gekko_io_stat( struct ntfs_device *dev, struct stat *buf )
|
||||
{
|
||||
ntfs_log_trace("dev %p, buf %p\n", dev, buf);
|
||||
ntfs_log_trace( "dev %p, buf %p\n", dev, buf );
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!buf)
|
||||
if ( !buf )
|
||||
return 0;
|
||||
|
||||
// Build the device mode
|
||||
mode_t mode = (S_IFBLK) |
|
||||
(S_IRUSR | S_IRGRP | S_IROTH) |
|
||||
((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
||||
mode_t mode = ( S_IFBLK ) |
|
||||
( S_IRUSR | S_IRGRP | S_IROTH ) |
|
||||
( ( !NDevReadOnly( dev ) ) ? ( S_IWUSR | S_IWGRP | S_IWOTH ) : 0 );
|
||||
|
||||
// Zero out the stat buffer
|
||||
memset(buf, 0, sizeof(struct stat));
|
||||
memset( buf, 0, sizeof( struct stat ) );
|
||||
|
||||
// Build the device stats
|
||||
buf->st_dev = fd->interface->ioType;
|
||||
@ -559,71 +600,79 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void *argp)
|
||||
static int ntfs_device_gekko_io_ioctl( struct ntfs_device *dev, int request, void *argp )
|
||||
{
|
||||
ntfs_log_trace("dev %p, request %i, argp %p\n", dev, request, argp);
|
||||
ntfs_log_trace( "dev %p, request %i, argp %p\n", dev, request, argp );
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Figure out which i/o control was requested
|
||||
switch (request) {
|
||||
switch ( request )
|
||||
{
|
||||
|
||||
// Get block device size (sectors)
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE: {
|
||||
*(u32*)argp = fd->sectorCount;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Get block device size (sectors)
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE:
|
||||
{
|
||||
*( u32* )argp = fd->sectorCount;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64: {
|
||||
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64:
|
||||
{
|
||||
*( u64* )argp = ( fd->sectorCount * fd->sectorSize );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO: {
|
||||
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
||||
geo->sectors = 0;
|
||||
geo->heads = 0;
|
||||
geo->cylinders = 0;
|
||||
geo->start = fd->hiddenSectors;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO:
|
||||
{
|
||||
struct hd_geometry *geo = ( struct hd_geometry* )argp;
|
||||
geo->sectors = 0;
|
||||
geo->heads = 0;
|
||||
geo->cylinders = 0;
|
||||
geo->start = fd->hiddenSectors;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET: {
|
||||
*(int*)argp = fd->sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET:
|
||||
{
|
||||
*( int* )argp = fd->sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET: {
|
||||
int sectorSize = *(int*)argp;
|
||||
fd->sectorSize = sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET:
|
||||
{
|
||||
int sectorSize = *( int* )argp;
|
||||
fd->sectorSize = sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unimplemented ioctrl
|
||||
default: {
|
||||
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
// Unimplemented ioctrl
|
||||
default:
|
||||
{
|
||||
ntfs_log_perror( "Unimplemented ioctrl %i\n", request );
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -633,7 +682,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
/**
|
||||
* Device operations for working with gekko style devices and files.
|
||||
*/
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops = {
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops =
|
||||
{
|
||||
.open = ntfs_device_gekko_io_open,
|
||||
.close = ntfs_device_gekko_io_close,
|
||||
.seek = ntfs_device_gekko_io_seek,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user