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
|
||||
|
@ -34,24 +34,24 @@ using namespace std;
|
||||
* @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)
|
||||
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)
|
||||
int bt = mbstowcs( strWChar, strChar, strlen( strChar ) );
|
||||
if ( bt > 0 )
|
||||
{
|
||||
strWChar[bt] = 0;
|
||||
return strWChar;
|
||||
}
|
||||
|
||||
wchar_t *tempDest = strWChar;
|
||||
while((*tempDest++ = *strChar++));
|
||||
while ( ( *tempDest++ = *strChar++ ) );
|
||||
|
||||
return strWChar;
|
||||
}
|
||||
@ -59,15 +59,15 @@ wchar_t* charToWideChar(const char* strChar)
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,8 +76,8 @@ FreeTypeGX::FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize)
|
||||
FreeTypeGX::~FreeTypeGX()
|
||||
{
|
||||
unloadFont();
|
||||
FT_Done_Face(ftFace);
|
||||
FT_Done_FreeType(ftLibrary);
|
||||
FT_Done_Face( ftFace );
|
||||
FT_Done_FreeType( ftLibrary );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,12 +89,12 @@ FreeTypeGX::~FreeTypeGX()
|
||||
*
|
||||
* @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);
|
||||
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,16 +104,16 @@ void FreeTypeGX::setVertexFormat(uint8_t vertexInd)
|
||||
*/
|
||||
void FreeTypeGX::unloadFont()
|
||||
{
|
||||
if(this->fontData.size() == 0)
|
||||
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 ( itr = fontData.begin(); itr != fontData.end(); itr++ )
|
||||
{
|
||||
for(itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)
|
||||
free(itr2->second.glyphDataTexture);
|
||||
for ( itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++ )
|
||||
free( itr2->second.glyphDataTexture );
|
||||
|
||||
itr->second.clear();
|
||||
}
|
||||
@ -131,17 +131,17 @@ void FreeTypeGX::unloadFont()
|
||||
* @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;
|
||||
}
|
||||
@ -150,43 +150,43 @@ ftgxCharData * FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize)
|
||||
FT_UInt gIndex;
|
||||
uint16_t textureWidth = 0, textureHeight = 0;
|
||||
|
||||
if(ftPointSize != pixelSize)
|
||||
if ( ftPointSize != pixelSize )
|
||||
{
|
||||
ftPointSize = pixelSize;
|
||||
FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize);
|
||||
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)
|
||||
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)
|
||||
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].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];
|
||||
}
|
||||
@ -200,7 +200,7 @@ 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;
|
||||
@ -208,11 +208,11 @@ uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize)
|
||||
FT_ULong charCode = FT_Get_First_Char( ftFace, &gIndex );
|
||||
while ( gIndex != 0 )
|
||||
{
|
||||
if(cacheGlyphData(charCode, pixelSize) != NULL)
|
||||
if ( cacheGlyphData( charCode, pixelSize ) != NULL )
|
||||
++i;
|
||||
charCode = FT_Get_Next_Char( ftFace, charCode, &gIndex );
|
||||
}
|
||||
return (uint16_t)(i);
|
||||
return ( uint16_t )( i );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -227,24 +227,24 @@ uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize)
|
||||
*
|
||||
* 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;
|
||||
uint8_t *src = ( uint8_t * )bmp->buffer;
|
||||
uint32_t offset;
|
||||
|
||||
for (int imagePosY = 0; imagePosY < bmp->rows; ++imagePosY)
|
||||
for ( int imagePosY = 0; imagePosY < bmp->rows; ++imagePosY )
|
||||
{
|
||||
for (int imagePosX = 0; imagePosX < bmp->width; ++imagePosX)
|
||||
for ( int imagePosX = 0; imagePosX < bmp->width; ++imagePosX )
|
||||
{
|
||||
offset = ((((imagePosY >> 2) * (charData->textureWidth >> 2) + (imagePosX >> 2)) << 5) + ((imagePosY & 3) << 2) + (imagePosX & 3)) << 1;
|
||||
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;
|
||||
@ -252,7 +252,7 @@ void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData)
|
||||
++src;
|
||||
}
|
||||
}
|
||||
DCFlushRange(glyphData, length);
|
||||
DCFlushRange( glyphData, length );
|
||||
|
||||
charData->glyphDataTexture = glyphData;
|
||||
}
|
||||
@ -265,13 +265,13 @@ void FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData)
|
||||
* @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)
|
||||
if ( format & FTGX_JUSTIFY_LEFT )
|
||||
return 0;
|
||||
else if (format & FTGX_JUSTIFY_CENTER)
|
||||
return -(width >> 1);
|
||||
else if (format & FTGX_JUSTIFY_RIGHT)
|
||||
else if ( format & FTGX_JUSTIFY_CENTER )
|
||||
return -( width >> 1 );
|
||||
else if ( format & FTGX_JUSTIFY_RIGHT )
|
||||
return -width;
|
||||
return 0;
|
||||
}
|
||||
@ -284,20 +284,20 @@ int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format)
|
||||
* @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)
|
||||
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;
|
||||
return ( itrAlign->second.ascender + itrAlign->second.descender + 1 ) >> 1;
|
||||
|
||||
case FTGX_ALIGN_BOTTOM:
|
||||
return itrAlign->second.descender;
|
||||
@ -309,7 +309,7 @@ int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize)
|
||||
return itrAlign->second.max;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_MIDDLE:
|
||||
return (itrAlign->second.max + itrAlign->second.min + 1) >> 1;
|
||||
return ( itrAlign->second.max + itrAlign->second.min + 1 ) >> 1;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_BOTTOM:
|
||||
return itrAlign->second.min;
|
||||
@ -330,45 +330,45 @@ int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize)
|
||||
* @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 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)
|
||||
if ( textStyle & FTGX_JUSTIFY_MASK )
|
||||
{
|
||||
x_offset = getStyleOffsetWidth(fullTextWidth, textStyle);
|
||||
x_offset = getStyleOffsetWidth( fullTextWidth, textStyle );
|
||||
}
|
||||
if(textStyle & FTGX_ALIGN_MASK)
|
||||
if ( textStyle & FTGX_ALIGN_MASK )
|
||||
{
|
||||
y_offset = getStyleOffsetHeight(textStyle, pixelSize);
|
||||
y_offset = getStyleOffsetHeight( textStyle, pixelSize );
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (text[i])
|
||||
while ( text[i] )
|
||||
{
|
||||
if(widthLimit > 0 && (x_pos-x) > widthLimit)
|
||||
if ( widthLimit > 0 && ( x_pos - x ) > widthLimit )
|
||||
break;
|
||||
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
ftgxCharData* glyphData = cacheGlyphData( text[i], pixelSize );
|
||||
|
||||
if (glyphData != NULL)
|
||||
if ( glyphData != NULL )
|
||||
{
|
||||
if (ftKerningEnabled && i > 0)
|
||||
if ( ftKerningEnabled && i > 0 )
|
||||
{
|
||||
FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
|
||||
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;
|
||||
@ -376,24 +376,24 @@ uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, int16_t z, const wchar_t *te
|
||||
++i;
|
||||
}
|
||||
|
||||
if(textStyle & FTGX_STYLE_MASK)
|
||||
if ( textStyle & FTGX_STYLE_MASK )
|
||||
{
|
||||
getOffset(text, pixelSize, widthLimit);
|
||||
drawTextFeature(x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle, color);
|
||||
getOffset( text, pixelSize, widthLimit );
|
||||
drawTextFeature( x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle, color );
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -405,24 +405,24 @@ void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelS
|
||||
* @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;
|
||||
|
||||
int i = 0;
|
||||
while (text[i])
|
||||
while ( text[i] )
|
||||
{
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
ftgxCharData* glyphData = cacheGlyphData( text[i], pixelSize );
|
||||
|
||||
if (glyphData != NULL)
|
||||
if ( glyphData != NULL )
|
||||
{
|
||||
if (ftKerningEnabled && (i > 0))
|
||||
if ( ftKerningEnabled && ( i > 0 ) )
|
||||
{
|
||||
FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
|
||||
FT_Get_Kerning( ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
|
||||
strWidth += pairDelta.x >> 6;
|
||||
}
|
||||
|
||||
@ -436,17 +436,17 @@ uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize)
|
||||
/**
|
||||
* 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;
|
||||
@ -464,9 +464,9 @@ uint16_t FreeTypeGX::getCharWidth(const wchar_t wChar, int16_t pixelSize, const
|
||||
* @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;
|
||||
}
|
||||
@ -481,9 +481,9 @@ uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize)
|
||||
* @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;
|
||||
@ -491,14 +491,14 @@ void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widt
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (text[i])
|
||||
while ( text[i] )
|
||||
{
|
||||
if(widthLimit > 0 && currWidth >= widthLimit)
|
||||
if ( widthLimit > 0 && currWidth >= widthLimit )
|
||||
break;
|
||||
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
ftgxCharData* glyphData = cacheGlyphData( text[i], pixelSize );
|
||||
|
||||
if(glyphData != NULL)
|
||||
if ( glyphData != NULL )
|
||||
{
|
||||
strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
|
||||
strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
|
||||
@ -508,14 +508,14 @@ void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widt
|
||||
++i;
|
||||
}
|
||||
|
||||
if(ftPointSize != pixelSize)
|
||||
if ( ftPointSize != pixelSize )
|
||||
{
|
||||
ftPointSize = pixelSize;
|
||||
FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize);
|
||||
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].ascender = ftFace->size->metrics.ascender >> 6;
|
||||
ftgxAlign[pixelSize].descender = ftFace->size->metrics.descender >> 6;
|
||||
ftgxAlign[pixelSize].max = strMax;
|
||||
ftgxAlign[pixelSize].min = strMin;
|
||||
}
|
||||
@ -532,34 +532,34 @@ void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widt
|
||||
* @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_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_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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -573,25 +573,25 @@ void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 te
|
||||
* @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_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,7 +37,8 @@
|
||||
*
|
||||
* Font face character glyph relevant data structure.
|
||||
*/
|
||||
typedef struct ftgxCharData_ {
|
||||
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. */
|
||||
@ -56,7 +57,8 @@ typedef struct ftgxCharData_ {
|
||||
*
|
||||
* Offset structure which hold both a maximum and minimum value.
|
||||
*/
|
||||
typedef struct ftgxDataOffset_ {
|
||||
typedef struct ftgxDataOffset_
|
||||
{
|
||||
int16_t ascender; /**< Maximum data offset. */
|
||||
int16_t descender; /**< Minimum data offset. */
|
||||
int16_t max; /**< Maximum data offset. */
|
||||
@ -87,9 +89,9 @@ typedef struct ftgxDataOffset_ ftgxDataOffset;
|
||||
#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.
|
||||
@ -111,32 +113,32 @@ class FreeTypeGX
|
||||
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);
|
||||
ftgxCharData *cacheGlyphData( wchar_t charCode, int16_t pixelSize );
|
||||
uint16_t cacheGlyphDataComplete( int16_t pixelSize );
|
||||
void loadGlyphData( FT_Bitmap *bmp, ftgxCharData *charData );
|
||||
|
||||
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( 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;
|
||||
}
|
||||
|
||||
|
@ -42,12 +42,12 @@ class ZipFile
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
ZipFile(const char *filepath);
|
||||
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);
|
||||
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,24 +111,24 @@
|
||||
*/
|
||||
|
||||
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,
|
||||
@ -148,7 +148,7 @@ static const uint32_t T[4][16] =
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 },
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
@ -178,7 +178,7 @@ 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.
|
||||
@ -210,7 +210,7 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
{
|
||||
int round;
|
||||
int i, j;
|
||||
uint8_t s;
|
||||
@ -220,19 +220,19 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
|
||||
/* Store the current ABCD values for later re-use.
|
||||
*/
|
||||
for( i = 0; i < 4; i++ )
|
||||
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++ )
|
||||
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.
|
||||
@ -249,21 +249,21 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
* (My implementation appears to be a poor compromise between speed, size,
|
||||
* and clarity. Ugh. [crh])
|
||||
*/
|
||||
for( round = 0; round < 4; round++ )
|
||||
for ( round = 0; round < 4; round++ )
|
||||
{
|
||||
for( i = 0; i < 16; i++ )
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
j = (4 - (i % 4)) & 0x3; /* <j> handles the rotation of ABCD. */
|
||||
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. */
|
||||
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 )
|
||||
switch ( round )
|
||||
{
|
||||
case 0:
|
||||
/* round 1 */
|
||||
@ -283,17 +283,17 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
break;
|
||||
}
|
||||
a = 0xFFFFFFFF & ( ABCD[j] + a + T[round][i] );
|
||||
ABCD[j] = b + (0xFFFFFFFF & (( a << s ) | ( a >> (32 - s) )));
|
||||
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++ )
|
||||
for ( i = 0; i < 4; i++ )
|
||||
ABCD[i] = 0xFFFFFFFF & ( ABCD[i] + KeepABCD[i] );
|
||||
|
||||
} /* Permute */
|
||||
} /* Permute */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
@ -301,7 +301,7 @@ 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.
|
||||
@ -328,7 +328,7 @@ auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx )
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
{
|
||||
ctx->len = 0;
|
||||
ctx->b_used = 0;
|
||||
|
||||
@ -345,13 +345,13 @@ auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx )
|
||||
/* here are provided as 32-bit values in C language format, */
|
||||
/* so they are endian-agnostic. */
|
||||
return( ctx );
|
||||
} /* auth_md5InitCtx */
|
||||
} /* 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
|
||||
@ -366,21 +366,21 @@ auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Add the new block's length to the total length.
|
||||
*/
|
||||
ctx->len += (uint32_t)len;
|
||||
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++ )
|
||||
for ( i = 0; i < len; i++ )
|
||||
{
|
||||
ctx->block[ ctx->b_used ] = src[i];
|
||||
(ctx->b_used)++;
|
||||
if( 64 == ctx->b_used )
|
||||
( ctx->b_used )++;
|
||||
if ( 64 == ctx->b_used )
|
||||
{
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
ctx->b_used = 0;
|
||||
@ -390,11 +390,11 @@ auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
/* Return the updated context.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5SumCtx */
|
||||
} /* 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
|
||||
@ -412,7 +412,7 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
{
|
||||
int i;
|
||||
uint32_t l;
|
||||
|
||||
@ -422,20 +422,20 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
||||
* free byte in the context block.
|
||||
*/
|
||||
ctx->block[ctx->b_used] = 0x80;
|
||||
(ctx->b_used)++;
|
||||
( ctx->b_used )++;
|
||||
|
||||
/* Zero out any remaining free bytes in the context block.
|
||||
*/
|
||||
for( i = ctx->b_used; i < 64; i++ )
|
||||
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 )
|
||||
if ( 56 < ctx->b_used )
|
||||
{
|
||||
Permute( ctx->ABCD, ctx->block );
|
||||
for( i = 0; i < 64; i++ )
|
||||
for ( i = 0; i < 64; i++ )
|
||||
ctx->block[i] = 0;
|
||||
}
|
||||
|
||||
@ -445,14 +445,14 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
||||
* any MAXINT numeric overflow issues.
|
||||
*/
|
||||
l = ctx->len << 3;
|
||||
for( i = 0; i < 4; i++ )
|
||||
for ( i = 0; i < 4; i++ )
|
||||
ctx->block[56+i] |= GetLongByte( l, i );
|
||||
ctx->block[60] = ((GetLongByte( ctx->len, 3 ) & 0xE0) >> 5); /* See Above! */
|
||||
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++ )
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
dst[ 0+i] = GetLongByte( ctx->ABCD[0], i );
|
||||
dst[ 4+i] = GetLongByte( ctx->ABCD[1], i );
|
||||
@ -464,11 +464,11 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
||||
* This is done for compatibility with the other auth_md5*Ctx() functions.
|
||||
*/
|
||||
return( ctx );
|
||||
} /* auth_md5CloseCtx */
|
||||
} /* auth_md5CloseCtx */
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
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.
|
||||
@ -500,20 +500,20 @@ unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
{
|
||||
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 */
|
||||
} /* auth_md5Sum */
|
||||
|
||||
|
||||
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
/* ------------------------------------------------------------------------ **
|
||||
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.
|
||||
@ -543,62 +543,65 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
{
|
||||
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){
|
||||
if ( buffer == NULL )
|
||||
{
|
||||
//no memory
|
||||
fclose(file);
|
||||
fclose( file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
read = fread(buffer, 1, blksize, file);
|
||||
(void)auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
|
||||
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,7 +5,7 @@
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/* ========================================================================== **
|
||||
/* ========================================================================== **
|
||||
*
|
||||
* MD5.h
|
||||
*
|
||||
@ -81,11 +81,11 @@ extern "C"
|
||||
*
|
||||
* ========================================================================== **
|
||||
*/
|
||||
/* -------------------------------------------------------------------------- **
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Typedefs:
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
typedef struct
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int ABCD[4];
|
||||
@ -94,11 +94,11 @@ typedef struct
|
||||
} auth_md5Ctx;
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions:
|
||||
*/
|
||||
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Initialize an MD5 context.
|
||||
*
|
||||
@ -128,7 +128,7 @@ auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
||||
*/
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
const unsigned char *src,
|
||||
const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
@ -148,7 +148,7 @@ auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
*/
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst );
|
||||
auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
*
|
||||
@ -169,7 +169,7 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst );
|
||||
*/
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len );
|
||||
unsigned char * MD5( unsigned char * hash, const unsigned char *src, const int len );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
@ -203,7 +203,7 @@ unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int le
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src);
|
||||
unsigned char * MD5fromFile( unsigned char *dst, const char *src );
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
*
|
||||
@ -235,10 +235,10 @@ unsigned char * MD5fromFile(unsigned char *dst, const char *src);
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
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,105 +22,106 @@
|
||||
#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);
|
||||
Disc_SetUSB( discid );
|
||||
|
||||
Disc_Open();
|
||||
|
||||
u64 offset;
|
||||
s32 ret;
|
||||
|
||||
ret = __Disc_FindPartition(&offset);
|
||||
if (ret < 0)
|
||||
ret = __Disc_FindPartition( &offset );
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
|
||||
ret = WDVD_OpenPartition(offset);
|
||||
ret = WDVD_OpenPartition( offset );
|
||||
|
||||
if (ret < 0) {
|
||||
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);
|
||||
u32 *buffer = memalign( 32, 0x20 );
|
||||
|
||||
if (buffer == NULL)
|
||||
if ( buffer == NULL )
|
||||
{
|
||||
//Out of memory
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read(buffer, 0x20, 0x420);
|
||||
if (ret < 0)
|
||||
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;
|
||||
void *fstbuffer = memalign( 32, buffer[2] * 4 );
|
||||
FST_ENTRY *fst = ( FST_ENTRY * )fstbuffer;
|
||||
|
||||
if (fst == NULL)
|
||||
if ( fst == NULL )
|
||||
{
|
||||
//Out of memory
|
||||
free(buffer);
|
||||
free( buffer );
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read(fstbuffer, buffer[2]*4, buffer[1]*4);
|
||||
if (ret < 0)
|
||||
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;
|
||||
|
||||
for (i=1;i<count;i++)
|
||||
for ( i = 1; i < count; i++ )
|
||||
{
|
||||
if (strstr(fstfiles(fst, i), "opening.bnr") != NULL)
|
||||
if ( strstr( fstfiles( fst, i ), "opening.bnr" ) != NULL )
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
if ( index == 0 )
|
||||
{
|
||||
//opening.bnr not found
|
||||
free(fstbuffer);
|
||||
free( fstbuffer );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Load the .bnr
|
||||
u8 *banner = memalign(32, fst[index].filelen);
|
||||
u8 *banner = memalign( 32, fst[index].filelen );
|
||||
|
||||
if (banner == NULL)
|
||||
if ( banner == NULL )
|
||||
{
|
||||
//Out of memory
|
||||
free(fstbuffer);
|
||||
free( fstbuffer );
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = WDVD_Read((void *)banner, fst[index].filelen, fst[index].fileoffset * 4);
|
||||
if (ret < 0)
|
||||
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)
|
||||
WDVD_SetUSBMode( NULL, 0 );
|
||||
FILE *fp = fopen( dest, "wb" );
|
||||
if ( fp )
|
||||
{
|
||||
fwrite(banner, 1, fst[index].filelen, fp);
|
||||
fclose(fp);
|
||||
fwrite( banner, 1, fst[index].filelen, fp );
|
||||
fclose( fp );
|
||||
}
|
||||
free(fstbuffer);
|
||||
free(banner);
|
||||
free( fstbuffer );
|
||||
free( banner );
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
filecheck = false;
|
||||
fclose(tplfp);
|
||||
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())
|
||||
LOCK( this );
|
||||
if ( !filecheck || !this->IsVisible() )
|
||||
return;
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -12,20 +12,20 @@
|
||||
|
||||
class GuiBanner : public GuiImage
|
||||
{
|
||||
public:
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param tplfilepath Path of the tpl file
|
||||
GuiBanner(const char *tplfilepath);
|
||||
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);
|
||||
GuiBanner( void *mem, u32 len, int w, int h );
|
||||
//!Destructor
|
||||
~GuiBanner();
|
||||
void Draw();
|
||||
protected:
|
||||
protected:
|
||||
void * memory;
|
||||
bool filecheck;
|
||||
u32 tplfilesize;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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,7 +90,8 @@ typedef struct {
|
||||
u8 crypto[0x10];
|
||||
} imet_data_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 imd5_tag; // 0x494D4435 "IMD5";
|
||||
u32 size; // size of the rest of part B, starting from next field.
|
||||
u8 zeroes[8];
|
||||
@ -115,20 +117,20 @@ typedef struct
|
||||
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;
|
||||
size_t written = 0;
|
||||
FILE *out;
|
||||
out = fopen(name, "wb");
|
||||
if(out)
|
||||
out = fopen( name, "wb" );
|
||||
if ( out )
|
||||
{
|
||||
written = fwrite(data, 1, size, out);
|
||||
fclose(out);
|
||||
written = fwrite( data, 1, size, out );
|
||||
fclose( out );
|
||||
}
|
||||
return (written == size) ? 1 : -1;
|
||||
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;
|
||||
@ -143,49 +145,58 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
||||
// Assume this for now and grow when needed
|
||||
unpacked_size = data_size;
|
||||
|
||||
decompressed_data = malloc(unpacked_size);
|
||||
decompressed_data = malloc( unpacked_size );
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
|
||||
out_ptr = decompressed_data;
|
||||
|
||||
while (in_ptr < data_end) {
|
||||
while ( in_ptr < data_end )
|
||||
{
|
||||
int bit;
|
||||
u8 bitmask = *in_ptr;
|
||||
|
||||
in_ptr++;
|
||||
for (bit = 0x80; bit != 0; bit >>= 1) {
|
||||
if (bitmask & bit) {
|
||||
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_length = ( *in_ptr >> 4 ) + 3;
|
||||
rep_offset = *in_ptr & 0x0f;
|
||||
in_ptr++;
|
||||
rep_offset = *in_ptr | (rep_offset << 8);
|
||||
rep_offset = *in_ptr | ( rep_offset << 8 );
|
||||
in_ptr++;
|
||||
if (out_ptr-decompressed_data < rep_offset) {
|
||||
if ( out_ptr - decompressed_data < rep_offset )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ; rep_length > 0; rep_length--) {
|
||||
for ( ; rep_length > 0; rep_length-- )
|
||||
{
|
||||
*out_ptr = out_ptr[-rep_offset-1];
|
||||
out_ptr++;
|
||||
if (out_ptr >= out_end) {
|
||||
if ( out_ptr >= out_end )
|
||||
{
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc(decompressed_data, unpacked_size*2);
|
||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||
out_ptr = decompressed_data + unpacked_size;
|
||||
unpacked_size *= 2;
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just copy byte
|
||||
*out_ptr = *in_ptr;
|
||||
out_ptr++;
|
||||
if (out_ptr >= out_end) {
|
||||
if ( out_ptr >= out_end )
|
||||
{
|
||||
// Need to grow buffer
|
||||
decompressed_data = realloc(decompressed_data, unpacked_size*2);
|
||||
decompressed_data = realloc( decompressed_data, unpacked_size * 2 );
|
||||
out_ptr = decompressed_data + unpacked_size;
|
||||
unpacked_size *= 2;
|
||||
out_end = decompressed_data + unpacked_size;
|
||||
@ -195,52 +206,58 @@ u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
|
||||
}
|
||||
}
|
||||
|
||||
*decompressed_size = (out_ptr - 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;
|
||||
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;
|
||||
|
||||
tag = be32((u8*) &header->imd5_tag);
|
||||
if (tag != 0x494D4435) {
|
||||
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)) {
|
||||
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) {
|
||||
size_in_imd5 = be32( ( u8* ) & header->size );
|
||||
if ( size_in_imd5 != size - 32 )
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
tag = be32((u8*) &header->payload_tag);
|
||||
if (tag == 0x4C5A3737) {
|
||||
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)
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
@ -255,93 +272,103 @@ static int do_U8_archive(FILE *fp)
|
||||
u16 dir_stack[16];
|
||||
int dir_index = 0;
|
||||
|
||||
fread(&header, 1, sizeof header, fp);
|
||||
tag = be32((u8*) &header.tag);
|
||||
if (tag != 0x55AA382D) {
|
||||
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;
|
||||
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++) {
|
||||
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];
|
||||
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) {
|
||||
if ( type == 0x0100 )
|
||||
{
|
||||
// Directory
|
||||
mkdir(name, 0777);
|
||||
chdir(name);
|
||||
mkdir( name, 0777 );
|
||||
chdir( name );
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal file
|
||||
u8 padding[32];
|
||||
|
||||
if (type != 0x0000) {
|
||||
free(string_table);
|
||||
if ( type != 0x0000 )
|
||||
{
|
||||
free( string_table );
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (current_offset < my_data_offset) {
|
||||
if ( current_offset < my_data_offset )
|
||||
{
|
||||
int diff = my_data_offset - current_offset;
|
||||
|
||||
if (diff > 32) {
|
||||
free(string_table);
|
||||
if ( diff > 32 )
|
||||
{
|
||||
free( string_table );
|
||||
return -3;
|
||||
}
|
||||
fread(padding, 1, diff, fp);
|
||||
fread( padding, 1, diff, fp );
|
||||
current_offset += diff;
|
||||
}
|
||||
|
||||
file_data = malloc(size);
|
||||
fread(file_data, 1, size, fp);
|
||||
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);
|
||||
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("..");
|
||||
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
||||
{
|
||||
chdir( ".." );
|
||||
dir_index--;
|
||||
}
|
||||
}
|
||||
free(string_table);
|
||||
free( string_table );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_imet_header(FILE *fp)
|
||||
static void do_imet_header( FILE *fp )
|
||||
{
|
||||
imet_data_t header;
|
||||
|
||||
fread(&header, 1, sizeof header, fp);
|
||||
fread( &header, 1, sizeof header, fp );
|
||||
|
||||
write_file(&header, sizeof(header), "header.imet");
|
||||
write_file( &header, sizeof( header ), "header.imet" );
|
||||
}
|
||||
|
||||
void do_U8_archivebanner(FILE *fp)
|
||||
void do_U8_archivebanner( FILE *fp )
|
||||
{
|
||||
U8_archive_header header;
|
||||
U8_node root_node;
|
||||
@ -355,92 +382,99 @@ void do_U8_archivebanner(FILE *fp)
|
||||
u16 dir_stack[16];
|
||||
int dir_index = 0;
|
||||
|
||||
fread(&header, 1, sizeof header, fp);
|
||||
tag = be32((u8*) &header.tag);
|
||||
if (tag != 0x55AA382D) {
|
||||
fread( &header, 1, sizeof header, fp );
|
||||
tag = be32( ( u8* ) & header.tag );
|
||||
if ( tag != 0x55AA382D )
|
||||
{
|
||||
//printf("No U8 tag");
|
||||
exit(0);
|
||||
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);
|
||||
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 );
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
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];
|
||||
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) {
|
||||
if ( type == 0x0100 )
|
||||
{
|
||||
// Directory
|
||||
mkdir(name, 0777);
|
||||
chdir(name);
|
||||
mkdir( name, 0777 );
|
||||
chdir( name );
|
||||
dir_stack[++dir_index] = size;
|
||||
//printf("%*s%s/\n", dir_index, "", name);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal file
|
||||
|
||||
if (type != 0x0000) {
|
||||
printf("Unknown type");
|
||||
exit(0);
|
||||
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);
|
||||
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("..");
|
||||
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
||||
{
|
||||
chdir( ".." );
|
||||
dir_index--;
|
||||
}
|
||||
}
|
||||
free(string_table);
|
||||
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)
|
||||
FILE *fp = fopen( filepath, "rb" );
|
||||
if ( fp )
|
||||
{
|
||||
subfoldercreate(destpath);
|
||||
chdir(destpath);
|
||||
subfoldercreate( destpath );
|
||||
chdir( destpath );
|
||||
|
||||
do_imet_header(fp);
|
||||
ret = do_U8_archive(fp);
|
||||
do_imet_header( fp );
|
||||
ret = do_U8_archive( fp );
|
||||
|
||||
fclose(fp);
|
||||
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)
|
||||
FILE *fp = fopen( filename, "rb" );;
|
||||
if ( fp )
|
||||
{
|
||||
subfoldercreate(outdir);
|
||||
chdir(outdir);
|
||||
subfoldercreate( outdir );
|
||||
chdir( outdir );
|
||||
|
||||
do_U8_archivebanner(fp);
|
||||
fclose(fp);
|
||||
do_U8_archivebanner( fp );
|
||||
fclose( fp );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -449,81 +483,81 @@ int unpackBin(const char * filename,const char * outdir)
|
||||
#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;
|
||||
if ( !ramdiskMount( "BANNER", NULL ) ) return -1;
|
||||
|
||||
subfoldercreate(TMP_PATH("/"));
|
||||
s32 ret = dump_banner(gameid, TMP_PATH("/opening.bnr"));
|
||||
if (ret != 1)
|
||||
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 = extractbnrfile( TMP_PATH( "/opening.bnr" ), TMP_PATH( "/" ) );
|
||||
if ( ret != 0 )
|
||||
{
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if(what & UNPACK_BANNER_BIN)
|
||||
if ( what & UNPACK_BANNER_BIN )
|
||||
{
|
||||
snprintf(path, sizeof(path),"%sbanner/", outdir);
|
||||
ret = unpackBin(TMP_PATH("/meta/banner.bin"), path);
|
||||
if (ret != 1)
|
||||
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)
|
||||
if ( what & UNPACK_ICON_BIN )
|
||||
{
|
||||
snprintf(path, sizeof(path),"%sicon/", outdir);
|
||||
ret = unpackBin(TMP_PATH("/meta/icon.bin"), path);
|
||||
if (ret != 1)
|
||||
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)
|
||||
if ( what & UNPACK_SOUND_BIN )
|
||||
{
|
||||
snprintf(path, sizeof(path),"%ssound.bin", outdir);
|
||||
FILE *fp = fopen(TMP_PATH("/meta/sound.bin"), "rb");
|
||||
if(fp)
|
||||
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)
|
||||
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)
|
||||
fseek( fp, 0, SEEK_SET );
|
||||
data = ( u8 * )malloc( size );
|
||||
if ( !data )
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
if(fread(data, 1, size, fp) != size)
|
||||
if ( fread( data, 1, size, fp ) != size )
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
ret = write_file(data, size, path);
|
||||
ret = write_file( data, size, path );
|
||||
}
|
||||
error: fclose(fp);
|
||||
error: fclose( fp );
|
||||
}
|
||||
ramdiskUnmount("BANNER");
|
||||
ramdiskUnmount( "BANNER" );
|
||||
error2:
|
||||
if(ret < 0)
|
||||
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);
|
||||
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
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ struct IMD5Header
|
||||
u32 filesize;
|
||||
u8 zeroes[8];
|
||||
u8 crypto[16];
|
||||
} __attribute__((packed));
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct IMETHeader
|
||||
{
|
||||
@ -31,7 +31,7 @@ struct IMETHeader
|
||||
u8 names[7][84];
|
||||
u8 zeroes_2[0x348];
|
||||
u8 crypto[16];
|
||||
} __attribute__((packed));
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct U8Header
|
||||
{
|
||||
@ -40,7 +40,7 @@ struct U8Header
|
||||
u32 headerSize;
|
||||
u32 dataOffset;
|
||||
u8 zeroes[16];
|
||||
} __attribute__((packed));
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct U8Entry
|
||||
{
|
||||
@ -55,59 +55,59 @@ struct U8Entry
|
||||
u32 fileLength;
|
||||
u32 numEntries;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
} __attribute__( ( packed ) );
|
||||
|
||||
struct LZ77Info
|
||||
{
|
||||
u16 length : 4;
|
||||
u16 offset : 12;
|
||||
} __attribute__((packed));
|
||||
} __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)
|
||||
if ( inLength <= 0x8 || *( ( const u32 * )inBuf ) != 0x4C5A3737 /*"LZ77"*/ || inBuf[4] != 0x10 )
|
||||
return NULL;
|
||||
u32 uncSize = le32(((const u32 *)inBuf)[1] << 8);
|
||||
u32 uncSize = le32( ( ( const u32 * )inBuf )[1] << 8 );
|
||||
|
||||
const u8 *inBufEnd = inBuf + inLength;
|
||||
inBuf += 8;
|
||||
buffer = new(std::nothrow) u8[uncSize];
|
||||
if (!buffer)
|
||||
buffer = new( std::nothrow ) u8[uncSize];
|
||||
if ( !buffer )
|
||||
return buffer;
|
||||
|
||||
u8 *bufCur = buffer;
|
||||
u8 *bufEnd = buffer + uncSize;
|
||||
|
||||
while (bufCur < bufEnd && inBuf < inBufEnd)
|
||||
while ( bufCur < bufEnd && inBuf < inBufEnd )
|
||||
{
|
||||
u8 flags = *inBuf;
|
||||
++inBuf;
|
||||
for (int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i)
|
||||
for ( int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i )
|
||||
{
|
||||
if ((flags & 0x80) != 0)
|
||||
if ( ( flags & 0x80 ) != 0 )
|
||||
{
|
||||
const LZ77Info &info = *(const LZ77Info *)inBuf;
|
||||
inBuf += sizeof (LZ77Info);
|
||||
const LZ77Info &info = *( const LZ77Info * )inBuf;
|
||||
inBuf += sizeof ( LZ77Info );
|
||||
int length = info.length + 3;
|
||||
if (bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd)
|
||||
if ( bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd )
|
||||
return buffer;
|
||||
memcpy(bufCur, bufCur - info.offset - 1, length);
|
||||
memcpy( bufCur, bufCur - info.offset - 1, length );
|
||||
bufCur += length;
|
||||
}
|
||||
else
|
||||
@ -123,87 +123,87 @@ static u8 *uncompressLZ77(const u8 *inBuf, u32 inLength, u32 &size)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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 IMETHeader *imetHdr = (IMETHeader *)opening_bnr;
|
||||
const IMETHeader *imetHdr = ( IMETHeader * )opening_bnr;
|
||||
if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ )
|
||||
{
|
||||
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
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);
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
free( opening_bnr );
|
||||
return NULL;
|
||||
}
|
||||
const u8 *sound_bin = ((const u8 *)bnrArcHdr) + fst[i].fileOffset;
|
||||
if ( ((IMD5Header *)sound_bin)->fcc != 0x494D4435 /*"IMD5"*/ )
|
||||
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);
|
||||
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"*/ )
|
||||
if ( *( ( u32* )soundChunk ) == 0x4C5A3737 /*"LZ77"*/ )
|
||||
{
|
||||
u32 uncSize = NULL;
|
||||
u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, uncSize);
|
||||
if (!uncompressed_data)
|
||||
u8 * uncompressed_data = uncompressLZ77( soundChunk, soundChunkSize, uncSize );
|
||||
if ( !uncompressed_data )
|
||||
{
|
||||
// WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK"));
|
||||
free(opening_bnr);
|
||||
free( opening_bnr );
|
||||
return NULL;
|
||||
}
|
||||
if(size) *size=uncSize;
|
||||
free(opening_bnr);
|
||||
if ( size ) *size = uncSize;
|
||||
free( opening_bnr );
|
||||
return uncompressed_data;
|
||||
}
|
||||
u8 *out = new(std::nothrow) u8[soundChunkSize];
|
||||
if(out)
|
||||
u8 *out = new( std::nothrow ) u8[soundChunkSize];
|
||||
if ( out )
|
||||
{
|
||||
memcpy(out, soundChunk, soundChunkSize);
|
||||
if(size) *size=soundChunkSize;
|
||||
memcpy( out, soundChunk, soundChunkSize );
|
||||
if ( size ) *size = soundChunkSize;
|
||||
}
|
||||
free(opening_bnr);
|
||||
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,140 +23,157 @@ extern GuiWindow * mainWindow;
|
||||
/****************************************************************************
|
||||
* CheatMenu
|
||||
***************************************************************************/
|
||||
int CheatMenu(const char * gameID) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
snprintf( txtfilename, sizeof( txtfilename ), "%s%s.txt", Settings.TxtCheatcodespath, gameID );
|
||||
|
||||
GCTCheats c;
|
||||
int check = c.openTxtfile(txtfilename);
|
||||
int check = c.openTxtfile( txtfilename );
|
||||
|
||||
int download =0;
|
||||
int download = 0;
|
||||
|
||||
switch (check) {
|
||||
switch ( check )
|
||||
{
|
||||
case -1:
|
||||
WindowPrompt(tr("Error"),tr("Cheatfile is blank"),tr("OK"));
|
||||
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 = 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)
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
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");
|
||||
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) {
|
||||
if ( createBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
createBtn.ResetState();
|
||||
if (cntcheats > 0) {
|
||||
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) {
|
||||
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);
|
||||
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"));
|
||||
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"));
|
||||
}
|
||||
else WindowPrompt( tr( "Error" ), tr( "Could not create GCT file" ), tr( "OK" ) );
|
||||
}
|
||||
|
||||
if (backBtn.GetState() == STATE_CLICKED) {
|
||||
if ( backBtn.GetState() == STATE_CLICKED )
|
||||
{
|
||||
backBtn.ResetState();
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HaltGui();
|
||||
mainWindow->SetState(STATE_DEFAULT);
|
||||
mainWindow->Remove(&w);
|
||||
mainWindow->SetState( STATE_DEFAULT );
|
||||
mainWindow->Remove( &w );
|
||||
ResumeGui();
|
||||
break;
|
||||
}
|
||||
|
@ -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)
|
||||
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,144 +129,160 @@ 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)
|
||||
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)) {
|
||||
if ( IsCode( str ) )
|
||||
{
|
||||
// remove any garbage (comment) after code
|
||||
while (str.size() > 17) {
|
||||
str.erase(str.length() - 1);
|
||||
while ( str.size() > 17 )
|
||||
{
|
||||
str.erase( str.length() - 1 );
|
||||
}
|
||||
cheatdata.append(str);
|
||||
size_t found=cheatdata.find(' ');
|
||||
cheatdata.replace(found,1,"");
|
||||
} else {
|
||||
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;
|
||||
if ( i == MAXCHEATS ) break;
|
||||
}
|
||||
iCntCheats = i;
|
||||
filestr.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GCTCheats::IsCode(const std::string& str) {
|
||||
if (str[8] == ' ' && str.size() >= 17) {
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,9 @@
|
||||
using namespace std;
|
||||
|
||||
//!Handles Ocarina TXT Cheatfiles
|
||||
class GCTCheats {
|
||||
private:
|
||||
class GCTCheats
|
||||
{
|
||||
private:
|
||||
string sGameID;
|
||||
string sGameTitle;
|
||||
string sCheatName[MAXCHEATS];
|
||||
@ -23,52 +24,52 @@ private:
|
||||
string sCheatComment[MAXCHEATS];
|
||||
int iCntCheats;
|
||||
|
||||
public:
|
||||
public:
|
||||
//!Constructor
|
||||
GCTCheats(void);
|
||||
GCTCheats( void );
|
||||
//!Destructor
|
||||
~GCTCheats(void);
|
||||
~GCTCheats( void );
|
||||
//!Open txt file with cheats
|
||||
//!\param filename name of TXT file
|
||||
//!\return error code
|
||||
int openTxtfile(const char * filename);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
string getGameName( void );
|
||||
//!Gets GameID
|
||||
//!\return GameID
|
||||
string getGameID(void);
|
||||
string getGameID( void );
|
||||
//!Gets cheat data
|
||||
//!\return cheat data
|
||||
string getCheat(int nr);
|
||||
string getCheat( int nr );
|
||||
//!Gets Cheat Name
|
||||
//!\return Cheat Name
|
||||
string getCheatName(int nr);
|
||||
string getCheatName( int nr );
|
||||
//!Gets Cheat Comment
|
||||
//!\return Cheat Comment
|
||||
string getCheatComment(int nr);
|
||||
string getCheatComment( int nr );
|
||||
//!Check if string is a code
|
||||
//!\return true/false
|
||||
bool IsCode(const std::string& s);
|
||||
bool IsCode( const std::string& s );
|
||||
};
|
||||
|
||||
#endif /* _GCT_H */
|
||||
|
@ -44,20 +44,22 @@ 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:/");
|
||||
fatUnmount( "USB:/" );
|
||||
//right now mounts first FAT-partition
|
||||
|
||||
//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)) {
|
||||
if ( !fatMount( "USB", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
||||
{
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":-1");
|
||||
gprintf( ":-1" );
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
@ -66,94 +68,104 @@ int USBDevice_Init() {
|
||||
fat_usb_mount = 1;
|
||||
fat_usb_sec = _FAT_startSector;
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":0");
|
||||
gprintf( ":0" );
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
//try now mount with libogc
|
||||
if (!fatMount("WBFS", &__io_usbstorage2, 0, CACHE, SECTORS)) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
#ifdef DEBUG_FAT
|
||||
gprintf(":-1");
|
||||
gprintf( ":-1" );
|
||||
#endif
|
||||
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;
|
||||
@ -161,11 +173,11 @@ void SDCard_deInit() {
|
||||
|
||||
void ntfsInit();
|
||||
|
||||
s32 MountNTFS(u32 sector)
|
||||
s32 MountNTFS( u32 sector )
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
if (fs_ntfs_mount) return 0;
|
||||
if ( fs_ntfs_mount ) return 0;
|
||||
//printf("mounting NTFS\n");
|
||||
//Wpad_WaitButtons();
|
||||
_FAT_mem_init();
|
||||
@ -175,31 +187,40 @@ s32 MountNTFS(u32 sector)
|
||||
// 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");
|
||||
setlocale( LC_CTYPE, "C-UTF-8" );
|
||||
setlocale( LC_MESSAGES, "C-UTF-8" );
|
||||
|
||||
if (wbfsDev == WBFS_DEVICE_USB) {
|
||||
if ( wbfsDev == WBFS_DEVICE_USB )
|
||||
{
|
||||
/* Initialize WBFS interface */
|
||||
// if (!__io_wiiums.startup()) {
|
||||
ret = __io_usbstorage2.startup();
|
||||
if (!ret) {
|
||||
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) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -210,10 +231,10 @@ s32 MountNTFS(u32 sector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 UnmountNTFS(void)
|
||||
s32 UnmountNTFS( void )
|
||||
{
|
||||
/* Unmount device */
|
||||
ntfsUnmount("NTFS:/", true);
|
||||
ntfsUnmount( "NTFS:/", true );
|
||||
|
||||
fs_ntfs_mount = 0;
|
||||
fs_ntfs_sec = 0;
|
||||
@ -225,17 +246,17 @@ 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,7 +2,8 @@
|
||||
#define _FATMOUNTER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern int fat_sd_mount;
|
||||
@ -14,14 +15,14 @@ extern "C" {
|
||||
|
||||
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;
|
||||
|
@ -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];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap,str);
|
||||
va_start( ap, str );
|
||||
|
||||
vsprintf( astr, str, ap );
|
||||
|
||||
va_end(ap);
|
||||
va_end( ap );
|
||||
|
||||
usb_sendbuffer( 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)
|
||||
u32 geckoattached = usb_isgeckoalive( EXI_CHANNEL_1 );
|
||||
if ( geckoattached )
|
||||
{
|
||||
usb_flush(EXI_CHANNEL_1);
|
||||
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)
|
||||
if ( s < 0x20 )
|
||||
return '.';
|
||||
if(s > 0x7E)
|
||||
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(" ");
|
||||
gprintf( "%04x ", off );
|
||||
for ( i = 0; i < 16; i++ )
|
||||
if ( ( i + off ) >= len )
|
||||
gprintf( " " );
|
||||
else
|
||||
gprintf("%02x ",data[off+i]);
|
||||
gprintf( "%02x ", data[off+i] );
|
||||
|
||||
gprintf(" ");
|
||||
for(i=0; i<16; i++)
|
||||
if((i+off)>=len)
|
||||
gprintf(" ");
|
||||
gprintf( " " );
|
||||
for ( i = 0; i < 16; i++ )
|
||||
if ( ( i + off ) >= len )
|
||||
gprintf( " " );
|
||||
else
|
||||
gprintf("%c",ascii(data[off+i]));
|
||||
gprintf("\n");
|
||||
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, ...);
|
||||
void gprintf( const char *str, ... );
|
||||
bool InitGecko();
|
||||
void hexdump(void *d, int len);
|
||||
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 */
|
||||
|
||||
|
||||
|
@ -17,59 +17,59 @@
|
||||
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,7 +155,7 @@ 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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -255,7 +255,7 @@ static int RunAppbooter()
|
||||
|
||||
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 )
|
||||
{
|
||||
@ -320,7 +320,7 @@ int BootHomebrew( char * filepath )
|
||||
|
||||
fclose( file );
|
||||
|
||||
CopyHomebrewMemory(( u8* ) buffer, 0, filesize );
|
||||
CopyHomebrewMemory( ( u8* ) buffer, 0, filesize );
|
||||
|
||||
if ( buffer )
|
||||
{
|
||||
@ -344,7 +344,7 @@ int BootHomebrewFromMem()
|
||||
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,36 +7,38 @@
|
||||
|
||||
#define MAXHOMEBREWS 500
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char FileName[100];
|
||||
char FilePath[150];
|
||||
unsigned int FileSize;
|
||||
} FileInfos;
|
||||
|
||||
class HomebrewFiles {
|
||||
public:
|
||||
class HomebrewFiles
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param path Path where to check for homebrew files
|
||||
HomebrewFiles(const char * path);
|
||||
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);
|
||||
bool LoadPath( const char * path );
|
||||
//! Get the a filename of the list
|
||||
//!\param list index
|
||||
char * GetFilename(int index);
|
||||
char * GetFilename( int index );
|
||||
//! Get the a filepath of the list
|
||||
//!\param list index
|
||||
char * GetFilepath(int index);
|
||||
char * GetFilepath( int index );
|
||||
//! Get the a filesize of the list
|
||||
//!\param list index
|
||||
unsigned int GetFilesize(int index);
|
||||
unsigned int GetFilesize( int index );
|
||||
//! Get the filecount of the whole list
|
||||
int GetFilecount();
|
||||
//! Sort list by filepath
|
||||
void SortList();
|
||||
protected:
|
||||
protected:
|
||||
int filecount;
|
||||
FileInfos *FileInfo;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,10 +64,10 @@ void SetupPads()
|
||||
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);
|
||||
WPAD_SetDataFormat( WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR );
|
||||
WPAD_SetVRes( WPAD_CHAN_ALL, screenwidth, screenheight );
|
||||
|
||||
for(int i=0; i < 4; i++)
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
userInput[i].chan = i;
|
||||
}
|
||||
@ -77,9 +77,11 @@ void SetupPads()
|
||||
* 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,25 +116,31 @@ 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) {
|
||||
switch ( data->exp.type )
|
||||
{
|
||||
case WPAD_EXP_NUNCHUK:
|
||||
case WPAD_EXP_GUITARHERO3:
|
||||
if (right == 0) {
|
||||
if ( right == 0 )
|
||||
{
|
||||
mag = data->exp.nunchuk.js.mag;
|
||||
ang = data->exp.nunchuk.js.ang;
|
||||
}
|
||||
break;
|
||||
|
||||
case WPAD_EXP_CLASSIC:
|
||||
if (right == 0) {
|
||||
if ( right == 0 )
|
||||
{
|
||||
mag = data->exp.classic.ljs.mag;
|
||||
ang = data->exp.classic.ljs.ang;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
mag = data->exp.classic.rjs.mag;
|
||||
ang = data->exp.classic.rjs.ang;
|
||||
}
|
||||
@ -137,14 +151,14 @@ s8 WPAD_Stick(u8 chan, u8 right, int axis) {
|
||||
}
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
|
@ -20,6 +20,6 @@ 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,22 +42,25 @@ 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) {
|
||||
switch ( *++cp )
|
||||
{
|
||||
case '\"': /* " */
|
||||
*rp++ = '\"';
|
||||
++cp;
|
||||
@ -97,14 +104,17 @@ expand_escape (const char *str) {
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7': {
|
||||
case '7':
|
||||
{
|
||||
int ch = *cp++ - '0';
|
||||
|
||||
if (*cp >= '0' && *cp <= '7') {
|
||||
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';
|
||||
}
|
||||
@ -117,9 +127,10 @@ expand_escape (const char *str) {
|
||||
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));
|
||||
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;
|
||||
}
|
||||
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,7 +42,8 @@
|
||||
#define PAGE_SECTORS 64
|
||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
@ -50,7 +51,8 @@ typedef struct {
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
@ -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
@ -59,13 +59,15 @@
|
||||
|
||||
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cluster;
|
||||
sec_t sector;
|
||||
int32_t offset;
|
||||
} DIR_ENTRY_POSITION;
|
||||
|
||||
typedef struct {
|
||||
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
|
||||
@ -73,7 +75,8 @@ typedef struct {
|
||||
} DIR_ENTRY;
|
||||
|
||||
// Directory entry offsets
|
||||
enum DIR_ENTRY_offset {
|
||||
enum DIR_ENTRY_offset
|
||||
{
|
||||
DIR_ENTRY_name = 0x00,
|
||||
DIR_ENTRY_extension = 0x08,
|
||||
DIR_ENTRY_attributes = 0x0B,
|
||||
@ -92,17 +95,20 @@ enum DIR_ENTRY_offset {
|
||||
/*
|
||||
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 {
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const DISC_INTERFACE* (*getInterface)(void);
|
||||
const DISC_INTERFACE* ( *getInterface )( void );
|
||||
} INTERFACE_ID;
|
||||
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
|
||||
@ -45,7 +46,8 @@ 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) {
|
||||
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,21 +70,24 @@ 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) {
|
||||
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) {
|
||||
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->startup();
|
||||
}
|
||||
|
||||
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->features;
|
||||
}
|
||||
|
||||
|
@ -43,21 +43,26 @@ 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) {
|
||||
static const DISC_INTERFACE* get_io_wiisd ( void )
|
||||
{
|
||||
return &__io_wiisd;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_usbstorage (void) {
|
||||
static const DISC_INTERFACE* get_io_usbstorage ( void )
|
||||
{
|
||||
return &__io_usbstorage2;
|
||||
}
|
||||
|
||||
static const DISC_INTERFACE* get_io_gcsda (void) {
|
||||
static const DISC_INTERFACE* get_io_gcsda ( void )
|
||||
{
|
||||
return &__io_gcsda;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_gcsdb (void) {
|
||||
static const DISC_INTERFACE* get_io_gcsdb ( void )
|
||||
{
|
||||
return &__io_gcsdb;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] =
|
||||
{
|
||||
{"sd", get_io_wiisd},
|
||||
{"usb", get_io_usbstorage},
|
||||
{"carda", get_io_gcsda},
|
||||
|
@ -35,9 +35,10 @@
|
||||
A list of all default devices to try at startup,
|
||||
terminated by a {NULL,NULL} entry.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const DISC_INTERFACE* (*getInterface)(void);
|
||||
const DISC_INTERFACE* ( *getInterface )( void );
|
||||
} INTERFACE_ID;
|
||||
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
|
||||
@ -45,7 +46,8 @@ 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) {
|
||||
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,21 +70,24 @@ 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) {
|
||||
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) {
|
||||
static inline bool _FAT_disc_startup ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->startup();
|
||||
}
|
||||
|
||||
@ -89,21 +95,24 @@ static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
static inline uint32_t _FAT_disc_features ( const DISC_INTERFACE* disc )
|
||||
{
|
||||
return disc->features;
|
||||
}
|
||||
|
||||
|
@ -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,21 +46,25 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
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 )
|
||||
{
|
||||
CACHE* cache;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if (numberOfPages < 2) {
|
||||
if ( numberOfPages < 2 )
|
||||
{
|
||||
numberOfPages = 2;
|
||||
}
|
||||
|
||||
if (sectorsPerPage < 8) {
|
||||
if ( sectorsPerPage < 8 )
|
||||
{
|
||||
sectorsPerPage = 8;
|
||||
}
|
||||
|
||||
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
|
||||
if (cache == NULL) {
|
||||
cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) );
|
||||
if ( cache == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -70,18 +74,20 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsP
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
|
||||
|
||||
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL) {
|
||||
_FAT_mem_free (cache);
|
||||
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++) {
|
||||
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 );
|
||||
cacheEntries[i].cache = ( uint8_t* ) _FAT_mem_align ( sectorsPerPage * BYTES_PER_READ );
|
||||
}
|
||||
|
||||
cache->cacheEntries = cacheEntries;
|
||||
@ -89,29 +95,32 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsP
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache) {
|
||||
void _FAT_cache_destructor ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
// Clear out cache before destroying it
|
||||
_FAT_cache_flush(cache);
|
||||
_FAT_cache_flush( cache );
|
||||
|
||||
// Free memory in reverse allocation order
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
_FAT_mem_free (cache->cacheEntries[i].cache);
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
_FAT_mem_free ( cache->cacheEntries[i].cache );
|
||||
}
|
||||
_FAT_mem_free (cache->cacheEntries);
|
||||
_FAT_mem_free (cache);
|
||||
_FAT_mem_free ( cache->cacheEntries );
|
||||
_FAT_mem_free ( cache );
|
||||
}
|
||||
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
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;
|
||||
@ -122,55 +131,60 @@ static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector)
|
||||
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)) {
|
||||
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]);
|
||||
return &( cacheEntries[i] );
|
||||
}
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||
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;
|
||||
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
|
||||
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 ( 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].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;
|
||||
|
||||
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;
|
||||
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);
|
||||
dest += ( secs_to_read * BYTES_PER_READ );
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
@ -181,30 +195,32 @@ bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buf
|
||||
/*
|
||||
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;
|
||||
|
||||
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);
|
||||
memcpy( buffer, entry->cache + ( ( sec*BYTES_PER_READ ) + offset ), size );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||
if ( !_FAT_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||
|
||||
switch(num_bytes) {
|
||||
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;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
@ -213,59 +229,62 @@ bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sect
|
||||
/*
|
||||
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;
|
||||
|
||||
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);
|
||||
memcpy( entry->cache + ( ( sec*BYTES_PER_READ ) + offset ), buffer, size );
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
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) {
|
||||
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;
|
||||
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;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@ -273,16 +292,22 @@ static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count)
|
||||
CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||
{
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
if ( sector > cacheEntries[i].sector )
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
@ -292,25 +317,27 @@ static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count)
|
||||
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;
|
||||
|
||||
while(numSectors>0)
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _FAT_cache_findPage(cache,sector,numSectors);
|
||||
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;
|
||||
|
||||
_FAT_disc_writeSectors(cache->disc,sector,secs_to_write,src);
|
||||
src += (secs_to_write*BYTES_PER_READ);
|
||||
_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;
|
||||
}
|
||||
@ -318,19 +345,21 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
|
||||
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);
|
||||
src += ( secs_to_write * BYTES_PER_READ );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
_FAT_disc_writeSectors(cache->disc,sector,numSectors,src);
|
||||
numSectors=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_FAT_disc_writeSectors( cache->disc, sector, numSectors, src );
|
||||
numSectors = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -339,12 +368,16 @@ bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, cons
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache) {
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -354,10 +387,12 @@ bool _FAT_cache_flush (CACHE* cache) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void _FAT_cache_invalidate (CACHE* cache) {
|
||||
void _FAT_cache_invalidate ( CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
_FAT_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; 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;
|
||||
|
@ -42,7 +42,8 @@
|
||||
#define PAGE_SECTORS 64
|
||||
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
@ -50,7 +51,8 @@ typedef struct {
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
@ -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
|
||||
|
||||
|
@ -45,48 +45,55 @@
|
||||
#include "lock.h"
|
||||
|
||||
|
||||
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
|
||||
int _FAT_stat_r ( struct _reent *r, const char *path, struct stat *st )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
DIR_ENTRY dirEntry;
|
||||
|
||||
// Get the partition this file is on
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL) {
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
path = strchr (path, ':') + 1;
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Search for the file on the disc
|
||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fill in the stat struct
|
||||
_FAT_directory_entryStat (partition, &dirEntry, st);
|
||||
_FAT_directory_entryStat ( partition, &dirEntry, st );
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink) {
|
||||
int _FAT_link_r ( struct _reent *r, const char *existing, const char *newLink )
|
||||
{
|
||||
r->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _FAT_unlink_r (struct _reent *r, const char *path) {
|
||||
int _FAT_unlink_r ( struct _reent *r, const char *path )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
DIR_ENTRY dirEntry;
|
||||
DIR_ENTRY dirContents;
|
||||
@ -95,117 +102,140 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
|
||||
bool errorOccured = false;
|
||||
|
||||
// Get the partition this directory is on
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL) {
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure we aren't trying to write to a read-only disc
|
||||
if (partition->readOnly) {
|
||||
if ( partition->readOnly )
|
||||
{
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
path = strchr (path, ':') + 1;
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Search for the file on the disc
|
||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData);
|
||||
cluster = _FAT_directory_entryGetCluster ( partition, dirEntry.entryData );
|
||||
|
||||
|
||||
// If this is a directory, make sure it is empty
|
||||
if (_FAT_directory_isDirectory (&dirEntry)) {
|
||||
nextEntry = _FAT_directory_getFirstEntry (partition, &dirContents, cluster);
|
||||
if ( _FAT_directory_isDirectory ( &dirEntry ) )
|
||||
{
|
||||
nextEntry = _FAT_directory_getFirstEntry ( partition, &dirContents, cluster );
|
||||
|
||||
while (nextEntry) {
|
||||
if (!_FAT_directory_isDot (&dirContents)) {
|
||||
while ( nextEntry )
|
||||
{
|
||||
if ( !_FAT_directory_isDot ( &dirContents ) )
|
||||
{
|
||||
// The directory had something in it that isn't a reference to itself or it's parent
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
nextEntry = _FAT_directory_getNextEntry (partition, &dirContents);
|
||||
nextEntry = _FAT_directory_getNextEntry ( partition, &dirContents );
|
||||
}
|
||||
}
|
||||
|
||||
if (_FAT_fat_isValidCluster(partition, cluster)) {
|
||||
if ( _FAT_fat_isValidCluster( partition, cluster ) )
|
||||
{
|
||||
// Remove the cluster chain for this file
|
||||
if (!_FAT_fat_clearLinks (partition, cluster)) {
|
||||
if ( !_FAT_fat_clearLinks ( partition, cluster ) )
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the directory entry for this file
|
||||
if (!_FAT_directory_removeEntry (partition, &dirEntry)) {
|
||||
if ( !_FAT_directory_removeEntry ( partition, &dirEntry ) )
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush(partition->cache)) {
|
||||
if ( !_FAT_cache_flush( partition->cache ) )
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
if (errorOccured) {
|
||||
_FAT_unlock( &partition->lock );
|
||||
if ( errorOccured )
|
||||
{
|
||||
return -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int _FAT_chdir_r (struct _reent *r, const char *path) {
|
||||
int _FAT_chdir_r ( struct _reent *r, const char *path )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
|
||||
// Get the partition this directory is on
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL) {
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
path = strchr (path, ':') + 1;
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Try changing directory
|
||||
if (_FAT_directory_chdir (partition, path)) {
|
||||
if ( _FAT_directory_chdir ( partition, path ) )
|
||||
{
|
||||
// Successful
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
return 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
||||
int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
DIR_ENTRY oldDirEntry;
|
||||
DIR_ENTRY newDirEntry;
|
||||
@ -213,113 +243,130 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
|
||||
uint32_t dirCluster;
|
||||
|
||||
// Get the partition this directory is on
|
||||
partition = _FAT_partition_getPartitionFromPath (oldName);
|
||||
if (partition == NULL) {
|
||||
partition = _FAT_partition_getPartitionFromPath ( oldName );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Make sure the same partition is used for the old and new names
|
||||
if (partition != _FAT_partition_getPartitionFromPath (newName)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( partition != _FAT_partition_getPartitionFromPath ( newName ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure we aren't trying to write to a read-only disc
|
||||
if (partition->readOnly) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( partition->readOnly )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (oldName, ':') != NULL) {
|
||||
oldName = strchr (oldName, ':') + 1;
|
||||
if ( strchr ( oldName, ':' ) != NULL )
|
||||
{
|
||||
oldName = strchr ( oldName, ':' ) + 1;
|
||||
}
|
||||
if (strchr (oldName, ':') != NULL) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( strchr ( oldName, ':' ) != NULL )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (strchr (newName, ':') != NULL) {
|
||||
newName = strchr (newName, ':') + 1;
|
||||
if ( strchr ( newName, ':' ) != NULL )
|
||||
{
|
||||
newName = strchr ( newName, ':' ) + 1;
|
||||
}
|
||||
if (strchr (newName, ':') != NULL) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( strchr ( newName, ':' ) != NULL )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Search for the file on the disc
|
||||
if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &oldDirEntry, oldName, NULL ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure there is no existing file / directory with the new name
|
||||
if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( _FAT_directory_entryFromPath ( partition, &newDirEntry, newName, NULL ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create the new file entry
|
||||
// Get the directory it has to go in
|
||||
pathEnd = strrchr (newName, DIR_SEPARATOR);
|
||||
if (pathEnd == NULL) {
|
||||
pathEnd = strrchr ( newName, DIR_SEPARATOR );
|
||||
if ( pathEnd == NULL )
|
||||
{
|
||||
// No path was specified
|
||||
dirCluster = partition->cwdCluster;
|
||||
pathEnd = newName;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Path was specified -- get the right dirCluster
|
||||
// Recycling newDirEntry, since it needs to be recreated anyway
|
||||
if (!_FAT_directory_entryFromPath (partition, &newDirEntry, newName, pathEnd) ||
|
||||
!_FAT_directory_isDirectory(&newDirEntry)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) ||
|
||||
!_FAT_directory_isDirectory( &newDirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
dirCluster = _FAT_directory_entryGetCluster (partition, newDirEntry.entryData);
|
||||
dirCluster = _FAT_directory_entryGetCluster ( partition, newDirEntry.entryData );
|
||||
// Move the pathEnd past the last DIR_SEPARATOR
|
||||
pathEnd += 1;
|
||||
}
|
||||
|
||||
// Copy the entry data
|
||||
memcpy (&newDirEntry, &oldDirEntry, sizeof(DIR_ENTRY));
|
||||
memcpy ( &newDirEntry, &oldDirEntry, sizeof( DIR_ENTRY ) );
|
||||
|
||||
// Set the new name
|
||||
strncpy (newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1);
|
||||
strncpy ( newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 );
|
||||
|
||||
// Write the new entry
|
||||
if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_addEntry ( partition, &newDirEntry, dirCluster ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Remove the old entry
|
||||
if (!_FAT_directory_removeEntry (partition, &oldDirEntry)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_removeEntry ( partition, &oldDirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush (partition->cache)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_cache_flush ( partition->cache ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
||||
int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
bool fileExists;
|
||||
DIR_ENTRY dirEntry;
|
||||
@ -327,145 +374,158 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
|
||||
uint32_t parentCluster, dirCluster;
|
||||
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
||||
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL) {
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
path = strchr (path, ':') + 1;
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
// Search for the file/directory on the disc
|
||||
fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL);
|
||||
fileExists = _FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL );
|
||||
|
||||
// Make sure it doesn't exist
|
||||
if (fileExists) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( fileExists )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (partition->readOnly) {
|
||||
if ( partition->readOnly )
|
||||
{
|
||||
// We can't write to a read-only partition
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the directory it has to go in
|
||||
pathEnd = strrchr (path, DIR_SEPARATOR);
|
||||
if (pathEnd == NULL) {
|
||||
pathEnd = strrchr ( path, DIR_SEPARATOR );
|
||||
if ( pathEnd == NULL )
|
||||
{
|
||||
// No path was specified
|
||||
parentCluster = partition->cwdCluster;
|
||||
pathEnd = path;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Path was specified -- get the right parentCluster
|
||||
// Recycling dirEntry, since it needs to be recreated anyway
|
||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) ||
|
||||
!_FAT_directory_isDirectory(&dirEntry)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
|
||||
!_FAT_directory_isDirectory( &dirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
parentCluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData);
|
||||
parentCluster = _FAT_directory_entryGetCluster ( partition, dirEntry.entryData );
|
||||
// Move the pathEnd past the last DIR_SEPARATOR
|
||||
pathEnd += 1;
|
||||
}
|
||||
// Create the entry data
|
||||
strncpy (dirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1);
|
||||
memset (dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||
strncpy ( dirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 );
|
||||
memset ( dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE );
|
||||
|
||||
// Set the creation time and date
|
||||
dirEntry.entryData[DIR_ENTRY_cTime_ms] = 0;
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cTime, _FAT_filetime_getTimeFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mTime, _FAT_filetime_getTimeFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mDate, _FAT_filetime_getDateFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_aDate, _FAT_filetime_getDateFromRTC());
|
||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_cTime, _FAT_filetime_getTimeFromRTC() );
|
||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC() );
|
||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_mTime, _FAT_filetime_getTimeFromRTC() );
|
||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_mDate, _FAT_filetime_getDateFromRTC() );
|
||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_aDate, _FAT_filetime_getDateFromRTC() );
|
||||
|
||||
// Set the directory attribute
|
||||
dirEntry.entryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||
|
||||
// Get a cluster for the new directory
|
||||
dirCluster = _FAT_fat_linkFreeClusterCleared (partition, CLUSTER_FREE);
|
||||
if (!_FAT_fat_isValidCluster(partition, dirCluster)) {
|
||||
dirCluster = _FAT_fat_linkFreeClusterCleared ( partition, CLUSTER_FREE );
|
||||
if ( !_FAT_fat_isValidCluster( partition, dirCluster ) )
|
||||
{
|
||||
// No space left on disc for the cluster
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cluster, dirCluster);
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_cluster, dirCluster );
|
||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16 );
|
||||
|
||||
// Write the new directory's entry to it's parent
|
||||
if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_directory_addEntry ( partition, &dirEntry, parentCluster ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create the dot entry within the directory
|
||||
memset (newEntryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||
memset (newEntryData, ' ', 11);
|
||||
memset ( newEntryData, 0, DIR_ENTRY_DATA_SIZE );
|
||||
memset ( newEntryData, ' ', 11 );
|
||||
newEntryData[DIR_ENTRY_name] = '.';
|
||||
newEntryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_cluster, dirCluster);
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||
u16_to_u8array ( newEntryData, DIR_ENTRY_cluster, dirCluster );
|
||||
u16_to_u8array ( newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16 );
|
||||
|
||||
// Write it to the directory, erasing that sector in the process
|
||||
_FAT_cache_eraseWritePartialSector ( partition->cache, newEntryData,
|
||||
_FAT_fat_clusterToSector (partition, dirCluster), 0, DIR_ENTRY_DATA_SIZE);
|
||||
_FAT_fat_clusterToSector ( partition, dirCluster ), 0, DIR_ENTRY_DATA_SIZE );
|
||||
|
||||
|
||||
// Create the double dot entry within the directory
|
||||
|
||||
// if ParentDir == Rootdir then ".."" always link to Cluster 0
|
||||
if(parentCluster == partition->rootDirCluster)
|
||||
if ( parentCluster == partition->rootDirCluster )
|
||||
parentCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
|
||||
newEntryData[DIR_ENTRY_name + 1] = '.';
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_cluster, parentCluster);
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16);
|
||||
u16_to_u8array ( newEntryData, DIR_ENTRY_cluster, parentCluster );
|
||||
u16_to_u8array ( newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16 );
|
||||
|
||||
// Write it to the directory
|
||||
_FAT_cache_writePartialSector ( partition->cache, newEntryData,
|
||||
_FAT_fat_clusterToSector (partition, dirCluster), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
_FAT_fat_clusterToSector ( partition, dirCluster ), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush(partition->cache)) {
|
||||
_FAT_unlock(&partition->lock);
|
||||
if ( !_FAT_cache_flush( partition->cache ) )
|
||||
{
|
||||
_FAT_unlock( &partition->lock );
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
int _FAT_statvfs_r ( struct _reent *r, const char *path, struct statvfs *buf )
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
unsigned int freeClusterCount;
|
||||
|
||||
// Get the partition of the requested path
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL) {
|
||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
_FAT_lock( &partition->lock );
|
||||
|
||||
freeClusterCount = _FAT_fat_freeClusterCount (partition);
|
||||
freeClusterCount = _FAT_fat_freeClusterCount ( partition );
|
||||
|
||||
// FAT clusters = POSIX blocks
|
||||
buf->f_bsize = partition->bytesPerCluster; // File system block size.
|
||||
@ -481,130 +541,143 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
buf->f_favail = freeClusterCount; // Number of file serial numbers available to non-privileged process.
|
||||
|
||||
// File system ID. 32bit ioType value
|
||||
buf->f_fsid = _FAT_disc_hostType(partition->disc);
|
||||
buf->f_fsid = _FAT_disc_hostType( partition->disc );
|
||||
|
||||
// Bit mask of f_flag values.
|
||||
buf->f_flag = ST_NOSUID /* No support for ST_ISUID and ST_ISGID file mode bits */
|
||||
| (partition->readOnly ? ST_RDONLY /* Read only file system */ : 0 ) ;
|
||||
| ( partition->readOnly ? ST_RDONLY /* Read only file system */ : 0 ) ;
|
||||
// Maximum filename length.
|
||||
buf->f_namemax = MAX_FILENAME_LENGTH;
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) {
|
||||
DIR_ITER* _FAT_diropen_r( struct _reent *r, DIR_ITER *dirState, const char *path )
|
||||
{
|
||||
DIR_ENTRY dirEntry;
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||
bool fileExists;
|
||||
|
||||
state->partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (state->partition == NULL) {
|
||||
state->partition = _FAT_partition_getPartitionFromPath ( path );
|
||||
if ( state->partition == NULL )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr (path, ':') != NULL) {
|
||||
path = strchr (path, ':') + 1;
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
path = strchr ( path, ':' ) + 1;
|
||||
}
|
||||
if (strchr (path, ':') != NULL) {
|
||||
if ( strchr ( path, ':' ) != NULL )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_FAT_lock(&state->partition->lock);
|
||||
_FAT_lock( &state->partition->lock );
|
||||
|
||||
// Get the start cluster of the directory
|
||||
fileExists = _FAT_directory_entryFromPath (state->partition, &dirEntry, path, NULL);
|
||||
fileExists = _FAT_directory_entryFromPath ( state->partition, &dirEntry, path, NULL );
|
||||
|
||||
if (!fileExists) {
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
if ( !fileExists )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Make sure it is a directory
|
||||
if (! _FAT_directory_isDirectory (&dirEntry)) {
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
if ( ! _FAT_directory_isDirectory ( &dirEntry ) )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Save the start cluster for use when resetting the directory data
|
||||
state->startCluster = _FAT_directory_entryGetCluster (state->partition, dirEntry.entryData);
|
||||
state->startCluster = _FAT_directory_entryGetCluster ( state->partition, dirEntry.entryData );
|
||||
|
||||
// Get the first entry for use with a call to dirnext
|
||||
state->validEntry =
|
||||
_FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster);
|
||||
_FAT_directory_getFirstEntry ( state->partition, &( state->currentEntry ), state->startCluster );
|
||||
|
||||
// We are now using this entry
|
||||
state->inUse = true;
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
return (DIR_ITER*) state;
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
return ( DIR_ITER* ) state;
|
||||
}
|
||||
|
||||
int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) {
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
int _FAT_dirreset_r ( struct _reent *r, DIR_ITER *dirState )
|
||||
{
|
||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||
|
||||
_FAT_lock(&state->partition->lock);
|
||||
_FAT_lock( &state->partition->lock );
|
||||
|
||||
// Make sure we are still using this entry
|
||||
if (!state->inUse) {
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
if ( !state->inUse )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the first entry for use with a call to dirnext
|
||||
state->validEntry =
|
||||
_FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster);
|
||||
_FAT_directory_getFirstEntry ( state->partition, &( state->currentEntry ), state->startCluster );
|
||||
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) {
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
int _FAT_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat )
|
||||
{
|
||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||
|
||||
_FAT_lock(&state->partition->lock);
|
||||
_FAT_lock( &state->partition->lock );
|
||||
|
||||
// Make sure we are still using this entry
|
||||
if (!state->inUse) {
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
if ( !state->inUse )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure there is another file to report on
|
||||
if (! state->validEntry) {
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
if ( ! state->validEntry )
|
||||
{
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the filename
|
||||
strncpy (filename, state->currentEntry.filename, MAX_FILENAME_LENGTH);
|
||||
strncpy ( filename, state->currentEntry.filename, MAX_FILENAME_LENGTH );
|
||||
// Get the stats, if requested
|
||||
if (filestat != NULL) {
|
||||
_FAT_directory_entryStat (state->partition, &(state->currentEntry), filestat);
|
||||
if ( filestat != NULL )
|
||||
{
|
||||
_FAT_directory_entryStat ( state->partition, &( state->currentEntry ), filestat );
|
||||
}
|
||||
|
||||
// Look for the next entry for use next time
|
||||
state->validEntry =
|
||||
_FAT_directory_getNextEntry (state->partition, &(state->currentEntry));
|
||||
_FAT_directory_getNextEntry ( state->partition, &( state->currentEntry ) );
|
||||
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState) {
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
int _FAT_dirclose_r ( struct _reent *r, DIR_ITER *dirState )
|
||||
{
|
||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
||||
|
||||
// We are no longer using this entry
|
||||
_FAT_lock(&state->partition->lock);
|
||||
_FAT_lock( &state->partition->lock );
|
||||
state->inUse = false;
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
_FAT_unlock( &state->partition->lock );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -39,7 +39,8 @@
|
||||
#include "common.h"
|
||||
#include "directory.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
PARTITION* partition;
|
||||
DIR_ENTRY currentEntry;
|
||||
uint32_t startCluster;
|
||||
@ -47,27 +48,27 @@ typedef struct {
|
||||
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
@ -41,7 +41,8 @@
|
||||
|
||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u32 cluster;
|
||||
sec_t sector;
|
||||
s32 byte;
|
||||
@ -49,7 +50,8 @@ typedef struct {
|
||||
|
||||
struct _FILE_STRUCT;
|
||||
|
||||
struct _FILE_STRUCT {
|
||||
struct _FILE_STRUCT
|
||||
{
|
||||
uint32_t filesize;
|
||||
uint32_t startCluster;
|
||||
uint32_t currentPosition;
|
||||
@ -69,37 +71,37 @@ struct _FILE_STRUCT {
|
||||
|
||||
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,17 +35,18 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
if (cluster == CLUSTER_FREE) {
|
||||
if ( cluster == CLUSTER_FREE )
|
||||
{
|
||||
return CLUSTER_FREE;
|
||||
}
|
||||
|
||||
switch (partition->filesysType)
|
||||
switch ( partition->filesysType )
|
||||
{
|
||||
case FS_UNKNOWN:
|
||||
return CLUSTER_ERROR;
|
||||
@ -54,30 +55,34 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||
case FS_FAT12:
|
||||
{
|
||||
u32 nextCluster_h;
|
||||
sector = partition->fat.fatStart + (((cluster * 3) / 2) / BYTES_PER_READ);
|
||||
offset = ((cluster * 3) / 2) % BYTES_PER_READ;
|
||||
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++;
|
||||
|
||||
if (offset >= BYTES_PER_READ) {
|
||||
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) {
|
||||
if ( cluster & 0x01 )
|
||||
{
|
||||
nextCluster = nextCluster >> 4;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
nextCluster &= 0x0FFF;
|
||||
}
|
||||
|
||||
if (nextCluster >= 0x0FF7)
|
||||
if ( nextCluster >= 0x0FF7 )
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
@ -85,23 +90,25 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||
break;
|
||||
}
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ((cluster << 1) / BYTES_PER_READ);
|
||||
offset = (cluster % (BYTES_PER_READ >> 1)) << 1;
|
||||
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) {
|
||||
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;
|
||||
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) {
|
||||
if ( nextCluster >= 0x0FFFFFF7 )
|
||||
{
|
||||
nextCluster = CLUSTER_EOF;
|
||||
}
|
||||
break;
|
||||
@ -118,74 +125,80 @@ uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||
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) {
|
||||
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 */))
|
||||
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (partition->filesysType)
|
||||
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;
|
||||
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) {
|
||||
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) {
|
||||
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;
|
||||
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ((cluster << 1) / BYTES_PER_READ);
|
||||
offset = (cluster % (BYTES_PER_READ >> 1)) << 1;
|
||||
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;
|
||||
|
||||
case FS_FAT32:
|
||||
sector = partition->fat.fatStart + ((cluster << 2) / BYTES_PER_READ);
|
||||
offset = (cluster % (BYTES_PER_READ >> 2)) << 2;
|
||||
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;
|
||||
|
||||
@ -203,7 +216,8 @@ 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 _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t firstFree;
|
||||
uint32_t curLink;
|
||||
uint32_t lastCluster;
|
||||
@ -211,32 +225,40 @@ uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
|
||||
|
||||
lastCluster = partition->fat.lastCluster;
|
||||
|
||||
if (cluster > lastCluster) {
|
||||
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)) {
|
||||
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) {
|
||||
if ( firstFree < CLUSTER_FIRST )
|
||||
{
|
||||
firstFree = CLUSTER_FIRST;
|
||||
}
|
||||
|
||||
// Search until a free cluster is found
|
||||
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE) {
|
||||
while ( _FAT_fat_nextCluster( partition, firstFree ) != CLUSTER_FREE )
|
||||
{
|
||||
firstFree++;
|
||||
if (firstFree > lastCluster) {
|
||||
if (loopedAroundFAT) {
|
||||
if ( firstFree > lastCluster )
|
||||
{
|
||||
if ( loopedAroundFAT )
|
||||
{
|
||||
// If couldn't get a free cluster then return an error
|
||||
partition->fat.firstFree = firstFree;
|
||||
return CLUSTER_ERROR;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try looping back to the beginning of the FAT
|
||||
// This was suggested by loopy
|
||||
firstFree = CLUSTER_FIRST;
|
||||
@ -246,13 +268,13 @@ uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
|
||||
}
|
||||
partition->fat.firstFree = firstFree;
|
||||
|
||||
if ((cluster >= CLUSTER_FIRST) && (cluster < lastCluster))
|
||||
if ( ( cluster >= CLUSTER_FIRST ) && ( cluster < lastCluster ) )
|
||||
{
|
||||
// Update the linked from FAT entry
|
||||
_FAT_fat_writeFatEntry (partition, cluster, firstFree);
|
||||
_FAT_fat_writeFatEntry ( partition, cluster, firstFree );
|
||||
}
|
||||
// Create the linked to FAT entry
|
||||
_FAT_fat_writeFatEntry (partition, firstFree, CLUSTER_EOF);
|
||||
_FAT_fat_writeFatEntry ( partition, firstFree, CLUSTER_EOF );
|
||||
|
||||
return firstFree;
|
||||
}
|
||||
@ -263,24 +285,27 @@ 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 _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);
|
||||
newCluster = _FAT_fat_linkFreeCluster( partition, cluster );
|
||||
|
||||
if (newCluster == CLUSTER_FREE || newCluster == 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);
|
||||
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;
|
||||
@ -291,23 +316,26 @@ 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) {
|
||||
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 */))
|
||||
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) {
|
||||
if ( cluster < partition->fat.firstFree )
|
||||
{
|
||||
partition->fat.firstFree = cluster;
|
||||
}
|
||||
|
||||
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR)) {
|
||||
while ( ( cluster != CLUSTER_EOF ) && ( cluster != CLUSTER_FREE ) && ( cluster != CLUSTER_ERROR ) )
|
||||
{
|
||||
// Store next cluster before erasing the link
|
||||
nextCluster = _FAT_fat_nextCluster (partition, cluster);
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, cluster );
|
||||
|
||||
// Erase the link
|
||||
_FAT_fat_writeFatEntry (partition, cluster, CLUSTER_FREE);
|
||||
_FAT_fat_writeFatEntry ( partition, cluster, CLUSTER_FREE );
|
||||
|
||||
// Move onto next cluster
|
||||
cluster = nextCluster;
|
||||
@ -324,30 +352,36 @@ 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 _FAT_fat_trimChain ( PARTITION* partition, uint32_t startCluster, unsigned int chainLength )
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if (chainLength == 0) {
|
||||
if ( chainLength == 0 )
|
||||
{
|
||||
// Drop the entire chain
|
||||
_FAT_fat_clearLinks (partition, startCluster);
|
||||
_FAT_fat_clearLinks ( partition, startCluster );
|
||||
return CLUSTER_FREE;
|
||||
} else {
|
||||
}
|
||||
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)) {
|
||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
||||
while ( ( chainLength > 0 ) && ( nextCluster != CLUSTER_FREE ) && ( nextCluster != CLUSTER_EOF ) )
|
||||
{
|
||||
chainLength--;
|
||||
startCluster = nextCluster;
|
||||
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
|
||||
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);
|
||||
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);
|
||||
_FAT_fat_writeFatEntry ( partition, startCluster, CLUSTER_EOF );
|
||||
|
||||
return startCluster;
|
||||
}
|
||||
@ -357,9 +391,11 @@ uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsign
|
||||
_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);
|
||||
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;
|
||||
}
|
||||
@ -368,12 +404,15 @@ uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
|
||||
_FAT_fat_freeClusterCount
|
||||
Return the number of free clusters available
|
||||
-----------------------------------------------------------------*/
|
||||
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition) {
|
||||
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) {
|
||||
for ( curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++ )
|
||||
{
|
||||
if ( _FAT_fat_nextCluster( partition, curCluster ) == CLUSTER_FREE )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -44,27 +44,29 @@
|
||||
#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 :
|
||||
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,26 +40,28 @@
|
||||
#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;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1) {
|
||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
localtime_r(&epochTime, &timeParts);
|
||||
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;
|
||||
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)
|
||||
( ( timeParts.tm_hour & 0x1F ) << 11 ) |
|
||||
( ( timeParts.tm_min & 0x3F ) << 5 ) |
|
||||
( ( timeParts.tm_sec >> 1 ) & 0x1F )
|
||||
);
|
||||
#else
|
||||
return 0;
|
||||
@ -67,41 +69,44 @@ uint16_t _FAT_filetime_getTimeFromRTC (void) {
|
||||
}
|
||||
|
||||
|
||||
uint16_t _FAT_filetime_getDateFromRTC (void) {
|
||||
uint16_t _FAT_filetime_getDateFromRTC ( void )
|
||||
{
|
||||
#ifdef USE_RTC_TIME
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1) {
|
||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
localtime_r(&epochTime, &timeParts);
|
||||
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)
|
||||
( ( ( 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;
|
||||
#endif
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
struct tm timeParts;
|
||||
|
||||
timeParts.tm_hour = t >> 11;
|
||||
timeParts.tm_min = (t >> 5) & 0x3F;
|
||||
timeParts.tm_sec = (t & 0x1F) << 1;
|
||||
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_mon = ( ( d >> 5 ) & 0x0F ) - 1;
|
||||
timeParts.tm_year = ( d >> 9 ) + 80;
|
||||
|
||||
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
|
||||
|
@ -38,9 +38,10 @@
|
||||
#include "mem_allocate.h"
|
||||
#include "disc_fat.h"
|
||||
|
||||
static const devoptab_t dotab_fat = {
|
||||
static const devoptab_t dotab_fat =
|
||||
{
|
||||
"fat",
|
||||
sizeof (FILE_STRUCT),
|
||||
sizeof ( FILE_STRUCT ),
|
||||
_FAT_open_r,
|
||||
_FAT_close_r,
|
||||
_FAT_write_r,
|
||||
@ -53,7 +54,7 @@ static const devoptab_t dotab_fat = {
|
||||
_FAT_chdir_r,
|
||||
_FAT_rename_r,
|
||||
_FAT_mkdir_r,
|
||||
sizeof (DIR_STATE_STRUCT),
|
||||
sizeof ( DIR_STATE_STRUCT ),
|
||||
_FAT_diropen_r,
|
||||
_FAT_dirreset_r,
|
||||
_FAT_dirnext_r,
|
||||
@ -64,134 +65,151 @@ static const devoptab_t dotab_fat = {
|
||||
NULL /* Device data */
|
||||
};
|
||||
|
||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) {
|
||||
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())
|
||||
if ( !interface->startup() )
|
||||
return false;
|
||||
|
||||
if(!interface->isInserted()) {
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
interface->shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
devops = _FAT_mem_allocate (sizeof(devoptab_t) + strlen(name) + 1);
|
||||
if (!devops) {
|
||||
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);
|
||||
nameCopy = ( char* )( devops + 1 );
|
||||
|
||||
// Initialize the file system
|
||||
partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector);
|
||||
if (!partition) {
|
||||
_FAT_mem_free (devops);
|
||||
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);
|
||||
memcpy ( devops, &dotab_fat, sizeof( dotab_fat ) );
|
||||
strcpy ( nameCopy, name );
|
||||
devops->name = nameCopy;
|
||||
devops->deviceData = partition;
|
||||
|
||||
AddDevice (devops);
|
||||
AddDevice ( devops );
|
||||
|
||||
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) {
|
||||
void fatUnmount ( const char* name )
|
||||
{
|
||||
devoptab_t *devops;
|
||||
PARTITION* partition;
|
||||
const DISC_INTERFACE *disc;
|
||||
|
||||
devops = (devoptab_t*)GetDeviceOpTab (name);
|
||||
if (!devops) {
|
||||
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) {
|
||||
if ( devops->open_r != dotab_fat.open_r )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (RemoveDevice (name) == -1) {
|
||||
if ( RemoveDevice ( name ) == -1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
partition = (PARTITION*)devops->deviceData;
|
||||
partition = ( PARTITION* )devops->deviceData;
|
||||
disc = partition->disc;
|
||||
_FAT_partition_destructor (partition);
|
||||
_FAT_mem_free (devops);
|
||||
_FAT_partition_destructor ( partition );
|
||||
_FAT_mem_free ( devops );
|
||||
disc->shutdown();
|
||||
}
|
||||
|
||||
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
||||
bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
|
||||
{
|
||||
int i;
|
||||
int defaultDevice = -1;
|
||||
const DISC_INTERFACE *disc;
|
||||
|
||||
for (i = 0;
|
||||
for ( i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++)
|
||||
i++ )
|
||||
{
|
||||
disc = _FAT_disc_interfaces[i].getInterface();
|
||||
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) {
|
||||
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) {
|
||||
if ( defaultDevice < 0 )
|
||||
{
|
||||
defaultDevice = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultDevice < 0) {
|
||||
if ( defaultDevice < 0 )
|
||||
{
|
||||
// None of our devices mounted
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setAsDefaultDevice) {
|
||||
if ( setAsDefaultDevice )
|
||||
{
|
||||
char filePath[MAXPATHLEN * 2];
|
||||
strcpy (filePath, _FAT_disc_interfaces[defaultDevice].name);
|
||||
strcat (filePath, ":/");
|
||||
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 ) {
|
||||
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;
|
||||
for ( i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++)
|
||||
i++ )
|
||||
{
|
||||
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
||||
strlen(_FAT_disc_interfaces[i].name)))
|
||||
strlen( _FAT_disc_interfaces[i].name ) ) )
|
||||
{
|
||||
char *lastSlash;
|
||||
strcpy(filePath, __system_argv->argv[0]);
|
||||
strcpy( filePath, __system_argv->argv[0] );
|
||||
lastSlash = strrchr( filePath, '/' );
|
||||
|
||||
if ( NULL != lastSlash) {
|
||||
if ( *(lastSlash - 1) == ':') lastSlash++;
|
||||
if ( NULL != lastSlash )
|
||||
{
|
||||
if ( *( lastSlash - 1 ) == ':' ) lastSlash++;
|
||||
*lastSlash = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
chdir (filePath);
|
||||
chdir ( filePath );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fatInitDefault (void) {
|
||||
return fatInit (DEFAULT_CACHE_PAGES, true);
|
||||
bool fatInitDefault ( void )
|
||||
{
|
||||
return fatInit ( DEFAULT_CACHE_PAGES, true );
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,22 +60,22 @@ 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;
|
||||
}
|
||||
|
||||
static inline void _FAT_lock_deinit(mutex_t *mutex)
|
||||
static inline void _FAT_lock_deinit( mutex_t *mutex )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void _FAT_lock(mutex_t *mutex)
|
||||
static inline void _FAT_lock( mutex_t *mutex )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void _FAT_unlock(mutex_t *mutex)
|
||||
static inline void _FAT_unlock( mutex_t *mutex )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -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,7 +50,8 @@ Data offsets
|
||||
*/
|
||||
|
||||
// BIOS Parameter Block offsets
|
||||
enum BPB {
|
||||
enum BPB
|
||||
{
|
||||
BPB_jmpBoot = 0x00,
|
||||
BPB_OEMName = 0x03,
|
||||
// BIOS Parameter Block
|
||||
@ -98,7 +99,7 @@ enum BPB {
|
||||
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;
|
||||
@ -107,49 +108,56 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
|
||||
// Read first sector of disc
|
||||
if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) {
|
||||
if ( !_FAT_disc_readSectors ( disc, 0, 1, sectorBuffer ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(part_table,sectorBuffer+0x1BE,16*4);
|
||||
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))) {
|
||||
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;
|
||||
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
|
||||
for ( n = 0; n < 8; n++ ) // max 8 logic partitions
|
||||
{
|
||||
if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer)) return 0;
|
||||
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)))
|
||||
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;
|
||||
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))) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -157,117 +165,140 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
PARTITION* partition;
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||
|
||||
// Read first sector of disc
|
||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
|
||||
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)) {
|
||||
if ( ( sectorBuffer[BPB_bootSig_55] != 0x55 ) || ( sectorBuffer[BPB_bootSig_AA] != 0xAA ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (startSector != 0) {
|
||||
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))) {
|
||||
}
|
||||
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))) {
|
||||
}
|
||||
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)) {
|
||||
}
|
||||
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)))
|
||||
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)
|
||||
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) {
|
||||
partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) );
|
||||
if ( partition == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_FAT_startSector = startSector;
|
||||
|
||||
// Init the partition lock
|
||||
_FAT_lock_init(&partition->lock);
|
||||
_FAT_lock_init( &partition->lock );
|
||||
|
||||
// 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);
|
||||
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->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->fat.fatStart = startSector + u8array_to_u16( sectorBuffer, BPB_reservedSectors );
|
||||
|
||||
partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat);
|
||||
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);
|
||||
( ( 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;
|
||||
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) {
|
||||
if ( clusterCount < CLUSTERS_PER_FAT12 )
|
||||
{
|
||||
partition->filesysType = FS_FAT12; // FAT12 volume
|
||||
} else if (clusterCount < CLUSTERS_PER_FAT16) {
|
||||
}
|
||||
else if ( clusterCount < CLUSTERS_PER_FAT16 )
|
||||
{
|
||||
partition->filesysType = FS_FAT16; // FAT16 volume
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
partition->filesysType = FS_FAT32; // FAT32 volume
|
||||
}
|
||||
|
||||
if (partition->filesysType != FS_FAT32) {
|
||||
if ( partition->filesysType != FS_FAT32 )
|
||||
{
|
||||
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set up for the FAT32 way
|
||||
partition->rootDirCluster = u8array_to_u32(sectorBuffer, BPB_FAT32_rootClus);
|
||||
partition->rootDirCluster = u8array_to_u32( sectorBuffer, BPB_FAT32_rootClus );
|
||||
// Check if FAT mirroring is enabled
|
||||
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) {
|
||||
if ( !( sectorBuffer[BPB_FAT32_extFlags] & 0x80 ) )
|
||||
{
|
||||
// Use the active FAT
|
||||
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * (sectorBuffer[BPB_FAT32_extFlags] & 0x0F));
|
||||
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);
|
||||
partition->cache = _FAT_cache_constructor ( cacheSize, sectorsPerPage, partition->disc, startSector + partition->numberOfSectors );
|
||||
|
||||
// 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);
|
||||
partition->readOnly = !( _FAT_disc_features( disc ) & FEATURE_MEDIUM_CANWRITE );
|
||||
|
||||
// There are currently no open files on this partition
|
||||
partition->openFileCount = 0;
|
||||
@ -276,37 +307,41 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
||||
return partition;
|
||||
}
|
||||
|
||||
void _FAT_partition_destructor (PARTITION* partition) {
|
||||
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);
|
||||
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);
|
||||
_FAT_cache_destructor ( partition->cache );
|
||||
|
||||
// Unlock the partition and destroy the lock
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_lock_deinit(&partition->lock);
|
||||
_FAT_unlock( &partition->lock );
|
||||
_FAT_lock_deinit( &partition->lock );
|
||||
|
||||
// Free memory used by the partition
|
||||
_FAT_mem_free (partition);
|
||||
_FAT_mem_free ( partition );
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_getPartitionFromPath (const char* path) {
|
||||
PARTITION* _FAT_partition_getPartitionFromPath ( const char* path )
|
||||
{
|
||||
const devoptab_t *devops;
|
||||
|
||||
devops = GetDeviceOpTab (path);
|
||||
devops = GetDeviceOpTab ( path );
|
||||
|
||||
if (!devops) {
|
||||
if ( !devops )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PARTITION*)devops->deviceData;
|
||||
return ( PARTITION* )devops->deviceData;
|
||||
}
|
||||
|
@ -40,14 +40,16 @@ extern const char* DEVICE_NAME;
|
||||
// Filesystem type
|
||||
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t fatStart;
|
||||
uint32_t sectorsPerFat;
|
||||
uint32_t lastCluster;
|
||||
uint32_t firstFree;
|
||||
} FAT;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
CACHE* cache;
|
||||
// Info about the partition
|
||||
@ -72,17 +74,17 @@ typedef struct {
|
||||
/*
|
||||
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
@ -64,7 +64,7 @@
|
||||
* 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 \
|
||||
@ -75,8 +75,8 @@
|
||||
| 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,19 +85,19 @@
|
||||
#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)
|
||||
|
||||
/* standard world rights */
|
||||
/* standard world rights */
|
||||
|
||||
#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \
|
||||
| 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)
|
||||
@ -122,7 +122,8 @@ typedef char BIGSID[40];
|
||||
* (private to this module)
|
||||
*/
|
||||
|
||||
struct MAPLIST {
|
||||
struct MAPLIST
|
||||
{
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
@ -130,7 +131,7 @@ struct MAPLIST {
|
||||
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
|
||||
@ -143,57 +144,57 @@ extern const SID *worldsid;
|
||||
* 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);
|
||||
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[],
|
||||
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);
|
||||
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 */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -49,7 +49,8 @@ extern ntfschar TXF_DATA[10];
|
||||
*
|
||||
* TODO: Describe them.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
@ -75,7 +76,8 @@ typedef enum {
|
||||
* any modification of the search context, to automagically get the next
|
||||
* matching attribute.
|
||||
*/
|
||||
struct _ntfs_attr_search_ctx {
|
||||
struct _ntfs_attr_search_ctx
|
||||
{
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
BOOL is_first;
|
||||
@ -86,20 +88,20 @@ struct _ntfs_attr_search_ctx {
|
||||
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,
|
||||
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);
|
||||
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
|
||||
@ -126,10 +128,10 @@ extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||
* // 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,7 +176,8 @@ 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 {
|
||||
struct _ntfs_attr
|
||||
{
|
||||
runlist_element *rl;
|
||||
ntfs_inode *ni;
|
||||
ATTR_TYPES type;
|
||||
@ -196,7 +199,8 @@ struct _ntfs_attr {
|
||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
||||
* structure
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
NA_NonResident, /* 1: Attribute is not resident. */
|
||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
@ -233,9 +237,9 @@ 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,7 +247,8 @@ GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
||||
*
|
||||
* For convenience. Used in the attr structure.
|
||||
*/
|
||||
typedef union {
|
||||
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;
|
||||
@ -265,73 +270,73 @@ typedef union {
|
||||
EFS_ATTR_HEADER efs;
|
||||
} attr_val;
|
||||
|
||||
extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
|
||||
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);
|
||||
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,
|
||||
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,
|
||||
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);
|
||||
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
|
||||
@ -344,7 +349,7 @@ 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
|
||||
@ -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
@ -58,36 +58,40 @@
|
||||
* 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;
|
||||
|
||||
if (!ni) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
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");
|
||||
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");
|
||||
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)
|
||||
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));
|
||||
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -104,7 +108,7 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
* 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;
|
||||
@ -113,122 +117,132 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
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");
|
||||
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)
|
||||
if ( ni->nr_extents == -1 )
|
||||
ni = ni->base_ni;
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
ntfs_log_trace("Attribute list isn't present.\n");
|
||||
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)
|
||||
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) {
|
||||
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)) :
|
||||
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)) {
|
||||
( 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) {
|
||||
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);
|
||||
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 {
|
||||
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
|
||||
le16_to_cpu( ctx->al_entry->length ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for real errors. */
|
||||
if (errno != ENOENT) {
|
||||
if ( errno != ENOENT )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
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);
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
|
||||
/* Determine new entry offset. */
|
||||
entry_offset = ((u8 *)ale - ni->attr_list);
|
||||
entry_offset = ( ( u8 * )ale - ni->attr_list );
|
||||
/* Set pointer to new entry. */
|
||||
ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset);
|
||||
ale = ( ATTR_LIST_ENTRY * )( new_al + entry_offset );
|
||||
/* Zero it to fix valgrind warning. */
|
||||
memset(ale, 0, entry_len);
|
||||
memset( ale, 0, entry_len );
|
||||
/* Form new entry. */
|
||||
ale->type = attr->type;
|
||||
ale->length = cpu_to_le16(entry_len);
|
||||
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->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));
|
||||
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) {
|
||||
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");
|
||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
|
||||
if ( ntfs_attr_truncate( na, ni->attr_list_size + entry_len ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
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);
|
||||
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);
|
||||
free( ni->attr_list );
|
||||
ni->attr_list = new_al;
|
||||
ni->attr_list_size = ni->attr_list_size + entry_len;
|
||||
NInoAttrListSetDirty(ni);
|
||||
NInoAttrListSetDirty( ni );
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
ntfs_attr_close( na );
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
free( new_al );
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
@ -241,7 +255,7 @@ err_out:
|
||||
*
|
||||
* 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;
|
||||
@ -250,65 +264,69 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
int err;
|
||||
|
||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
if ( !ctx || !ctx->ntfs_ino || !ctx->al_entry )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->base_ntfs_ino)
|
||||
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");
|
||||
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)
|
||||
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) {
|
||||
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");
|
||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, new_al_len)) {
|
||||
if ( ntfs_attr_truncate( na, new_al_len ) )
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
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));
|
||||
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);
|
||||
free( base_ni->attr_list );
|
||||
base_ni->attr_list = new_al;
|
||||
base_ni->attr_list_size = new_al_len;
|
||||
NInoAttrListSetDirty(base_ni);
|
||||
NInoAttrListSetDirty( base_ni );
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
ntfs_attr_close( na );
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
free( new_al );
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
@ -26,10 +26,10 @@
|
||||
|
||||
#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
|
||||
@ -40,12 +40,12 @@ extern int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx);
|
||||
*
|
||||
* 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);
|
||||
if ( ni->nr_extents == -1 )
|
||||
NInoAttrListSetDirty( ni->base_ni );
|
||||
else
|
||||
NInoAttrListSetDirty(ni);
|
||||
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
|
||||
|
@ -53,14 +53,14 @@
|
||||
*
|
||||
* 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)
|
||||
if ( !bitmap || new_value > 1 )
|
||||
return;
|
||||
if (!new_value)
|
||||
bitmap[bit >> 3] &= ~(1 << (bit & 7));
|
||||
if ( !new_value )
|
||||
bitmap[bit >> 3] &= ~( 1 << ( bit & 7 ) );
|
||||
else
|
||||
bitmap[bit >> 3] |= (1 << (bit & 7));
|
||||
bitmap[bit >> 3] |= ( 1 << ( bit & 7 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,11 +71,11 @@ void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
* 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)
|
||||
if ( !bitmap )
|
||||
return -1;
|
||||
return (bitmap[bit >> 3] >> (bit & 7)) & 1;
|
||||
return ( bitmap[bit >> 3] >> ( bit & 7 ) ) & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,15 +87,15 @@ char ntfs_bit_get(const u8 *bitmap, const u64 bit)
|
||||
* 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;
|
||||
|
||||
if (!bitmap || new_value > 1)
|
||||
if ( !bitmap || new_value > 1 )
|
||||
return -1;
|
||||
shift = bit & 7;
|
||||
old_bit = (bitmap[bit >> 3] >> shift) & 1;
|
||||
if (new_value != old_bit)
|
||||
old_bit = ( bitmap[bit >> 3] >> shift ) & 1;
|
||||
if ( new_value != old_bit )
|
||||
bitmap[bit >> 3] ^= 1 << shift;
|
||||
return old_bit;
|
||||
}
|
||||
@ -112,95 +112,105 @@ char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
*
|
||||
* 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;
|
||||
|
||||
if (!na || start_bit < 0 || count < 0) {
|
||||
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);
|
||||
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)
|
||||
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 = ( ( count - ( bit ? 8 - bit : 0 ) + 7 ) >> 3 ) + firstbyte;
|
||||
if ( bufsize > 8192 )
|
||||
bufsize = 8192;
|
||||
|
||||
buf = ntfs_malloc(bufsize);
|
||||
if (!buf)
|
||||
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);
|
||||
memset( buf, value ? 0xff : 0, bufsize );
|
||||
|
||||
/* If there is a first partial byte... */
|
||||
if (bit) {
|
||||
if ( bit )
|
||||
{
|
||||
/* read it in... */
|
||||
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
||||
if (br != 1) {
|
||||
if (br >= 0)
|
||||
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)
|
||||
while ( ( bit & 7 ) && count-- )
|
||||
{
|
||||
if ( value )
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
*buf &= ~(1 << bit++);
|
||||
*buf &= ~( 1 << bit++ );
|
||||
}
|
||||
/* Update @start_bit to the new position. */
|
||||
start_bit = (start_bit + 7) & ~7;
|
||||
start_bit = ( start_bit + 7 ) & ~7;
|
||||
}
|
||||
|
||||
/* Loop until @count reaches zero. */
|
||||
lastbyte = 0;
|
||||
lastbyte_buf = NULL;
|
||||
bit = count & 7;
|
||||
do {
|
||||
do
|
||||
{
|
||||
/* If there is a last partial byte... */
|
||||
if (count > 0 && bit) {
|
||||
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||
if (!lastbyte_pos) {
|
||||
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");
|
||||
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) {
|
||||
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) {
|
||||
br = ntfs_attr_pread( na, ( start_bit + count ) >>
|
||||
3, 1, lastbyte_buf );
|
||||
if ( br != 1 )
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if (br >= 0)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Reading of last byte "
|
||||
ntfs_log_perror( "Reading of last byte "
|
||||
"failed (%lld). Leaving inconsistent "
|
||||
"metadata", (long long)br);
|
||||
"metadata", ( long long )br );
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set/clear the appropriate bits in it. */
|
||||
while (bit && count--) {
|
||||
if (value)
|
||||
while ( bit && count-- )
|
||||
{
|
||||
if ( value )
|
||||
*lastbyte_buf |= 1 << --bit;
|
||||
else
|
||||
*lastbyte_buf &= ~(1 << --bit);
|
||||
*lastbyte_buf &= ~( 1 << --bit );
|
||||
}
|
||||
/* We don't want to come back here... */
|
||||
bit = 0;
|
||||
@ -210,21 +220,23 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
}
|
||||
|
||||
/* Write the prepared buffer to disk. */
|
||||
tmp = (start_bit >> 3) - firstbyte;
|
||||
br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
|
||||
if (br != bufsize) {
|
||||
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)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Failed to write buffer to bitmap "
|
||||
ntfs_log_perror( "Failed to write buffer to bitmap "
|
||||
"(%lld != %lld). Leaving inconsistent metadata",
|
||||
(long long)br, (long long)bufsize);
|
||||
( long long )br, ( long long )bufsize );
|
||||
goto free_err_out;
|
||||
}
|
||||
|
||||
/* Update counters. */
|
||||
tmp = (bufsize - firstbyte - lastbyte) << 3;
|
||||
if (firstbyte) {
|
||||
tmp = ( bufsize - firstbyte - lastbyte ) << 3;
|
||||
if ( firstbyte )
|
||||
{
|
||||
firstbyte = 0;
|
||||
/*
|
||||
* Re-set the partial first byte so a subsequent write
|
||||
@ -234,23 +246,25 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
}
|
||||
start_bit += tmp;
|
||||
count -= tmp;
|
||||
if (bufsize > (tmp = (count + 7) >> 3))
|
||||
if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) )
|
||||
bufsize = tmp;
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
if ( lastbyte && count != 0 )
|
||||
{
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error("Last buffer but count is not zero "
|
||||
ntfs_log_error( "Last buffer but count is not zero "
|
||||
"(%lld). Leaving inconsistent metadata.\n",
|
||||
(long long)count);
|
||||
( long long )count );
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
}
|
||||
while ( count > 0 );
|
||||
|
||||
ret = 0;
|
||||
|
||||
free_err_out:
|
||||
free(buf);
|
||||
free( buf );
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -265,14 +279,14 @@ free_err_out:
|
||||
*
|
||||
* 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;
|
||||
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
@ -287,14 +301,14 @@ int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count)
|
||||
*
|
||||
* 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;
|
||||
|
||||
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");
|
||||
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,11 +36,11 @@
|
||||
* 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
|
||||
@ -51,9 +51,9 @@ extern int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count);
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,9 +65,9 @@ static __inline__ int ntfs_bitmap_set_bit(ntfs_attr *na, s64 bit)
|
||||
*
|
||||
* 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 */
|
||||
|
@ -57,94 +57,103 @@
|
||||
*
|
||||
* 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;
|
||||
|
||||
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");
|
||||
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));
|
||||
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) {
|
||||
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);
|
||||
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) *
|
||||
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);
|
||||
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 "
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
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;
|
||||
not_ntfs:
|
||||
@ -152,11 +161,11 @@ not_ntfs:
|
||||
}
|
||||
|
||||
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
|
||||
@ -168,7 +177,7 @@ static const char *last_sector_error =
|
||||
*
|
||||
* 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;
|
||||
@ -177,97 +186,103 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
/* 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);
|
||||
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);
|
||||
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");
|
||||
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);
|
||||
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 "
|
||||
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);
|
||||
( 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);
|
||||
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;
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
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
|
||||
@ -276,7 +291,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
* mft mirror contains as many mft records as will fit into one
|
||||
* cluster.
|
||||
*/
|
||||
if (vol->cluster_size <= 4 * vol->mft_record_size)
|
||||
if ( vol->cluster_size <= 4 * vol->mft_record_size )
|
||||
vol->mftmirr_size = 4;
|
||||
else
|
||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||
|
@ -35,8 +35,8 @@
|
||||
* 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 */
|
||||
|
||||
|
@ -60,38 +60,45 @@
|
||||
* Do not call when a record has been modified (with no key change)
|
||||
*/
|
||||
|
||||
static void inserthashindex(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *current)
|
||||
static void inserthashindex( struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *current )
|
||||
{
|
||||
int h;
|
||||
struct HASH_ENTRY *link;
|
||||
struct HASH_ENTRY *first;
|
||||
|
||||
if (cache->dohash) {
|
||||
h = cache->dohash(current);
|
||||
if ((h >= 0) && (h < cache->max_hash)) {
|
||||
if ( cache->dohash )
|
||||
{
|
||||
h = cache->dohash( current );
|
||||
if ( ( h >= 0 ) && ( h < cache->max_hash ) )
|
||||
{
|
||||
/* get a free link and insert at top of hash list */
|
||||
link = cache->free_hash;
|
||||
if (link) {
|
||||
if ( link )
|
||||
{
|
||||
cache->free_hash = link->next;
|
||||
first = cache->first_hash[h];
|
||||
if (first)
|
||||
if ( first )
|
||||
link->next = first;
|
||||
else
|
||||
link->next = NULL;
|
||||
link->entry = current;
|
||||
cache->first_hash[h] = link;
|
||||
} else {
|
||||
ntfs_log_error("No more hash entries,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
cache->dohash = (cache_hash)NULL;
|
||||
}
|
||||
} else {
|
||||
ntfs_log_error("Illegal hash value,"
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "No more hash entries,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
cache->dohash = (cache_hash)NULL;
|
||||
cache->name );
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Illegal hash value,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name );
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,39 +107,47 @@ static void inserthashindex(struct CACHE_HEADER *cache,
|
||||
* Drop a hash index when a record is about to be deleted
|
||||
*/
|
||||
|
||||
static void drophashindex(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *current, int hash)
|
||||
static void drophashindex( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *current, int hash )
|
||||
{
|
||||
struct HASH_ENTRY *link;
|
||||
struct HASH_ENTRY *previous;
|
||||
|
||||
if (cache->dohash) {
|
||||
if ((hash >= 0) && (hash < cache->max_hash)) {
|
||||
if ( cache->dohash )
|
||||
{
|
||||
if ( ( hash >= 0 ) && ( hash < cache->max_hash ) )
|
||||
{
|
||||
/* find the link and unlink */
|
||||
link = cache->first_hash[hash];
|
||||
previous = (struct HASH_ENTRY*)NULL;
|
||||
while (link && (link->entry != current)) {
|
||||
previous = ( struct HASH_ENTRY* )NULL;
|
||||
while ( link && ( link->entry != current ) )
|
||||
{
|
||||
previous = link;
|
||||
link = link->next;
|
||||
}
|
||||
if (link) {
|
||||
if (previous)
|
||||
if ( link )
|
||||
{
|
||||
if ( previous )
|
||||
previous->next = link->next;
|
||||
else
|
||||
cache->first_hash[hash] = link->next;
|
||||
link->next = cache->free_hash;
|
||||
cache->free_hash = link;
|
||||
} else {
|
||||
ntfs_log_error("Bad hash list,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
cache->dohash = (cache_hash)NULL;
|
||||
}
|
||||
} else {
|
||||
ntfs_log_error("Illegal hash value,"
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Bad hash list,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
cache->dohash = (cache_hash)NULL;
|
||||
cache->name );
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Illegal hash value,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name );
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,49 +159,55 @@ static void drophashindex(struct CACHE_HEADER *cache,
|
||||
* The returned entry may be modified, but not freed
|
||||
*/
|
||||
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted, cache_compare compare)
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted, cache_compare compare )
|
||||
{
|
||||
struct CACHED_GENERIC *current;
|
||||
struct CACHED_GENERIC *previous;
|
||||
struct HASH_ENTRY *link;
|
||||
int h;
|
||||
|
||||
current = (struct CACHED_GENERIC*)NULL;
|
||||
if (cache) {
|
||||
if (cache->dohash) {
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
if ( cache )
|
||||
{
|
||||
if ( cache->dohash )
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* locate the entry if present
|
||||
*/
|
||||
h = cache->dohash(wanted);
|
||||
h = cache->dohash( wanted );
|
||||
link = cache->first_hash[h];
|
||||
while (link && compare(link->entry, wanted))
|
||||
while ( link && compare( link->entry, wanted ) )
|
||||
link = link->next;
|
||||
if (link)
|
||||
if ( link )
|
||||
current = link->entry;
|
||||
}
|
||||
if (!cache->dohash) {
|
||||
if ( !cache->dohash )
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list if no hash table
|
||||
* or if hashing has just failed
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
while (current
|
||||
&& compare(current, wanted)) {
|
||||
while ( current
|
||||
&& compare( current, wanted ) )
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
if (current) {
|
||||
if ( current )
|
||||
{
|
||||
previous = current->previous;
|
||||
cache->hits++;
|
||||
if (previous) {
|
||||
if ( previous )
|
||||
{
|
||||
/*
|
||||
* found and not at head of list, unlink from current
|
||||
* position and relink as head of list
|
||||
*/
|
||||
previous->next = current->next;
|
||||
if (current->next)
|
||||
if ( current->next )
|
||||
current->next->previous
|
||||
= current->previous;
|
||||
else
|
||||
@ -194,14 +215,14 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
= current->previous;
|
||||
current->next = cache->most_recent_entry;
|
||||
current->previous
|
||||
= (struct CACHED_GENERIC*)NULL;
|
||||
= ( struct CACHED_GENERIC* )NULL;
|
||||
cache->most_recent_entry->previous = current;
|
||||
cache->most_recent_entry = current;
|
||||
}
|
||||
}
|
||||
cache->reads++;
|
||||
}
|
||||
return (current);
|
||||
return ( current );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -209,31 +230,35 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
* returns the cache entry or NULL if not possible
|
||||
*/
|
||||
|
||||
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare)
|
||||
cache_compare compare )
|
||||
{
|
||||
struct CACHED_GENERIC *current;
|
||||
struct CACHED_GENERIC *before;
|
||||
struct HASH_ENTRY *link;
|
||||
int h;
|
||||
|
||||
current = (struct CACHED_GENERIC*)NULL;
|
||||
if (cache) {
|
||||
if (cache->dohash) {
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
if ( cache )
|
||||
{
|
||||
if ( cache->dohash )
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* find out whether the entry if present
|
||||
*/
|
||||
h = cache->dohash(item);
|
||||
h = cache->dohash( item );
|
||||
link = cache->first_hash[h];
|
||||
while (link && compare(link->entry, item))
|
||||
while ( link && compare( link->entry, item ) )
|
||||
link = link->next;
|
||||
if (link) {
|
||||
if ( link )
|
||||
{
|
||||
current = link->entry;
|
||||
}
|
||||
}
|
||||
if (!cache->dohash) {
|
||||
if ( !cache->dohash )
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list to locate the end,
|
||||
* and find out whether the entry is already in list
|
||||
@ -241,13 +266,15 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
* kept.
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
while (current
|
||||
&& compare(current, item)) {
|
||||
while ( current
|
||||
&& compare( current, item ) )
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!current) {
|
||||
if ( !current )
|
||||
{
|
||||
/*
|
||||
* Not in list, get a free entry or reuse the
|
||||
* last entry, and relink as head of list
|
||||
@ -256,54 +283,66 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
* an entry is reused.
|
||||
*/
|
||||
|
||||
if (cache->free_entry) {
|
||||
if ( cache->free_entry )
|
||||
{
|
||||
current = cache->free_entry;
|
||||
cache->free_entry = cache->free_entry->next;
|
||||
if (item->varsize) {
|
||||
if ( item->varsize )
|
||||
{
|
||||
current->variable = ntfs_malloc(
|
||||
item->varsize);
|
||||
} else
|
||||
current->variable = (void*)NULL;
|
||||
item->varsize );
|
||||
}
|
||||
else
|
||||
current->variable = ( void* )NULL;
|
||||
current->varsize = item->varsize;
|
||||
if (!cache->oldest_entry)
|
||||
if ( !cache->oldest_entry )
|
||||
cache->oldest_entry = current;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reusing the oldest entry */
|
||||
current = cache->oldest_entry;
|
||||
before = current->previous;
|
||||
before->next = (struct CACHED_GENERIC*)NULL;
|
||||
if (cache->dohash)
|
||||
drophashindex(cache,current,
|
||||
cache->dohash(current));
|
||||
if (cache->dofree)
|
||||
cache->dofree(current);
|
||||
before->next = ( struct CACHED_GENERIC* )NULL;
|
||||
if ( cache->dohash )
|
||||
drophashindex( cache, current,
|
||||
cache->dohash( current ) );
|
||||
if ( cache->dofree )
|
||||
cache->dofree( current );
|
||||
cache->oldest_entry = current->previous;
|
||||
if (item->varsize) {
|
||||
if (current->varsize)
|
||||
if ( item->varsize )
|
||||
{
|
||||
if ( current->varsize )
|
||||
current->variable = realloc(
|
||||
current->variable,
|
||||
item->varsize);
|
||||
item->varsize );
|
||||
else
|
||||
current->variable = ntfs_malloc(
|
||||
item->varsize);
|
||||
} else {
|
||||
if (current->varsize)
|
||||
free(current->variable);
|
||||
current->variable = (void*)NULL;
|
||||
item->varsize );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( current->varsize )
|
||||
free( current->variable );
|
||||
current->variable = ( void* )NULL;
|
||||
}
|
||||
current->varsize = item->varsize;
|
||||
}
|
||||
current->next = cache->most_recent_entry;
|
||||
current->previous = (struct CACHED_GENERIC*)NULL;
|
||||
if (cache->most_recent_entry)
|
||||
current->previous = ( struct CACHED_GENERIC* )NULL;
|
||||
if ( cache->most_recent_entry )
|
||||
cache->most_recent_entry->previous = current;
|
||||
cache->most_recent_entry = current;
|
||||
memcpy(current->fixed, item->fixed, cache->fixed_size);
|
||||
if (item->varsize) {
|
||||
if (current->variable) {
|
||||
memcpy(current->variable,
|
||||
item->variable, item->varsize);
|
||||
} else {
|
||||
memcpy( current->fixed, item->fixed, cache->fixed_size );
|
||||
if ( item->varsize )
|
||||
{
|
||||
if ( current->variable )
|
||||
{
|
||||
memcpy( current->variable,
|
||||
item->variable, item->varsize );
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* no more memory for variable part
|
||||
* recycle entry in free list
|
||||
@ -312,18 +351,20 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
cache->most_recent_entry = current->next;
|
||||
current->next = cache->free_entry;
|
||||
cache->free_entry = current;
|
||||
current = (struct CACHED_GENERIC*)NULL;
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
}
|
||||
} else {
|
||||
current->variable = (void*)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
current->variable = ( void* )NULL;
|
||||
current->varsize = 0;
|
||||
}
|
||||
if (cache->dohash && current)
|
||||
inserthashindex(cache,current);
|
||||
if ( cache->dohash && current )
|
||||
inserthashindex( cache, current );
|
||||
}
|
||||
cache->writes++;
|
||||
}
|
||||
return (current);
|
||||
return ( current );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -332,31 +373,31 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
* A specific function may be called for entry deletion
|
||||
*/
|
||||
|
||||
static void do_invalidate(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *current, int flags)
|
||||
static void do_invalidate( struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *current, int flags )
|
||||
{
|
||||
struct CACHED_GENERIC *previous;
|
||||
|
||||
previous = current->previous;
|
||||
if ((flags & CACHE_FREE) && cache->dofree)
|
||||
cache->dofree(current);
|
||||
if ( ( flags & CACHE_FREE ) && cache->dofree )
|
||||
cache->dofree( current );
|
||||
/*
|
||||
* Relink into free list
|
||||
*/
|
||||
if (current->next)
|
||||
if ( current->next )
|
||||
current->next->previous = current->previous;
|
||||
else
|
||||
cache->oldest_entry = current->previous;
|
||||
if (previous)
|
||||
if ( previous )
|
||||
previous->next = current->next;
|
||||
else
|
||||
cache->most_recent_entry = current->next;
|
||||
current->next = cache->free_entry;
|
||||
cache->free_entry = current;
|
||||
if (current->variable)
|
||||
free(current->variable);
|
||||
if ( current->variable )
|
||||
free( current->variable );
|
||||
current->varsize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -371,9 +412,9 @@ static void do_invalidate(struct CACHE_HEADER *cache,
|
||||
* supposed to be found.
|
||||
*/
|
||||
|
||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
int ntfs_invalidate_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item, cache_compare compare,
|
||||
int flags)
|
||||
int flags )
|
||||
{
|
||||
struct CACHED_GENERIC *current;
|
||||
struct CACHED_GENERIC *previous;
|
||||
@ -382,87 +423,100 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
int count;
|
||||
int h;
|
||||
|
||||
current = (struct CACHED_GENERIC*)NULL;
|
||||
current = ( struct CACHED_GENERIC* )NULL;
|
||||
count = 0;
|
||||
if (cache) {
|
||||
if (!(flags & CACHE_NOHASH) && cache->dohash) {
|
||||
if ( cache )
|
||||
{
|
||||
if ( !( flags & CACHE_NOHASH ) && cache->dohash )
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* find out whether the entry if present
|
||||
*/
|
||||
h = cache->dohash(item);
|
||||
h = cache->dohash( item );
|
||||
link = cache->first_hash[h];
|
||||
while (link) {
|
||||
if (compare(link->entry, item))
|
||||
while ( link )
|
||||
{
|
||||
if ( compare( link->entry, item ) )
|
||||
link = link->next;
|
||||
else {
|
||||
else
|
||||
{
|
||||
current = link->entry;
|
||||
link = link->next;
|
||||
if (current) {
|
||||
drophashindex(cache,current,h);
|
||||
do_invalidate(cache,
|
||||
current,flags);
|
||||
if ( current )
|
||||
{
|
||||
drophashindex( cache, current, h );
|
||||
do_invalidate( cache,
|
||||
current, flags );
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & CACHE_NOHASH) || !cache->dohash) {
|
||||
if ( ( flags & CACHE_NOHASH ) || !cache->dohash )
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
previous = (struct CACHED_GENERIC*)NULL;
|
||||
while (current) {
|
||||
if (!compare(current, item)) {
|
||||
previous = ( struct CACHED_GENERIC* )NULL;
|
||||
while ( current )
|
||||
{
|
||||
if ( !compare( current, item ) )
|
||||
{
|
||||
next = current->next;
|
||||
if (cache->dohash)
|
||||
drophashindex(cache,current,
|
||||
cache->dohash(current));
|
||||
do_invalidate(cache,current,flags);
|
||||
if ( cache->dohash )
|
||||
drophashindex( cache, current,
|
||||
cache->dohash( current ) );
|
||||
do_invalidate( cache, current, flags );
|
||||
current = next;
|
||||
count++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = current;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (count);
|
||||
return ( count );
|
||||
}
|
||||
|
||||
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags)
|
||||
int ntfs_remove_cache( struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags )
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
if (cache) {
|
||||
if (cache->dohash)
|
||||
drophashindex(cache,item,cache->dohash(item));
|
||||
do_invalidate(cache,item,flags);
|
||||
if ( cache )
|
||||
{
|
||||
if ( cache->dohash )
|
||||
drophashindex( cache, item, cache->dohash( item ) );
|
||||
do_invalidate( cache, item, flags );
|
||||
count++;
|
||||
}
|
||||
return (count);
|
||||
return ( count );
|
||||
}
|
||||
|
||||
/*
|
||||
* Free memory allocated to a cache
|
||||
*/
|
||||
|
||||
static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
||||
static void ntfs_free_cache( struct CACHE_HEADER *cache )
|
||||
{
|
||||
struct CACHED_GENERIC *entry;
|
||||
|
||||
if (cache) {
|
||||
for (entry=cache->most_recent_entry; entry; entry=entry->next) {
|
||||
if (cache->dofree)
|
||||
cache->dofree(entry);
|
||||
if (entry->variable)
|
||||
free(entry->variable);
|
||||
if ( cache )
|
||||
{
|
||||
for ( entry = cache->most_recent_entry; entry; entry = entry->next )
|
||||
{
|
||||
if ( cache->dofree )
|
||||
cache->dofree( entry );
|
||||
if ( entry->variable )
|
||||
free( entry->variable );
|
||||
}
|
||||
free(cache);
|
||||
free( cache );
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,10 +526,10 @@ static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
||||
* Returns the cache header, or NULL if the cache could not be created
|
||||
*/
|
||||
|
||||
static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
static struct CACHE_HEADER *ntfs_create_cache( const char *name,
|
||||
cache_free dofree, cache_hash dohash,
|
||||
int full_item_size,
|
||||
int item_count, int max_hash)
|
||||
int item_count, int max_hash )
|
||||
{
|
||||
struct CACHE_HEADER *cache;
|
||||
struct CACHED_GENERIC *pc;
|
||||
@ -486,68 +540,78 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
size = sizeof(struct CACHE_HEADER) + item_count*full_item_size;
|
||||
if (max_hash)
|
||||
size += item_count*sizeof(struct HASH_ENTRY)
|
||||
+ max_hash*sizeof(struct HASH_ENTRY*);
|
||||
cache = (struct CACHE_HEADER*)ntfs_malloc(size);
|
||||
if (cache) {
|
||||
size = sizeof( struct CACHE_HEADER ) + item_count*full_item_size;
|
||||
if ( max_hash )
|
||||
size += item_count*sizeof( struct HASH_ENTRY )
|
||||
+ max_hash*sizeof( struct HASH_ENTRY* );
|
||||
cache = ( struct CACHE_HEADER* )ntfs_malloc( size );
|
||||
if ( cache )
|
||||
{
|
||||
/* header */
|
||||
cache->name = name;
|
||||
cache->dofree = dofree;
|
||||
if (dohash && max_hash) {
|
||||
if ( dohash && max_hash )
|
||||
{
|
||||
cache->dohash = dohash;
|
||||
cache->max_hash = max_hash;
|
||||
} else {
|
||||
cache->dohash = (cache_hash)NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->dohash = ( cache_hash )NULL;
|
||||
cache->max_hash = 0;
|
||||
}
|
||||
cache->fixed_size = full_item_size - sizeof(struct CACHED_GENERIC);
|
||||
cache->fixed_size = full_item_size - sizeof( struct CACHED_GENERIC );
|
||||
cache->reads = 0;
|
||||
cache->writes = 0;
|
||||
cache->hits = 0;
|
||||
/* chain the data entries, and mark an invalid entry */
|
||||
cache->most_recent_entry = (struct CACHED_GENERIC*)NULL;
|
||||
cache->oldest_entry = (struct CACHED_GENERIC*)NULL;
|
||||
cache->most_recent_entry = ( struct CACHED_GENERIC* )NULL;
|
||||
cache->oldest_entry = ( struct CACHED_GENERIC* )NULL;
|
||||
cache->free_entry = &cache->entry[0];
|
||||
pc = &cache->entry[0];
|
||||
for (i=0; i<(item_count - 1); i++) {
|
||||
qc = (struct CACHED_GENERIC*)((char*)pc
|
||||
+ full_item_size);
|
||||
for ( i = 0; i < ( item_count - 1 ); i++ )
|
||||
{
|
||||
qc = ( struct CACHED_GENERIC* )( ( char* )pc
|
||||
+ full_item_size );
|
||||
pc->next = qc;
|
||||
pc->variable = (void*)NULL;
|
||||
pc->variable = ( void* )NULL;
|
||||
pc->varsize = 0;
|
||||
pc = qc;
|
||||
}
|
||||
/* special for the last entry */
|
||||
pc->next = (struct CACHED_GENERIC*)NULL;
|
||||
pc->variable = (void*)NULL;
|
||||
pc->next = ( struct CACHED_GENERIC* )NULL;
|
||||
pc->variable = ( void* )NULL;
|
||||
pc->varsize = 0;
|
||||
|
||||
if (max_hash) {
|
||||
if ( max_hash )
|
||||
{
|
||||
/* chain the hash entries */
|
||||
ph = (struct HASH_ENTRY*)(((char*)pc) + full_item_size);
|
||||
ph = ( struct HASH_ENTRY* )( ( ( char* )pc ) + full_item_size );
|
||||
cache->free_hash = ph;
|
||||
for (i=0; i<(item_count - 1); i++) {
|
||||
for ( i = 0; i < ( item_count - 1 ); i++ )
|
||||
{
|
||||
qh = &ph[1];
|
||||
ph->next = qh;
|
||||
ph = qh;
|
||||
}
|
||||
/* special for the last entry */
|
||||
if (item_count) {
|
||||
ph->next = (struct HASH_ENTRY*)NULL;
|
||||
if ( item_count )
|
||||
{
|
||||
ph->next = ( struct HASH_ENTRY* )NULL;
|
||||
}
|
||||
/* create and initialize the hash indexes */
|
||||
px = (struct HASH_ENTRY**)&ph[1];
|
||||
px = ( struct HASH_ENTRY** ) & ph[1];
|
||||
cache->first_hash = px;
|
||||
for (i=0; i<max_hash; i++)
|
||||
px[i] = (struct HASH_ENTRY*)NULL;
|
||||
} else {
|
||||
cache->free_hash = (struct HASH_ENTRY*)NULL;
|
||||
cache->first_hash = (struct HASH_ENTRY**)NULL;
|
||||
for ( i = 0; i < max_hash; i++ )
|
||||
px[i] = ( struct HASH_ENTRY* )NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->free_hash = ( struct HASH_ENTRY* )NULL;
|
||||
cache->first_hash = ( struct HASH_ENTRY** )NULL;
|
||||
}
|
||||
}
|
||||
return (cache);
|
||||
return ( cache );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -557,33 +621,33 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
* just be not available
|
||||
*/
|
||||
|
||||
void ntfs_create_lru_caches(ntfs_volume *vol)
|
||||
void ntfs_create_lru_caches( ntfs_volume *vol )
|
||||
{
|
||||
#if CACHE_INODE_SIZE
|
||||
/* inode cache */
|
||||
vol->xinode_cache = ntfs_create_cache("inode",(cache_free)NULL,
|
||||
ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
|
||||
CACHE_INODE_SIZE, 2*CACHE_INODE_SIZE);
|
||||
vol->xinode_cache = ntfs_create_cache( "inode", ( cache_free )NULL,
|
||||
ntfs_dir_inode_hash, sizeof( struct CACHED_INODE ),
|
||||
CACHE_INODE_SIZE, 2 * CACHE_INODE_SIZE );
|
||||
#endif
|
||||
#if CACHE_NIDATA_SIZE
|
||||
/* idata cache */
|
||||
vol->nidata_cache = ntfs_create_cache("nidata",
|
||||
vol->nidata_cache = ntfs_create_cache( "nidata",
|
||||
ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
|
||||
sizeof(struct CACHED_NIDATA),
|
||||
CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE);
|
||||
sizeof( struct CACHED_NIDATA ),
|
||||
CACHE_NIDATA_SIZE, 2 * CACHE_NIDATA_SIZE );
|
||||
#endif
|
||||
#if CACHE_LOOKUP_SIZE
|
||||
/* lookup cache */
|
||||
vol->lookup_cache = ntfs_create_cache("lookup",
|
||||
(cache_free)NULL, ntfs_dir_lookup_hash,
|
||||
sizeof(struct CACHED_LOOKUP),
|
||||
CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE);
|
||||
vol->lookup_cache = ntfs_create_cache( "lookup",
|
||||
( cache_free )NULL, ntfs_dir_lookup_hash,
|
||||
sizeof( struct CACHED_LOOKUP ),
|
||||
CACHE_LOOKUP_SIZE, 2 * CACHE_LOOKUP_SIZE );
|
||||
#endif
|
||||
vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL,
|
||||
(cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
|
||||
vol->securid_cache = ntfs_create_cache( "securid", ( cache_free )NULL,
|
||||
( cache_hash )NULL, sizeof( struct CACHED_SECURID ), CACHE_SECURID_SIZE, 0 );
|
||||
#if CACHE_LEGACY_SIZE
|
||||
vol->legacy_cache = ntfs_create_cache("legacy",(cache_free)NULL,
|
||||
(cache_hash)NULL, sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0);
|
||||
vol->legacy_cache = ntfs_create_cache( "legacy", ( cache_free )NULL,
|
||||
( cache_hash )NULL, sizeof( struct CACHED_PERMISSIONS_LEGACY ), CACHE_LEGACY_SIZE, 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -591,19 +655,19 @@ void ntfs_create_lru_caches(ntfs_volume *vol)
|
||||
* Free all LRU caches
|
||||
*/
|
||||
|
||||
void ntfs_free_lru_caches(ntfs_volume *vol)
|
||||
void ntfs_free_lru_caches( ntfs_volume *vol )
|
||||
{
|
||||
#if CACHE_INODE_SIZE
|
||||
ntfs_free_cache(vol->xinode_cache);
|
||||
ntfs_free_cache( vol->xinode_cache );
|
||||
#endif
|
||||
#if CACHE_NIDATA_SIZE
|
||||
ntfs_free_cache(vol->nidata_cache);
|
||||
ntfs_free_cache( vol->nidata_cache );
|
||||
#endif
|
||||
#if CACHE_LOOKUP_SIZE
|
||||
ntfs_free_cache(vol->lookup_cache);
|
||||
ntfs_free_cache( vol->lookup_cache );
|
||||
#endif
|
||||
ntfs_free_cache(vol->securid_cache);
|
||||
ntfs_free_cache( vol->securid_cache );
|
||||
#if CACHE_LEGACY_SIZE
|
||||
ntfs_free_cache(vol->legacy_cache);
|
||||
ntfs_free_cache( vol->legacy_cache );
|
||||
#endif
|
||||
}
|
||||
|
@ -24,19 +24,22 @@
|
||||
|
||||
#include "volume.h"
|
||||
|
||||
struct CACHED_GENERIC {
|
||||
struct CACHED_GENERIC
|
||||
{
|
||||
struct CACHED_GENERIC *next;
|
||||
struct CACHED_GENERIC *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
union {
|
||||
union
|
||||
{
|
||||
/* force alignment for pointers and u64 */
|
||||
u64 u64align;
|
||||
void *ptralign;
|
||||
} fixed[0];
|
||||
} ;
|
||||
|
||||
struct CACHED_INODE {
|
||||
struct CACHED_INODE
|
||||
{
|
||||
struct CACHED_INODE *next;
|
||||
struct CACHED_INODE *previous;
|
||||
const char *pathname;
|
||||
@ -45,7 +48,8 @@ struct CACHED_INODE {
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
struct CACHED_NIDATA {
|
||||
struct CACHED_NIDATA
|
||||
{
|
||||
struct CACHED_NIDATA *next;
|
||||
struct CACHED_NIDATA *previous;
|
||||
const char *pathname; /* not used */
|
||||
@ -55,7 +59,8 @@ struct CACHED_NIDATA {
|
||||
ntfs_inode *ni;
|
||||
} ;
|
||||
|
||||
struct CACHED_LOOKUP {
|
||||
struct CACHED_LOOKUP
|
||||
{
|
||||
struct CACHED_LOOKUP *next;
|
||||
struct CACHED_LOOKUP *previous;
|
||||
const char *name;
|
||||
@ -65,22 +70,25 @@ struct CACHED_LOOKUP {
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
enum {
|
||||
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
|
||||
{
|
||||
struct HASH_ENTRY *next;
|
||||
struct CACHED_GENERIC *entry;
|
||||
} ;
|
||||
|
||||
struct CACHE_HEADER {
|
||||
struct CACHE_HEADER
|
||||
{
|
||||
const char *name;
|
||||
struct CACHED_GENERIC *most_recent_entry;
|
||||
struct CACHED_GENERIC *oldest_entry;
|
||||
@ -97,23 +105,23 @@ struct CACHE_HEADER {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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);
|
||||
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,23 +45,27 @@
|
||||
|
||||
#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* _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) {
|
||||
if ( numberOfPages < 4 )
|
||||
{
|
||||
numberOfPages = 4;
|
||||
}
|
||||
|
||||
if (sectorsPerPage < 32) {
|
||||
if ( sectorsPerPage < 32 )
|
||||
{
|
||||
sectorsPerPage = 32;
|
||||
}
|
||||
|
||||
cache = (NTFS_CACHE*) ntfs_alloc (sizeof(NTFS_CACHE));
|
||||
if (cache == NULL) {
|
||||
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
|
||||
if ( cache == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -72,18 +76,20 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
||||
cache->sectorSize = sectorSize;
|
||||
|
||||
|
||||
cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc ( sizeof(NTFS_CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL) {
|
||||
ntfs_free (cache);
|
||||
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++) {
|
||||
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 );
|
||||
cacheEntries[i].cache = ( uint8_t* ) ntfs_align ( sectorsPerPage * cache->sectorSize );
|
||||
}
|
||||
|
||||
cache->cacheEntries = cacheEntries;
|
||||
@ -91,30 +97,33 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
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);
|
||||
_NTFS_cache_flush( cache );
|
||||
|
||||
// Free memory in reverse allocation order
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
ntfs_free (cache->cacheEntries[i].cache);
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
ntfs_free ( cache->cacheEntries[i].cache );
|
||||
}
|
||||
ntfs_free (cache->cacheEntries);
|
||||
ntfs_free (cache);
|
||||
ntfs_free ( cache->cacheEntries );
|
||||
ntfs_free ( cache );
|
||||
}
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
static u32 accessTime()
|
||||
{
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_getPage( NTFS_CACHE *cache, sec_t sector )
|
||||
{
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
@ -125,37 +134,42 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
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)) {
|
||||
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]);
|
||||
return &( cacheEntries[i] );
|
||||
}
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||
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;
|
||||
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
|
||||
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 ( next_page > cache->endOfPartition ) next_page = cache->endOfPartition;
|
||||
|
||||
if(!cache->disc->readSectors(sector,next_page-sector,cacheEntries[oldUsed].cache)) return NULL;
|
||||
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].count = next_page - sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
|
||||
return &(cacheEntries[oldUsed]);
|
||||
return &( cacheEntries[oldUsed] );
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
|
||||
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;
|
||||
@ -163,16 +177,22 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||
{
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
if ( sector > cacheEntries[i].sector )
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
@ -182,24 +202,25 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
|
||||
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;
|
||||
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;
|
||||
if ( secs_to_read > numSectors ) secs_to_read = numSectors;
|
||||
|
||||
memcpy(dest,entry->cache + (sec*cache->sectorSize),(secs_to_read*cache->sectorSize));
|
||||
memcpy( dest, entry->cache + ( sec*cache->sectorSize ), ( secs_to_read*cache->sectorSize ) );
|
||||
|
||||
dest += (secs_to_read*cache->sectorSize);
|
||||
dest += ( secs_to_read * cache->sectorSize );
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
@ -211,30 +232,32 @@ bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,voi
|
||||
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;
|
||||
|
||||
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);
|
||||
memcpy( buffer, entry->cache + ( ( sec*cache->sectorSize ) + offset ), size );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
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;
|
||||
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||
|
||||
switch(num_bytes) {
|
||||
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;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
@ -244,77 +267,81 @@ bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_
|
||||
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;
|
||||
|
||||
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);
|
||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
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) {
|
||||
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;
|
||||
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;
|
||||
|
||||
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);
|
||||
memset( entry->cache + ( sec*cache->sectorSize ), 0, cache->sectorSize );
|
||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
||||
|
||||
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;
|
||||
|
||||
while(numSectors>0)
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _NTFS_cache_findPage(cache,sector,numSectors);
|
||||
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;
|
||||
|
||||
cache->disc->writeSectors(sector,secs_to_write,src);
|
||||
src += (secs_to_write*cache->sectorSize);
|
||||
cache->disc->writeSectors( sector, secs_to_write, src );
|
||||
src += ( secs_to_write * cache->sectorSize );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
@ -322,19 +349,21 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
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);
|
||||
src += ( secs_to_write * cache->sectorSize );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
cache->disc->writeSectors(sector,numSectors,src);
|
||||
numSectors=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->disc->writeSectors( sector, numSectors, src );
|
||||
numSectors = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -343,13 +372,17 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
bool _NTFS_cache_flush ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if(cache==NULL) return true;
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -359,13 +392,15 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
||||
void _NTFS_cache_invalidate ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if(cache==NULL)
|
||||
if ( cache == NULL )
|
||||
return;
|
||||
|
||||
_NTFS_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
_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;
|
||||
|
@ -46,7 +46,8 @@
|
||||
#include <ogc/disc_io.h>
|
||||
#include <gccore.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
u64 last_access;
|
||||
@ -54,7 +55,8 @@ typedef struct {
|
||||
u8* cache;
|
||||
} NTFS_CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
@ -99,7 +101,7 @@ 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
|
||||
@ -115,21 +117,21 @@ Write a full sector to the NTFS_CACHE
|
||||
// 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,21 +52,22 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
static int ntfs_collate_binary( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
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)
|
||||
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);
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -82,29 +83,31 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
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)
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
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");
|
||||
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)
|
||||
d1 = le32_to_cpup( data1 );
|
||||
d2 = le32_to_cpup( data2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 == d2)
|
||||
else
|
||||
{
|
||||
if ( d1 == d2 )
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -114,38 +117,42 @@ 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)),
|
||||
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)
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
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");
|
||||
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;
|
||||
p1 = ( const le32* )data1;
|
||||
p2 = ( const le32* )data2;
|
||||
len = data1_len;
|
||||
do {
|
||||
d1 = le32_to_cpup(p1);
|
||||
do
|
||||
{
|
||||
d1 = le32_to_cpup( p1 );
|
||||
p1++;
|
||||
d2 = le32_to_cpup(p2);
|
||||
d2 = le32_to_cpup( p2 );
|
||||
p2++;
|
||||
} while ((d1 == d2) && ((len -= 4) > 0));
|
||||
if (d1 < d2)
|
||||
}
|
||||
while ( ( d1 == d2 ) && ( ( len -= 4 ) > 0 ) );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 == d2)
|
||||
else
|
||||
{
|
||||
if ( d1 == d2 )
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -162,44 +169,48 @@ 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)),
|
||||
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)
|
||||
const void *data2, const int data2_len )
|
||||
{
|
||||
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");
|
||||
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)
|
||||
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)
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
p1++;
|
||||
p2++;
|
||||
d1 = le32_to_cpup(p1);
|
||||
d2 = le32_to_cpup(p2);
|
||||
if (d1 < d2)
|
||||
d1 = le32_to_cpup( p1 );
|
||||
d2 = le32_to_cpup( p2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 > d2)
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -215,24 +226,24 @@ 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;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
file_name_attr1 = (const FILE_NAME_ATTR*)data1;
|
||||
file_name_attr2 = (const FILE_NAME_ATTR*)data2;
|
||||
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,
|
||||
( ntfschar* ) & file_name_attr1->file_name,
|
||||
file_name_attr1->file_name_length,
|
||||
(ntfschar*)&file_name_attr2->file_name,
|
||||
( 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);
|
||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len );
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -242,11 +253,12 @@ static int ntfs_collate_file_name(ntfs_volume *vol,
|
||||
* 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;
|
||||
|
||||
switch (cr) {
|
||||
switch ( cr )
|
||||
{
|
||||
case COLLATION_BINARY :
|
||||
collate = ntfs_collate_binary;
|
||||
break;
|
||||
@ -264,8 +276,8 @@ COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
collate = (COLLATE)NULL;
|
||||
collate = ( COLLATE )NULL;
|
||||
break;
|
||||
}
|
||||
return (collate);
|
||||
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,29 +35,34 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ffs(int x)
|
||||
int ffs( int x )
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if (!x)
|
||||
if ( !x )
|
||||
return 0;
|
||||
if (!(x & 0xffff)) {
|
||||
if ( !( x & 0xffff ) )
|
||||
{
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (!(x & 0xff)) {
|
||||
if ( !( x & 0xff ) )
|
||||
{
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (!(x & 0xf)) {
|
||||
if ( !( x & 0xf ) )
|
||||
{
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (!(x & 3)) {
|
||||
if ( !( x & 3 ) )
|
||||
{
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
if ( !( x & 1 ) )
|
||||
{
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
@ -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 daemon( int nochdir, int noclose )
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (fork()) {
|
||||
switch ( fork() )
|
||||
{
|
||||
case -1:
|
||||
return (-1);
|
||||
return ( -1 );
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
_exit(0);
|
||||
_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);
|
||||
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);
|
||||
return ( 0 );
|
||||
}
|
||||
/*
|
||||
* End: src/lib/libresolv2/common/bsd/daemon.c
|
||||
@ -218,27 +226,32 @@ 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 *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;;) {
|
||||
if ( ( s = *stringp ) == NULL )
|
||||
return ( NULL );
|
||||
for ( tok = s;; )
|
||||
{
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
if (c == 0)
|
||||
do
|
||||
{
|
||||
if ( ( sc = *spanp++ ) == c )
|
||||
{
|
||||
if ( c == 0 )
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
*stringp = s;
|
||||
return (tok);
|
||||
return ( tok );
|
||||
}
|
||||
} while (sc != 0);
|
||||
}
|
||||
while ( sc != 0 );
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
@ -36,15 +36,15 @@
|
||||
#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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
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);
|
||||
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 " };
|
||||
"LCN_unknown "
|
||||
};
|
||||
|
||||
ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
|
||||
if (!rl) {
|
||||
ntfs_log_debug("Run list not present.\n");
|
||||
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( "VCN LCN Run length\n" );
|
||||
do
|
||||
{
|
||||
LCN lcn = ( rl + i )->lcn;
|
||||
|
||||
if (lcn < (LCN)0) {
|
||||
if ( lcn < ( LCN )0 )
|
||||
{
|
||||
int idx = -lcn - 1;
|
||||
|
||||
if (idx > -LCN_EINVAL - 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);
|
||||
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,9 +31,9 @@
|
||||
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) \
|
||||
|
@ -103,21 +103,24 @@
|
||||
* On success return a pointer to the allocated ntfs device structure and on
|
||||
* error return NULL with errno set to the error code returned by ntfs_malloc().
|
||||
*/
|
||||
struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
struct ntfs_device_operations *dops, void *priv_data)
|
||||
struct ntfs_device *ntfs_device_alloc( const char *name, const long state,
|
||||
struct ntfs_device_operations *dops, void *priv_data )
|
||||
{
|
||||
struct ntfs_device *dev;
|
||||
|
||||
if (!name) {
|
||||
if ( !name )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = ntfs_malloc(sizeof(struct ntfs_device));
|
||||
if (dev) {
|
||||
if (!(dev->d_name = strdup(name))) {
|
||||
dev = ntfs_malloc( sizeof( struct ntfs_device ) );
|
||||
if ( dev )
|
||||
{
|
||||
if ( !( dev->d_name = strdup( name ) ) )
|
||||
{
|
||||
int eo = errno;
|
||||
free(dev);
|
||||
free( dev );
|
||||
errno = eo;
|
||||
return NULL;
|
||||
}
|
||||
@ -139,18 +142,20 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
* EINVAL Invalid pointer @dev.
|
||||
* EBUSY Device is still open. Close it before freeing it!
|
||||
*/
|
||||
int ntfs_device_free(struct ntfs_device *dev)
|
||||
int ntfs_device_free( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (NDevOpen(dev)) {
|
||||
if ( NDevOpen( dev ) )
|
||||
{
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
free(dev->d_name);
|
||||
free(dev);
|
||||
free( dev->d_name );
|
||||
free( dev );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -173,29 +178,31 @@ int ntfs_device_free(struct ntfs_device *dev)
|
||||
* to the return code of either seek, read, or set to EINVAL in case of
|
||||
* invalid arguments.
|
||||
*/
|
||||
s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
||||
s64 ntfs_pread( struct ntfs_device *dev, const s64 pos, s64 count, void *b )
|
||||
{
|
||||
s64 br, total;
|
||||
struct ntfs_device_operations *dops;
|
||||
|
||||
ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
|
||||
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
||||
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
if ( !b || count < 0 || pos < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
if ( !count )
|
||||
return 0;
|
||||
|
||||
dops = dev->d_ops;
|
||||
|
||||
for (total = 0; count; count -= br, total += br) {
|
||||
br = dops->pread(dev, (char*)b + total, count, pos + total);
|
||||
for ( total = 0; count; count -= br, total += br )
|
||||
{
|
||||
br = dops->pread( dev, ( char* )b + total, count, pos + total );
|
||||
/* If everything ok, continue. */
|
||||
if (br > 0)
|
||||
if ( br > 0 )
|
||||
continue;
|
||||
/* If EOF or error return number of bytes read. */
|
||||
if (!br || total)
|
||||
if ( !br || total )
|
||||
return total;
|
||||
/* Nothing read and error, return error status. */
|
||||
return br;
|
||||
@ -223,38 +230,41 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
||||
* appropriately to the return code of either seek, write, or set
|
||||
* to EINVAL in case of invalid arguments.
|
||||
*/
|
||||
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b)
|
||||
s64 ntfs_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b )
|
||||
{
|
||||
s64 written, total, ret = -1;
|
||||
struct ntfs_device_operations *dops;
|
||||
|
||||
ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
|
||||
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
||||
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
if ( !b || count < 0 || pos < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (!count)
|
||||
if ( !count )
|
||||
return 0;
|
||||
if (NDevReadOnly(dev)) {
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
errno = EROFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dops = dev->d_ops;
|
||||
|
||||
NDevSetDirty(dev);
|
||||
for (total = 0; count; count -= written, total += written) {
|
||||
written = dops->pwrite(dev, (const char*)b + total, count,
|
||||
pos + total);
|
||||
NDevSetDirty( dev );
|
||||
for ( total = 0; count; count -= written, total += written )
|
||||
{
|
||||
written = dops->pwrite( dev, ( const char* )b + total, count,
|
||||
pos + total );
|
||||
/* If everything ok, continue. */
|
||||
if (written > 0)
|
||||
if ( written > 0 )
|
||||
continue;
|
||||
/*
|
||||
* If nothing written or error return number of bytes written.
|
||||
*/
|
||||
if (!written || total)
|
||||
if ( !written || total )
|
||||
break;
|
||||
/* Nothing written and error, return error status. */
|
||||
total = written;
|
||||
@ -294,18 +304,19 @@ out:
|
||||
* sector transfer error. This should be detected by the caller by checking for
|
||||
* the magic being "BAAD".
|
||||
*/
|
||||
s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b)
|
||||
s64 ntfs_mst_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b )
|
||||
{
|
||||
s64 br, i;
|
||||
|
||||
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
|
||||
if ( bksize & ( bksize - 1 ) || bksize % NTFS_BLOCK_SIZE )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Do the read. */
|
||||
br = ntfs_pread(dev, pos, count * bksize, b);
|
||||
if (br < 0)
|
||||
br = ntfs_pread( dev, pos, count * bksize, b );
|
||||
if ( br < 0 )
|
||||
return br;
|
||||
/*
|
||||
* Apply fixups to successfully read data, disregarding any errors
|
||||
@ -314,9 +325,9 @@ s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
* magic will be detected later on.
|
||||
*/
|
||||
count = br / bksize;
|
||||
for (i = 0; i < count; ++i)
|
||||
ntfs_mst_post_read_fixup((NTFS_RECORD*)
|
||||
((u8*)b + i * bksize), bksize);
|
||||
for ( i = 0; i < count; ++i )
|
||||
ntfs_mst_post_read_fixup( ( NTFS_RECORD* )
|
||||
( ( u8* )b + i * bksize ), bksize );
|
||||
/* Finally, return the number of complete blocks read. */
|
||||
return count;
|
||||
}
|
||||
@ -351,37 +362,40 @@ s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
* simulating an mst read on the written data. This way cache coherency is
|
||||
* achieved.
|
||||
*/
|
||||
s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b)
|
||||
s64 ntfs_mst_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b )
|
||||
{
|
||||
s64 written, i;
|
||||
|
||||
if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
|
||||
if ( count < 0 || bksize % NTFS_BLOCK_SIZE )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
if ( !count )
|
||||
return 0;
|
||||
/* Prepare data for writing. */
|
||||
for (i = 0; i < count; ++i) {
|
||||
for ( i = 0; i < count; ++i )
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
|
||||
((u8*)b + i * bksize), bksize);
|
||||
if (err < 0) {
|
||||
err = ntfs_mst_pre_write_fixup( ( NTFS_RECORD* )
|
||||
( ( u8* )b + i * bksize ), bksize );
|
||||
if ( err < 0 )
|
||||
{
|
||||
/* Abort write at this position. */
|
||||
if (!i)
|
||||
if ( !i )
|
||||
return err;
|
||||
count = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Write the prepared data. */
|
||||
written = ntfs_pwrite(dev, pos, count * bksize, b);
|
||||
written = ntfs_pwrite( dev, pos, count * bksize, b );
|
||||
/* Quickly deprotect the data again. */
|
||||
for (i = 0; i < count; ++i)
|
||||
ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
|
||||
if (written <= 0)
|
||||
for ( i = 0; i < count; ++i )
|
||||
ntfs_mst_post_write_fixup( ( NTFS_RECORD* )( ( u8* )b + i * bksize ) );
|
||||
if ( written <= 0 )
|
||||
return written;
|
||||
/* Finally, return the number of complete blocks written. */
|
||||
return written / bksize;
|
||||
@ -398,26 +412,29 @@ s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
* volume @vol into buffer @b. Return number of clusters read or -1 on error,
|
||||
* with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
||||
void *b)
|
||||
s64 ntfs_cluster_read( const ntfs_volume *vol, const s64 lcn, const s64 count,
|
||||
void *b )
|
||||
{
|
||||
s64 br;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
if ( !vol || lcn < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
if ( vol->nr_clusters < lcn + count )
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror("Trying to read outside of volume "
|
||||
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||
(long long)lcn + count);
|
||||
ntfs_log_perror( "Trying to read outside of volume "
|
||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
||||
( long long )lcn + count );
|
||||
return -1;
|
||||
}
|
||||
br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b);
|
||||
if (br < 0) {
|
||||
ntfs_log_perror("Error reading cluster(s)");
|
||||
br = ntfs_pread( vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b );
|
||||
if ( br < 0 )
|
||||
{
|
||||
ntfs_log_perror( "Error reading cluster(s)" );
|
||||
return br;
|
||||
}
|
||||
return br >> vol->cluster_size_bits;
|
||||
@ -434,29 +451,32 @@ s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
||||
* buffer @b to volume @vol. Return the number of clusters written or -1 on
|
||||
* error, with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b)
|
||||
s64 ntfs_cluster_write( const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b )
|
||||
{
|
||||
s64 bw;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
if ( !vol || lcn < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
if ( vol->nr_clusters < lcn + count )
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror("Trying to write outside of volume "
|
||||
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||
(long long)lcn + count);
|
||||
ntfs_log_perror( "Trying to write outside of volume "
|
||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
||||
( long long )lcn + count );
|
||||
return -1;
|
||||
}
|
||||
if (!NVolReadOnly(vol))
|
||||
bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b);
|
||||
if ( !NVolReadOnly( vol ) )
|
||||
bw = ntfs_pwrite( vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b );
|
||||
else
|
||||
bw = count << vol->cluster_size_bits;
|
||||
if (bw < 0) {
|
||||
ntfs_log_perror("Error writing cluster(s)");
|
||||
if ( bw < 0 )
|
||||
{
|
||||
ntfs_log_perror( "Error writing cluster(s)" );
|
||||
return bw;
|
||||
}
|
||||
return bw >> vol->cluster_size_bits;
|
||||
@ -472,12 +492,12 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
*
|
||||
* Return 0 if it is valid and -1 if it is not valid.
|
||||
*/
|
||||
static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
|
||||
static int ntfs_device_offset_valid( struct ntfs_device *dev, s64 ofs )
|
||||
{
|
||||
char ch;
|
||||
|
||||
if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
|
||||
dev->d_ops->read(dev, &ch, 1) == 1)
|
||||
if ( dev->d_ops->seek( dev, ofs, SEEK_SET ) >= 0 &&
|
||||
dev->d_ops->read( dev, &ch, 1 ) == 1 )
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
@ -494,43 +514,47 @@ static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
|
||||
*
|
||||
* On error return -1 with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
s64 ntfs_device_size_get( struct ntfs_device *dev, int block_size )
|
||||
{
|
||||
s64 high, low;
|
||||
|
||||
if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
|
||||
if ( !dev || block_size <= 0 || ( block_size - 1 ) & block_size )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKGETSIZE64
|
||||
{ u64 size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
|
||||
ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||
(unsigned long long)size,
|
||||
(unsigned long long)size);
|
||||
return (s64)size / block_size;
|
||||
if ( dev->d_ops->ioctl( dev, BLKGETSIZE64, &size ) >= 0 )
|
||||
{
|
||||
ntfs_log_debug( "BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||
( unsigned long long )size,
|
||||
( unsigned long long )size );
|
||||
return ( s64 )size / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef BLKGETSIZE
|
||||
{ unsigned long size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
|
||||
ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
size, size);
|
||||
return (s64)size * 512 / block_size;
|
||||
if ( dev->d_ops->ioctl( dev, BLKGETSIZE, &size ) >= 0 )
|
||||
{
|
||||
ntfs_log_debug( "BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
size, size );
|
||||
return ( s64 )size * 512 / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef FDGETPRM
|
||||
{ struct floppy_struct this_floppy;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
|
||||
ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
(unsigned long)this_floppy.size,
|
||||
(unsigned long)this_floppy.size);
|
||||
return (s64)this_floppy.size * 512 / block_size;
|
||||
if ( dev->d_ops->ioctl( dev, FDGETPRM, &this_floppy ) >= 0 )
|
||||
{
|
||||
ntfs_log_debug( "FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
( unsigned long )this_floppy.size,
|
||||
( unsigned long )this_floppy.size );
|
||||
return ( s64 )this_floppy.size * 512 / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -539,18 +563,19 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
* so do binary search to find the size of the device.
|
||||
*/
|
||||
low = 0LL;
|
||||
for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
|
||||
for ( high = 1024LL; !ntfs_device_offset_valid( dev, high ); high <<= 1 )
|
||||
low = high;
|
||||
while (low < high - 1LL) {
|
||||
const s64 mid = (low + high) / 2;
|
||||
while ( low < high - 1LL )
|
||||
{
|
||||
const s64 mid = ( low + high ) / 2;
|
||||
|
||||
if (!ntfs_device_offset_valid(dev, mid))
|
||||
if ( !ntfs_device_offset_valid( dev, mid ) )
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
dev->d_ops->seek(dev, 0LL, SEEK_SET);
|
||||
return (low + 1LL) / block_size;
|
||||
dev->d_ops->seek( dev, 0LL, SEEK_SET );
|
||||
return ( low + 1LL ) / block_size;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -565,18 +590,20 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||
*/
|
||||
s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
|
||||
s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ struct hd_geometry geo;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||
ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
||||
geo.start, geo.start);
|
||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||
{
|
||||
ntfs_log_debug( "HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
||||
geo.start, geo.start );
|
||||
return geo.start;
|
||||
}
|
||||
}
|
||||
@ -598,19 +625,21 @@ s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
|
||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||
*/
|
||||
int ntfs_device_heads_get(struct ntfs_device *dev)
|
||||
int ntfs_device_heads_get( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ struct hd_geometry geo;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||
ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
|
||||
(unsigned)geo.heads,
|
||||
(unsigned)geo.heads);
|
||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||
{
|
||||
ntfs_log_debug( "HDIO_GETGEO heads = %u (0x%x)\n",
|
||||
( unsigned )geo.heads,
|
||||
( unsigned )geo.heads );
|
||||
return geo.heads;
|
||||
}
|
||||
}
|
||||
@ -632,19 +661,21 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
|
||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||
*/
|
||||
int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
|
||||
int ntfs_device_sectors_per_track_get( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ struct hd_geometry geo;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||
ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
||||
(unsigned)geo.sectors,
|
||||
(unsigned)geo.sectors);
|
||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
||||
{
|
||||
ntfs_log_debug( "HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
||||
( unsigned )geo.sectors,
|
||||
( unsigned )geo.sectors );
|
||||
return geo.sectors;
|
||||
}
|
||||
}
|
||||
@ -666,9 +697,10 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
|
||||
* EOPNOTSUPP System does not support BLKSSZGET ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting BLKSSZGET
|
||||
*/
|
||||
int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
||||
int ntfs_device_sector_size_get( struct ntfs_device *dev )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -676,9 +708,10 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
||||
{
|
||||
int sect_size = 0;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) {
|
||||
ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
|
||||
sect_size);
|
||||
if ( !dev->d_ops->ioctl( dev, BLKSSZGET, §_size ) )
|
||||
{
|
||||
ntfs_log_debug( "BLKSSZGET sector size = %d bytes\n",
|
||||
sect_size );
|
||||
return sect_size;
|
||||
}
|
||||
}
|
||||
@ -701,28 +734,30 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
||||
* EOPNOTSUPP System does not support BLKBSZSET ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting BLKBSZSET
|
||||
*/
|
||||
int ntfs_device_block_size_set(struct ntfs_device *dev,
|
||||
int block_size __attribute__((unused)))
|
||||
int ntfs_device_block_size_set( struct ntfs_device *dev,
|
||||
int block_size __attribute__( ( unused ) ) )
|
||||
{
|
||||
if (!dev) {
|
||||
if ( !dev )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKBSZSET
|
||||
{
|
||||
size_t s_block_size = block_size;
|
||||
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
|
||||
ntfs_log_debug("Used BLKBSZSET to set block size to "
|
||||
"%d bytes.\n", block_size);
|
||||
if ( !dev->d_ops->ioctl( dev, BLKBSZSET, &s_block_size ) )
|
||||
{
|
||||
ntfs_log_debug( "Used BLKBSZSET to set block size to "
|
||||
"%d bytes.\n", block_size );
|
||||
return 0;
|
||||
}
|
||||
/* If not a block device, pretend it was successful. */
|
||||
if (!NDevBlock(dev))
|
||||
if ( !NDevBlock( dev ) )
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* If not a block device, pretend it was successful. */
|
||||
if (!NDevBlock(dev))
|
||||
if ( !NDevBlock( dev ) )
|
||||
return 0;
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
|
@ -36,7 +36,8 @@
|
||||
*
|
||||
* Defined bits for the state field in the ntfs_device structure.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ND_Open, /* 1: Device is open. */
|
||||
ND_ReadOnly, /* 1: Device is read-only. */
|
||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||
@ -69,7 +70,8 @@ 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
|
||||
{
|
||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||
unsigned long d_state; /* State of the device. */
|
||||
char *d_name; /* Name of device. */
|
||||
@ -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 */
|
||||
|
@ -45,7 +45,8 @@
|
||||
/**
|
||||
* struct hd_geometry -
|
||||
*/
|
||||
struct hd_geometry {
|
||||
struct hd_geometry
|
||||
{
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
|
2199
source/libntfs/dir.c
2199
source/libntfs/dir.c
File diff suppressed because it is too large
Load Diff
@ -59,27 +59,27 @@ 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,
|
||||
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);
|
||||
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>)
|
||||
@ -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,
|
||||
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);
|
||||
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
|
||||
|
||||
|
@ -60,12 +60,13 @@
|
||||
|
||||
#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 )
|
||||
} ;
|
||||
|
||||
|
||||
@ -73,51 +74,64 @@ static ntfschar logged_utility_stream_name[] = {
|
||||
* 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;
|
||||
|
||||
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 {
|
||||
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) {
|
||||
}
|
||||
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"
|
||||
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);
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
ntfs_log_trace("Inode %lld is not encrypted\n",
|
||||
(long long)ni->mft_no);
|
||||
ntfs_log_trace( "Inode %lld is not encrypted\n",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
}
|
||||
return (attr_size ? (int)attr_size : -errno);
|
||||
return ( attr_size ? ( int )attr_size : -errno );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -133,7 +147,7 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
||||
* -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;
|
||||
@ -145,66 +159,80 @@ static int fixup_loop(ntfs_inode *ni)
|
||||
int res = 0;
|
||||
|
||||
maxcnt = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
restart = FALSE;
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
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)) {
|
||||
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");
|
||||
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)) {
|
||||
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)) {
|
||||
if ( ntfs_attr_force_non_resident( na ) )
|
||||
{
|
||||
res = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* make sure there is some progress */
|
||||
if (cnt <= maxcnt) {
|
||||
if ( cnt <= maxcnt )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_error("Multiple failure"
|
||||
" making non resident\n");
|
||||
ntfs_log_error( "Multiple failure"
|
||||
" making non resident\n" );
|
||||
res = -1;
|
||||
} else {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||
}
|
||||
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");
|
||||
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);
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
first = FALSE;
|
||||
} while (restart && !res);
|
||||
if (ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (res);
|
||||
}
|
||||
while ( restart && !res );
|
||||
if ( ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
return ( res );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -213,8 +241,8 @@ static int fixup_loop(ntfs_inode *ni)
|
||||
* 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;
|
||||
@ -223,91 +251,112 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
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);
|
||||
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 {
|
||||
}
|
||||
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);
|
||||
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;
|
||||
info_header = ( const EFS_ATTR_HEADER* )value;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if (le32_to_cpu(info_header->length) != size) {
|
||||
if ( le32_to_cpu( info_header->length ) != size )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
return ( -1 );
|
||||
}
|
||||
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
(ntfschar*)NULL,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
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 {
|
||||
res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4,
|
||||
( u8* )NULL, ( s64 )size );
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
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) {
|
||||
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);
|
||||
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");
|
||||
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
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
else
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
if ( !res )
|
||||
{
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_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))
|
||||
if ( fixup_loop( ni ) )
|
||||
return -1;
|
||||
}
|
||||
ni->flags |= FILE_ATTR_ENCRYPTED;
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
NInoSetDirty( ni );
|
||||
NInoFileNameSetDirty( ni );
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
return (res ? -1 : 0);
|
||||
return ( res ? -1 : 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -321,7 +370,7 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
* -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;
|
||||
@ -330,48 +379,59 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
ntfs_inode *ni;
|
||||
BOOL close_ctx = FALSE;
|
||||
|
||||
if (!na) {
|
||||
ntfs_log_error("no na specified for efs_fixup_attribute\n");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
}
|
||||
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) {
|
||||
if ( oldsize )
|
||||
{
|
||||
/* make sure size is valid for a raw encrypted stream */
|
||||
if ((oldsize & 511) != 2) {
|
||||
ntfs_log_error("Bad raw encrypted stream\n");
|
||||
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");
|
||||
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) {
|
||||
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);
|
||||
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;
|
||||
@ -380,11 +440,13 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
* 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");
|
||||
if ( ntfs_attr_truncate( na, oldsize - 2 ) )
|
||||
{
|
||||
ntfs_log_error( "Error truncating attribute\n" );
|
||||
goto err_out;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
newsize = 0;
|
||||
|
||||
/*
|
||||
@ -393,47 +455,53 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
* 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");
|
||||
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 {
|
||||
}
|
||||
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");
|
||||
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) {
|
||||
if ( !na->name_len )
|
||||
{
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
NInoSetDirty( ni );
|
||||
NInoFileNameSetDirty( ni );
|
||||
|
||||
ctx->attr->data_size = cpu_to_le64(newsize);
|
||||
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
|
||||
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);
|
||||
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 */
|
||||
|
@ -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,86 +245,92 @@ 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;
|
||||
}
|
||||
@ -319,25 +341,27 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
{
|
||||
|
||||
// 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,58 +371,65 @@ 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;
|
||||
}
|
||||
@ -407,86 +438,92 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
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,68 +600,76 @@ 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;
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE:
|
||||
{
|
||||
*( u32* )argp = fd->sectorCount;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64: {
|
||||
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64:
|
||||
{
|
||||
*( u64* )argp = ( fd->sectorCount * fd->sectorSize );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO: {
|
||||
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
||||
#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
|
||||
#endif
|
||||
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET: {
|
||||
*(int*)argp = fd->sectorSize;
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET:
|
||||
{
|
||||
*( int* )argp = fd->sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET: {
|
||||
int sectorSize = *(int*)argp;
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET:
|
||||
{
|
||||
int sectorSize = *( int* )argp;
|
||||
fd->sectorSize = sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Unimplemented ioctrl
|
||||
default: {
|
||||
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||
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,
|
||||
|
@ -33,7 +33,8 @@
|
||||
/**
|
||||
* gekko_fd - Gekko device driver descriptor
|
||||
*/
|
||||
typedef struct _gekko_fd {
|
||||
typedef struct _gekko_fd
|
||||
{
|
||||
const DISC_INTERFACE* interface; /* Device disc interface */
|
||||
sec_t startSector; /* LBA of partition start */
|
||||
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -63,8 +63,8 @@
|
||||
|
||||
#define MAX_PARENT_VCN 32
|
||||
|
||||
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
||||
const void *data2, int len2);
|
||||
typedef int ( *COLLATE )( ntfs_volume *vol, const void *data1, int len1,
|
||||
const void *data2, int len2 );
|
||||
|
||||
/**
|
||||
* struct ntfs_index_context -
|
||||
@ -112,7 +112,8 @@ typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
||||
* the call to ntfs_index_ctx_put() to ensure that the changes are written
|
||||
* to disk.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
@ -133,35 +134,35 @@ typedef struct {
|
||||
u8 vcn_size_bits;
|
||||
} ntfs_index_context;
|
||||
|
||||
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
|
||||
extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx);
|
||||
extern ntfs_index_context *ntfs_index_ctx_get( ntfs_inode *ni,
|
||||
ntfschar *name, u32 name_len );
|
||||
extern void ntfs_index_ctx_put( ntfs_index_context *ictx );
|
||||
extern void ntfs_index_ctx_reinit( ntfs_index_context *ictx );
|
||||
|
||||
extern int ntfs_index_lookup(const void *key, const int key_len,
|
||||
ntfs_index_context *ictx) __attribute_warn_unused_result__;
|
||||
extern int ntfs_index_lookup( const void *key, const int key_len,
|
||||
ntfs_index_context *ictx ) __attribute_warn_unused_result__;
|
||||
|
||||
extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie,
|
||||
ntfs_index_context *ictx);
|
||||
extern INDEX_ENTRY *ntfs_index_next( INDEX_ENTRY *ie,
|
||||
ntfs_index_context *ictx );
|
||||
|
||||
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
||||
MFT_REF mref);
|
||||
extern int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
const void *key, const int keylen);
|
||||
extern int ntfs_index_add_filename( ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
||||
MFT_REF mref );
|
||||
extern int ntfs_index_remove( ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
const void *key, const int keylen );
|
||||
|
||||
extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr);
|
||||
extern INDEX_ROOT *ntfs_index_root_get( ntfs_inode *ni, ATTR_RECORD *attr );
|
||||
|
||||
extern VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie);
|
||||
extern VCN ntfs_ie_get_vcn( INDEX_ENTRY *ie );
|
||||
|
||||
extern void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx);
|
||||
extern void ntfs_index_entry_mark_dirty( ntfs_index_context *ictx );
|
||||
|
||||
extern char *ntfs_ie_filename_get(INDEX_ENTRY *ie);
|
||||
extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie);
|
||||
extern void ntfs_ih_filename_dump(INDEX_HEADER *ih);
|
||||
extern char *ntfs_ie_filename_get( INDEX_ENTRY *ie );
|
||||
extern void ntfs_ie_filename_dump( INDEX_ENTRY *ie );
|
||||
extern void ntfs_ih_filename_dump( INDEX_HEADER *ih );
|
||||
|
||||
/* the following was added by JPA for use in security.c */
|
||||
extern int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie);
|
||||
extern int ntfs_index_rm(ntfs_index_context *icx);
|
||||
extern int ntfs_ie_add( ntfs_index_context *icx, INDEX_ENTRY *ie );
|
||||
extern int ntfs_index_rm( ntfs_index_context *icx );
|
||||
|
||||
#endif /* _NTFS_INDEX_H */
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user