mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-22 03:09:15 +01:00
* Unified formating of source files.
This commit is contained in:
parent
05825a3231
commit
772859ecbc
@ -2,8 +2,8 @@
|
|||||||
<app version="1">
|
<app version="1">
|
||||||
<name> USB Loader GX</name>
|
<name> USB Loader GX</name>
|
||||||
<coder>USB Loader GX Team</coder>
|
<coder>USB Loader GX Team</coder>
|
||||||
<version>1.0 r961</version>
|
<version>1.0 r962</version>
|
||||||
<release_date>201009222057</release_date>
|
<release_date>201009232353</release_date>
|
||||||
<short_description>Loads games from USB-devices</short_description>
|
<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.
|
<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.
|
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||||
|
@ -27,55 +27,52 @@
|
|||||||
#include "filelist.h"
|
#include "filelist.h"
|
||||||
|
|
||||||
FreeTypeGX * fontSystem = NULL;
|
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;
|
static u32 MainFontSize = font_ttf_size;
|
||||||
|
|
||||||
void ClearFontData()
|
void ClearFontData()
|
||||||
{
|
{
|
||||||
if ( fontSystem )
|
if (fontSystem) delete fontSystem;
|
||||||
delete fontSystem;
|
|
||||||
fontSystem = NULL;
|
fontSystem = NULL;
|
||||||
|
|
||||||
if ( MainFont != ( FT_Byte * ) font_ttf )
|
if (MainFont != (FT_Byte *) font_ttf)
|
||||||
{
|
{
|
||||||
if ( MainFont != NULL )
|
if (MainFont != NULL) delete[] MainFont;
|
||||||
delete [] MainFont;
|
MainFont = (FT_Byte *) font_ttf;
|
||||||
MainFont = ( FT_Byte * ) font_ttf;
|
|
||||||
MainFontSize = font_ttf_size;
|
MainFontSize = font_ttf_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetupDefaultFont( const char *path )
|
bool SetupDefaultFont(const char *path)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
FILE *pfile = NULL;
|
FILE *pfile = NULL;
|
||||||
|
|
||||||
ClearFontData();
|
ClearFontData();
|
||||||
|
|
||||||
if ( path )
|
if (path) pfile = fopen(path, "rb");
|
||||||
pfile = fopen( path, "rb" );
|
|
||||||
|
|
||||||
if ( pfile )
|
if (pfile)
|
||||||
{
|
{
|
||||||
fseek( pfile, 0, SEEK_END );
|
fseek(pfile, 0, SEEK_END);
|
||||||
MainFontSize = ftell( pfile );
|
MainFontSize = ftell(pfile);
|
||||||
rewind( pfile );
|
rewind(pfile);
|
||||||
|
|
||||||
MainFont = new ( std::nothrow ) FT_Byte[MainFontSize];
|
MainFont = new (std::nothrow) FT_Byte[MainFontSize];
|
||||||
if ( !MainFont )
|
if (!MainFont)
|
||||||
{
|
{
|
||||||
MainFont = ( FT_Byte * ) font_ttf;
|
MainFont = (FT_Byte *) font_ttf;
|
||||||
MainFontSize = font_ttf_size;
|
MainFontSize = font_ttf_size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fread( MainFont, 1, MainFontSize, pfile );
|
fread(MainFont, 1, MainFontSize, pfile);
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
fclose( pfile );
|
fclose(pfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
fontSystem = new FreeTypeGX( MainFont, MainFontSize );
|
fontSystem = new FreeTypeGX(MainFont, MainFontSize);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#ifndef FONTSYSTEM_H_
|
#ifndef FONTSYSTEM_H_
|
||||||
#define FONTSYSTEM_H_
|
#define FONTSYSTEM_H_
|
||||||
|
|
||||||
bool SetupDefaultFont( const char *path );
|
bool SetupDefaultFont(const char *path);
|
||||||
void ClearFontData();
|
void ClearFontData();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,24 +34,23 @@ using namespace std;
|
|||||||
* @return Wide character representation of supplied character string.
|
* @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;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
wchar_t *strWChar = new ( std::nothrow ) wchar_t[strlen( strChar ) + 1];
|
wchar_t *strWChar = new (std::nothrow) wchar_t[strlen(strChar) + 1];
|
||||||
if ( !strWChar )
|
if (!strWChar) return NULL;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
int bt = mbstowcs( strWChar, strChar, strlen( strChar ) );
|
int bt = mbstowcs(strWChar, strChar, strlen(strChar));
|
||||||
if ( bt > 0 )
|
if (bt > 0)
|
||||||
{
|
{
|
||||||
strWChar[bt] = 0;
|
strWChar[bt] = 0;
|
||||||
return strWChar;
|
return strWChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t *tempDest = strWChar;
|
wchar_t *tempDest = strWChar;
|
||||||
while ( ( *tempDest++ = *strChar++ ) );
|
while ((*tempDest++ = *strChar++))
|
||||||
|
;
|
||||||
|
|
||||||
return strWChar;
|
return strWChar;
|
||||||
}
|
}
|
||||||
@ -59,14 +58,14 @@ wchar_t* charToWideChar( const char* strChar )
|
|||||||
/**
|
/**
|
||||||
* Default constructor for the FreeTypeGX class for WiiXplorer.
|
* 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;
|
ftPointSize = 0;
|
||||||
|
|
||||||
FT_Init_FreeType( &ftLibrary );
|
FT_Init_FreeType(&ftLibrary);
|
||||||
FT_New_Memory_Face( ftLibrary, ( FT_Byte * )fontBuffer, bufferSize, 0, &ftFace );
|
FT_New_Memory_Face(ftLibrary, (FT_Byte *) fontBuffer, bufferSize, 0, &ftFace);
|
||||||
|
|
||||||
setVertexFormat( GX_VTXFMT1 );
|
setVertexFormat(GX_VTXFMT1);
|
||||||
ftKerningEnabled = FT_HAS_KERNING( ftFace );
|
ftKerningEnabled = FT_HAS_KERNING( ftFace );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +75,8 @@ FreeTypeGX::FreeTypeGX( const uint8_t* fontBuffer, FT_Long bufferSize )
|
|||||||
FreeTypeGX::~FreeTypeGX()
|
FreeTypeGX::~FreeTypeGX()
|
||||||
{
|
{
|
||||||
unloadFont();
|
unloadFont();
|
||||||
FT_Done_Face( ftFace );
|
FT_Done_Face(ftFace);
|
||||||
FT_Done_FreeType( ftLibrary );
|
FT_Done_FreeType(ftLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,13 +87,13 @@ FreeTypeGX::~FreeTypeGX()
|
|||||||
* vertex format index is modified.
|
* vertex format index is modified.
|
||||||
*
|
*
|
||||||
* @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file.
|
* @param vertexIndex Vertex format index (GX_VTXFMT*) of the glyph textures as defined by the libogc gx.h header file.
|
||||||
*/
|
*/
|
||||||
void FreeTypeGX::setVertexFormat( uint8_t vertexInd )
|
void FreeTypeGX::setVertexFormat(uint8_t vertexInd)
|
||||||
{
|
{
|
||||||
vertexIndex = vertexInd;
|
vertexIndex = vertexInd;
|
||||||
GX_SetVtxAttrFmt( vertexIndex, GX_VA_POS, GX_POS_XYZ, GX_S16, 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_TEX0, GX_TEX_ST, GX_F32, 0);
|
||||||
GX_SetVtxAttrFmt( vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0 );
|
GX_SetVtxAttrFmt(vertexIndex, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,16 +103,15 @@ void FreeTypeGX::setVertexFormat( uint8_t vertexInd )
|
|||||||
*/
|
*/
|
||||||
void FreeTypeGX::unloadFont()
|
void FreeTypeGX::unloadFont()
|
||||||
{
|
{
|
||||||
if ( this->fontData.size() == 0 )
|
if (this->fontData.size() == 0) return;
|
||||||
return;
|
|
||||||
|
|
||||||
map<int16_t, map<wchar_t, ftgxCharData> >::iterator itr;
|
map<int16_t, map<wchar_t, ftgxCharData> >::iterator itr;
|
||||||
map<wchar_t, ftgxCharData>::iterator itr2;
|
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++ )
|
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)
|
||||||
free( itr2->second.glyphDataTexture );
|
free(itr2->second.glyphDataTexture);
|
||||||
|
|
||||||
itr->second.clear();
|
itr->second.clear();
|
||||||
}
|
}
|
||||||
@ -131,17 +129,17 @@ void FreeTypeGX::unloadFont()
|
|||||||
* @param charCode The requested glyph's character code.
|
* @param charCode The requested glyph's character code.
|
||||||
* @return A pointer to the allocated font structure.
|
* @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<int16_t, map<wchar_t, ftgxCharData> >::iterator itr;
|
||||||
map<wchar_t, ftgxCharData>::iterator itr2;
|
map<wchar_t, ftgxCharData>::iterator itr2;
|
||||||
|
|
||||||
itr = fontData.find( pixelSize );
|
itr = fontData.find(pixelSize);
|
||||||
if ( itr != fontData.end() )
|
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;
|
return &itr2->second;
|
||||||
}
|
}
|
||||||
@ -150,43 +148,43 @@ ftgxCharData * FreeTypeGX::cacheGlyphData( wchar_t charCode, int16_t pixelSize )
|
|||||||
FT_UInt gIndex;
|
FT_UInt gIndex;
|
||||||
uint16_t textureWidth = 0, textureHeight = 0;
|
uint16_t textureWidth = 0, textureHeight = 0;
|
||||||
|
|
||||||
if ( ftPointSize != pixelSize )
|
if (ftPointSize != pixelSize)
|
||||||
{
|
{
|
||||||
ftPointSize = pixelSize;
|
ftPointSize = pixelSize;
|
||||||
FT_Set_Pixel_Sizes( ftFace, 0, ftPointSize );
|
FT_Set_Pixel_Sizes(ftFace, 0, ftPointSize);
|
||||||
|
|
||||||
//!Cache ascender and decender as well
|
//!Cache ascender and decender as well
|
||||||
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find( ftPointSize );
|
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find(ftPointSize);
|
||||||
if ( itrAlign == ftgxAlign.end() )
|
if (itrAlign == ftgxAlign.end())
|
||||||
{
|
{
|
||||||
ftgxAlign[ftPointSize].ascender = ( int16_t ) ftFace->size->metrics.ascender >> 6;
|
ftgxAlign[ftPointSize].ascender = (int16_t) ftFace->size->metrics.ascender >> 6;
|
||||||
ftgxAlign[ftPointSize].descender = ( int16_t ) ftFace->size->metrics.descender >> 6;
|
ftgxAlign[ftPointSize].descender = (int16_t) ftFace->size->metrics.descender >> 6;
|
||||||
ftgxAlign[ftPointSize].max = 0;
|
ftgxAlign[ftPointSize].max = 0;
|
||||||
ftgxAlign[ftPointSize].min = 0;
|
ftgxAlign[ftPointSize].min = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gIndex = FT_Get_Char_Index( ftFace, ( FT_ULong ) charCode );
|
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 (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;
|
FT_Bitmap *glyphBitmap = &ftFace->glyph->bitmap;
|
||||||
|
|
||||||
textureWidth = glyphBitmap->width + ( 4 - glyphBitmap->width % 4 ) % 4;
|
textureWidth = glyphBitmap->width + (4 - glyphBitmap->width % 4) % 4;
|
||||||
textureHeight = glyphBitmap->rows + ( 4 - glyphBitmap->rows % 4 ) % 4;
|
textureHeight = glyphBitmap->rows + (4 - glyphBitmap->rows % 4) % 4;
|
||||||
|
|
||||||
fontData[pixelSize][charCode].renderOffsetX = ( int16_t ) ftFace->glyph->bitmap_left;
|
fontData[pixelSize][charCode].renderOffsetX = (int16_t) ftFace->glyph->bitmap_left;
|
||||||
fontData[pixelSize][charCode].glyphAdvanceX = ( uint16_t ) ( ftFace->glyph->advance.x >> 6 );
|
fontData[pixelSize][charCode].glyphAdvanceX = (uint16_t) (ftFace->glyph->advance.x >> 6);
|
||||||
fontData[pixelSize][charCode].glyphIndex = ( uint32_t ) gIndex;
|
fontData[pixelSize][charCode].glyphIndex = (uint32_t) gIndex;
|
||||||
fontData[pixelSize][charCode].textureWidth = ( uint16_t ) textureWidth;
|
fontData[pixelSize][charCode].textureWidth = (uint16_t) textureWidth;
|
||||||
fontData[pixelSize][charCode].textureHeight = ( uint16_t ) textureHeight;
|
fontData[pixelSize][charCode].textureHeight = (uint16_t) textureHeight;
|
||||||
fontData[pixelSize][charCode].renderOffsetY = ( int16_t ) ftFace->glyph->bitmap_top;
|
fontData[pixelSize][charCode].renderOffsetY = (int16_t) ftFace->glyph->bitmap_top;
|
||||||
fontData[pixelSize][charCode].renderOffsetMax = ( 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].renderOffsetMin = (int16_t) glyphBitmap->rows - ftFace->glyph->bitmap_top;
|
||||||
fontData[pixelSize][charCode].glyphDataTexture = NULL;
|
fontData[pixelSize][charCode].glyphDataTexture = NULL;
|
||||||
|
|
||||||
loadGlyphData( glyphBitmap, &fontData[pixelSize][charCode] );
|
loadGlyphData(glyphBitmap, &fontData[pixelSize][charCode]);
|
||||||
|
|
||||||
return &fontData[pixelSize][charCode];
|
return &fontData[pixelSize][charCode];
|
||||||
}
|
}
|
||||||
@ -200,19 +198,18 @@ 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.
|
* 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.
|
* 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;
|
uint32_t i = 0;
|
||||||
FT_UInt gIndex;
|
FT_UInt gIndex;
|
||||||
|
|
||||||
FT_ULong charCode = FT_Get_First_Char( ftFace, &gIndex );
|
FT_ULong charCode = FT_Get_First_Char(ftFace, &gIndex);
|
||||||
while ( gIndex != 0 )
|
while (gIndex != 0)
|
||||||
{
|
{
|
||||||
if ( cacheGlyphData( charCode, pixelSize ) != NULL )
|
if (cacheGlyphData(charCode, pixelSize) != NULL) ++i;
|
||||||
++i;
|
charCode = FT_Get_Next_Char(ftFace, charCode, &gIndex);
|
||||||
charCode = FT_Get_Next_Char( ftFace, charCode, &gIndex );
|
|
||||||
}
|
}
|
||||||
return ( uint16_t )( i );
|
return (uint16_t) (i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -227,32 +224,32 @@ uint16_t FreeTypeGX::cacheGlyphDataComplete( int16_t pixelSize )
|
|||||||
*
|
*
|
||||||
* Optimized for RGBA8 use by Dimok.
|
* 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 );
|
uint8_t * glyphData = (uint8_t *) memalign(32, length);
|
||||||
if ( !glyphData )
|
if (!glyphData) return;
|
||||||
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;
|
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] = *src;
|
||||||
glyphData[offset+1] = *src;
|
glyphData[offset + 1] = *src;
|
||||||
glyphData[offset+32] = *src;
|
glyphData[offset + 32] = *src;
|
||||||
glyphData[offset+33] = *src;
|
glyphData[offset + 33] = *src;
|
||||||
++src;
|
++src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DCFlushRange( glyphData, length );
|
DCFlushRange(glyphData, length);
|
||||||
|
|
||||||
charData->glyphDataTexture = glyphData;
|
charData->glyphDataTexture = glyphData;
|
||||||
}
|
}
|
||||||
@ -265,14 +262,13 @@ void FreeTypeGX::loadGlyphData( FT_Bitmap *bmp, ftgxCharData *charData )
|
|||||||
* @param width Current pixel width of the string.
|
* @param width Current pixel width of the string.
|
||||||
* @param format Positional format 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;
|
return 0;
|
||||||
else if ( format & FTGX_JUSTIFY_CENTER )
|
else if (format & FTGX_JUSTIFY_CENTER)
|
||||||
return -( width >> 1 );
|
return -(width >> 1);
|
||||||
else if ( format & FTGX_JUSTIFY_RIGHT )
|
else if (format & FTGX_JUSTIFY_RIGHT) return -width;
|
||||||
return -width;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,20 +280,19 @@ int16_t FreeTypeGX::getStyleOffsetWidth( uint16_t width, uint16_t format )
|
|||||||
* @param offset Current pixel offset data of the string.
|
* @param offset Current pixel offset data of the string.
|
||||||
* @param format Positional format 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 );
|
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find(pixelSize);
|
||||||
if ( itrAlign == ftgxAlign.end() )
|
if (itrAlign == ftgxAlign.end()) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch ( format & FTGX_ALIGN_MASK )
|
switch (format & FTGX_ALIGN_MASK)
|
||||||
{
|
{
|
||||||
case FTGX_ALIGN_TOP:
|
case FTGX_ALIGN_TOP:
|
||||||
return itrAlign->second.ascender;
|
return itrAlign->second.ascender;
|
||||||
|
|
||||||
case FTGX_ALIGN_MIDDLE:
|
case FTGX_ALIGN_MIDDLE:
|
||||||
default:
|
default:
|
||||||
return ( itrAlign->second.ascender + itrAlign->second.descender + 1 ) >> 1;
|
return (itrAlign->second.ascender + itrAlign->second.descender + 1) >> 1;
|
||||||
|
|
||||||
case FTGX_ALIGN_BOTTOM:
|
case FTGX_ALIGN_BOTTOM:
|
||||||
return itrAlign->second.descender;
|
return itrAlign->second.descender;
|
||||||
@ -309,7 +304,7 @@ int16_t FreeTypeGX::getStyleOffsetHeight( int16_t format, uint16_t pixelSize )
|
|||||||
return itrAlign->second.max;
|
return itrAlign->second.max;
|
||||||
|
|
||||||
case FTGX_ALIGN_GLYPH_MIDDLE:
|
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:
|
case FTGX_ALIGN_GLYPH_BOTTOM:
|
||||||
return itrAlign->second.min;
|
return itrAlign->second.min;
|
||||||
@ -330,45 +325,47 @@ 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.
|
* @param textStyle Flags which specify any styling which should be applied to the rendered string.
|
||||||
* @return The number of characters printed.
|
* @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;
|
||||||
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_pos = x, printed = 0;
|
||||||
uint16_t x_offset = 0, y_offset = 0;
|
uint16_t x_offset = 0, y_offset = 0;
|
||||||
GXTexObj glyphTexture;
|
GXTexObj glyphTexture;
|
||||||
FT_Vector pairDelta;
|
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;
|
int i = 0;
|
||||||
|
|
||||||
while ( text[i] )
|
while (text[i])
|
||||||
{
|
{
|
||||||
if ( widthLimit > 0 && ( x_pos - x ) > widthLimit )
|
if (widthLimit > 0 && (x_pos - x) > widthLimit) break;
|
||||||
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;
|
x_pos += pairDelta.x >> 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
GX_InitTexObj( &glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE );
|
GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth,
|
||||||
copyTextureToFramebuffer( &glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, z, color );
|
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;
|
x_pos += glyphData->glyphAdvanceX;
|
||||||
++printed;
|
++printed;
|
||||||
@ -376,24 +373,25 @@ uint16_t FreeTypeGX::drawText( int16_t x, int16_t y, int16_t z, const wchar_t *t
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( textStyle & FTGX_STYLE_MASK )
|
if (textStyle & FTGX_STYLE_MASK)
|
||||||
{
|
{
|
||||||
getOffset( text, pixelSize, widthLimit );
|
getOffset(text, pixelSize, widthLimit);
|
||||||
drawTextFeature( x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle, color );
|
drawTextFeature(x + x_offset, y + y_offset, z, pixelSize, fullTextWidth, &ftgxAlign[pixelSize], textStyle,
|
||||||
|
color);
|
||||||
}
|
}
|
||||||
|
|
||||||
return printed;
|
return printed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeTypeGX::drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color )
|
void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width,
|
||||||
|
ftgxDataOffset *offsetData, uint16_t format, GXColor color)
|
||||||
{
|
{
|
||||||
uint16_t featureHeight = pixelSize >> 4 > 0 ? pixelSize >> 4 : 1;
|
uint16_t featureHeight = pixelSize >> 4 > 0 ? pixelSize >> 4 : 1;
|
||||||
|
|
||||||
if ( format & FTGX_STYLE_UNDERLINE )
|
if (format & FTGX_STYLE_UNDERLINE) this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, z, color);
|
||||||
this->copyFeatureToFramebuffer( width, featureHeight, x, y + 1, z, color );
|
|
||||||
|
|
||||||
if ( format & FTGX_STYLE_STRIKE )
|
if (format & FTGX_STYLE_STRIKE) this->copyFeatureToFramebuffer(width, featureHeight, x, y
|
||||||
this->copyFeatureToFramebuffer( width, featureHeight, x, y - ( ( offsetData->max ) >> 1 ), z, color );
|
- ((offsetData->max) >> 1), z, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -405,24 +403,24 @@ void FreeTypeGX::drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixel
|
|||||||
* @param text NULL terminated string to calculate.
|
* @param text NULL terminated string to calculate.
|
||||||
* @return The width of the text string in pixels.
|
* @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;
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint16_t strWidth = 0;
|
uint16_t strWidth = 0;
|
||||||
FT_Vector pairDelta;
|
FT_Vector pairDelta;
|
||||||
|
|
||||||
int i = 0;
|
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;
|
strWidth += pairDelta.x >> 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,18 +433,19 @@ uint16_t FreeTypeGX::getWidth( const wchar_t *text, int16_t pixelSize )
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Single char width
|
* 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;
|
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_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 += pairDelta.x >> 6;
|
||||||
}
|
}
|
||||||
strWidth += glyphData->glyphAdvanceX;
|
strWidth += glyphData->glyphAdvanceX;
|
||||||
@ -464,9 +463,9 @@ uint16_t FreeTypeGX::getCharWidth( const wchar_t wChar, int16_t pixelSize, const
|
|||||||
* @param text NULL terminated string to calculate.
|
* @param text NULL terminated string to calculate.
|
||||||
* @return The height of the text string in pixels.
|
* @return The height of the text string in pixels.
|
||||||
*/
|
*/
|
||||||
uint16_t FreeTypeGX::getHeight( const wchar_t *text, int16_t pixelSize )
|
uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize)
|
||||||
{
|
{
|
||||||
getOffset( text, pixelSize );
|
getOffset(text, pixelSize);
|
||||||
|
|
||||||
return ftgxAlign[pixelSize].max - ftgxAlign[pixelSize].min;
|
return ftgxAlign[pixelSize].max - ftgxAlign[pixelSize].min;
|
||||||
}
|
}
|
||||||
@ -481,24 +480,22 @@ 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
|
* @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;
|
||||||
return;
|
|
||||||
|
|
||||||
int16_t strMax = 0, strMin = 9999;
|
int16_t strMax = 0, strMin = 9999;
|
||||||
uint16_t currWidth = 0;
|
uint16_t currWidth = 0;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while ( text[i] )
|
while (text[i])
|
||||||
{
|
{
|
||||||
if ( widthLimit > 0 && currWidth >= widthLimit )
|
if (widthLimit > 0 && currWidth >= widthLimit) break;
|
||||||
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;
|
strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
|
||||||
strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
|
strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
|
||||||
@ -508,10 +505,10 @@ void FreeTypeGX::getOffset( const wchar_t *text, int16_t pixelSize, uint16_t wid
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ftPointSize != pixelSize )
|
if (ftPointSize != pixelSize)
|
||||||
{
|
{
|
||||||
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].ascender = ftFace->size->metrics.ascender >> 6;
|
||||||
@ -532,34 +529,35 @@ void FreeTypeGX::getOffset( const wchar_t *text, int16_t pixelSize, uint16_t wid
|
|||||||
* @param screenY The screen Y coordinate at which to output the rendered texture.
|
* @param screenY The screen Y coordinate at which to output the rendered texture.
|
||||||
* @param color Color to apply to the texture.
|
* @param 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_InvalidateTexAll();
|
||||||
|
|
||||||
GX_SetTevOp ( GX_TEVSTAGE0, GX_MODULATE );
|
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
|
||||||
GX_SetVtxDesc ( GX_VA_TEX0, GX_DIRECT );
|
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
||||||
|
|
||||||
GX_Begin( GX_QUADS, this->vertexIndex, 4 );
|
GX_Begin(GX_QUADS, this->vertexIndex, 4);
|
||||||
GX_Position3s16( screenX, screenY, screenZ );
|
GX_Position3s16(screenX, screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
GX_TexCoord2f32( 0.0f, 0.0f );
|
GX_TexCoord2f32(0.0f, 0.0f);
|
||||||
|
|
||||||
GX_Position3s16( texWidth + screenX, screenY, screenZ );
|
GX_Position3s16(texWidth + screenX, screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
GX_TexCoord2f32( 1.0f, 0.0f );
|
GX_TexCoord2f32(1.0f, 0.0f);
|
||||||
|
|
||||||
GX_Position3s16( texWidth + screenX, texHeight + screenY, screenZ );
|
GX_Position3s16(texWidth + screenX, texHeight + screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
GX_TexCoord2f32( 1.0f, 1.0f );
|
GX_TexCoord2f32(1.0f, 1.0f);
|
||||||
|
|
||||||
GX_Position3s16( screenX, texHeight + screenY, screenZ );
|
GX_Position3s16(screenX, texHeight + screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
GX_TexCoord2f32( 0.0f, 1.0f );
|
GX_TexCoord2f32(0.0f, 1.0f);
|
||||||
GX_End();
|
GX_End();
|
||||||
|
|
||||||
GX_SetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
|
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||||
GX_SetVtxDesc( GX_VA_TEX0, GX_NONE );
|
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -573,25 +571,26 @@ void FreeTypeGX::copyTextureToFramebuffer( GXTexObj *texObj, f32 texWidth, f32 t
|
|||||||
* @param screenY The screen Y coordinate at which to output the quad.
|
* @param screenY The screen Y coordinate at which to output the quad.
|
||||||
* @param color Color to apply to the texture.
|
* @param 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_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||||
GX_SetVtxDesc ( GX_VA_TEX0, GX_NONE );
|
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
||||||
|
|
||||||
GX_Begin( GX_QUADS, this->vertexIndex, 4 );
|
GX_Begin(GX_QUADS, this->vertexIndex, 4);
|
||||||
GX_Position3s16( screenX, screenY, screenZ );
|
GX_Position3s16(screenX, screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
GX_Position3s16( featureWidth + screenX, screenY, screenZ );
|
GX_Position3s16(featureWidth + screenX, screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
GX_Position3s16( featureWidth + screenX, featureHeight + screenY, screenZ );
|
GX_Position3s16(featureWidth + screenX, featureHeight + screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
GX_Position3s16( screenX, featureHeight + screenY, screenZ );
|
GX_Position3s16(screenX, featureHeight + screenY, screenZ);
|
||||||
GX_Color4u8( color.r, color.g, color.b, color.a );
|
GX_Color4u8(color.r, color.g, color.b, color.a);
|
||||||
GX_End();
|
GX_End();
|
||||||
|
|
||||||
GX_SetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
|
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||||
GX_SetVtxDesc( GX_VA_TEX0, GX_NONE );
|
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
||||||
}
|
}
|
||||||
|
@ -89,9 +89,10 @@ typedef struct ftgxDataOffset_ ftgxDataOffset;
|
|||||||
#define FTGX_STYLE_STRIKE 0x2000
|
#define FTGX_STYLE_STRIKE 0x2000
|
||||||
#define FTGX_STYLE_MASK 0xf000
|
#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
|
/*! \class FreeTypeGX
|
||||||
* \brief Wrapper class for the libFreeType library with GX rendering.
|
* \brief Wrapper class for the libFreeType library with GX rendering.
|
||||||
@ -113,32 +114,36 @@ 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, 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. */
|
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 getStyleOffsetWidth(uint16_t width, uint16_t format);
|
||||||
int16_t getStyleOffsetHeight( int16_t format, uint16_t pixelSize );
|
int16_t getStyleOffsetHeight(int16_t format, uint16_t pixelSize);
|
||||||
|
|
||||||
void unloadFont();
|
void unloadFont();
|
||||||
ftgxCharData *cacheGlyphData( wchar_t charCode, int16_t pixelSize );
|
ftgxCharData *cacheGlyphData(wchar_t charCode, int16_t pixelSize);
|
||||||
uint16_t cacheGlyphDataComplete( int16_t pixelSize );
|
uint16_t cacheGlyphDataComplete(int16_t pixelSize);
|
||||||
void loadGlyphData( FT_Bitmap *bmp, ftgxCharData *charData );
|
void loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData);
|
||||||
|
|
||||||
void setDefaultMode();
|
void setDefaultMode();
|
||||||
|
|
||||||
void drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color );
|
void drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width,
|
||||||
void copyTextureToFramebuffer( GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color );
|
ftgxDataOffset *offsetData, uint16_t format, GXColor color);
|
||||||
void copyFeatureToFramebuffer( f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, 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:
|
public:
|
||||||
FreeTypeGX( const uint8_t* fontBuffer, FT_Long bufferSize );
|
FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize);
|
||||||
~FreeTypeGX();
|
~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 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 getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000);
|
||||||
uint16_t getHeight( const wchar_t *text, int16_t pixelSize );
|
uint16_t getHeight(const wchar_t *text, int16_t pixelSize);
|
||||||
void getOffset( const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0 );
|
void getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FREETYPEGX_H_ */
|
#endif /* FREETYPEGX_H_ */
|
||||||
|
@ -39,16 +39,15 @@
|
|||||||
#include "ZipFile.h"
|
#include "ZipFile.h"
|
||||||
#include "language/gettext.h"
|
#include "language/gettext.h"
|
||||||
|
|
||||||
ZipFile::ZipFile( const char *filepath )
|
ZipFile::ZipFile(const char *filepath)
|
||||||
{
|
{
|
||||||
File = unzOpen( filepath );
|
File = unzOpen(filepath);
|
||||||
if ( File )
|
if (File) this->LoadList();
|
||||||
this->LoadList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZipFile::~ZipFile()
|
ZipFile::~ZipFile()
|
||||||
{
|
{
|
||||||
unzClose( File );
|
unzClose(File);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZipFile::LoadList()
|
bool ZipFile::LoadList()
|
||||||
@ -56,83 +55,76 @@ bool ZipFile::LoadList()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZipFile::ExtractAll( const char *dest )
|
bool ZipFile::ExtractAll(const char *dest)
|
||||||
{
|
{
|
||||||
if ( !File )
|
if (!File) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
bool Stop = false;
|
bool Stop = false;
|
||||||
|
|
||||||
u32 blocksize = 1024 * 50;
|
u32 blocksize = 1024 * 50;
|
||||||
u8 *buffer = new u8[blocksize];
|
u8 *buffer = new u8[blocksize];
|
||||||
|
|
||||||
if ( !buffer )
|
if (!buffer) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
char writepath[MAXPATHLEN];
|
char writepath[MAXPATHLEN];
|
||||||
char filename[MAXPATHLEN];
|
char filename[MAXPATHLEN];
|
||||||
memset( filename, 0, sizeof( filename ) );
|
memset(filename, 0, sizeof(filename));
|
||||||
|
|
||||||
int ret = unzGoToFirstFile( File );
|
int ret = unzGoToFirstFile(File);
|
||||||
if ( ret != UNZ_OK )
|
if (ret != UNZ_OK) Stop = true;
|
||||||
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
|
||||||
Stop = true;
|
= true;
|
||||||
|
|
||||||
if ( !Stop && filename[strlen( filename )-1] != '/' )
|
if (!Stop && filename[strlen(filename) - 1] != '/')
|
||||||
{
|
{
|
||||||
u32 uncompressed_size = cur_file_info.uncompressed_size;
|
u32 uncompressed_size = cur_file_info.uncompressed_size;
|
||||||
|
|
||||||
u32 done = 0;
|
u32 done = 0;
|
||||||
char *pointer = NULL;
|
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, '/' );
|
pointer = strrchr(writepath, '/');
|
||||||
int position = pointer - writepath + 2;
|
int position = pointer - writepath + 2;
|
||||||
|
|
||||||
char temppath[strlen( writepath )];
|
char temppath[strlen(writepath)];
|
||||||
snprintf( temppath, position, "%s", 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
|
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;
|
||||||
blocksize = uncompressed_size - done;
|
|
||||||
|
|
||||||
ret = unzReadCurrentFile( File, buffer, blocksize );
|
ret = unzReadCurrentFile(File, buffer, blocksize);
|
||||||
|
|
||||||
if ( ret == 0 )
|
if (ret == 0) break;
|
||||||
break;
|
|
||||||
|
|
||||||
fwrite( buffer, 1, blocksize, pfile );
|
fwrite(buffer, 1, blocksize, pfile);
|
||||||
|
|
||||||
done += ret;
|
done += ret;
|
||||||
|
|
||||||
}
|
} while (done < uncompressed_size);
|
||||||
while ( done < uncompressed_size );
|
|
||||||
|
|
||||||
fclose( pfile );
|
fclose(pfile);
|
||||||
unzCloseCurrentFile( File );
|
unzCloseCurrentFile(File);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( unzGoToNextFile( File ) != UNZ_OK )
|
if (unzGoToNextFile(File) != UNZ_OK) Stop = true;
|
||||||
Stop = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] buffer;
|
delete[] buffer;
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
|
|
||||||
ProgressStop();
|
ProgressStop();
|
||||||
|
@ -42,12 +42,12 @@ class ZipFile
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//!Constructor
|
//!Constructor
|
||||||
ZipFile( const char *filepath );
|
ZipFile(const char *filepath);
|
||||||
//!Destructor
|
//!Destructor
|
||||||
~ZipFile();
|
~ZipFile();
|
||||||
//!Extract all files from a zip file to a directory
|
//!Extract all files from a zip file to a directory
|
||||||
//!\param dest Destination path to where to extract
|
//!\param dest Destination path to where to extract
|
||||||
bool ExtractAll( const char *dest );
|
bool ExtractAll(const char *dest);
|
||||||
protected:
|
protected:
|
||||||
bool LoadList();
|
bool LoadList();
|
||||||
unzFile File;
|
unzFile File;
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
void InitAudio()
|
void InitAudio()
|
||||||
{
|
{
|
||||||
AUDIO_Init( NULL );
|
AUDIO_Init(NULL);
|
||||||
ASND_Init();
|
ASND_Init();
|
||||||
ASND_Pause( 0 );
|
ASND_Pause(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -30,6 +30,6 @@ void InitAudio()
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
void ShutdownAudio()
|
void ShutdownAudio()
|
||||||
{
|
{
|
||||||
ASND_Pause( 1 );
|
ASND_Pause(1);
|
||||||
ASND_End();
|
ASND_End();
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,6 @@
|
|||||||
|
|
||||||
#include "MD5.h"
|
#include "MD5.h"
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- **
|
/* -------------------------------------------------------------------------- **
|
||||||
* Static Constants:
|
* Static Constants:
|
||||||
*
|
*
|
||||||
@ -110,46 +109,34 @@
|
|||||||
* array. They're divided up into four groups of 16.
|
* array. They're divided up into four groups of 16.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const uint8_t K[3][16] =
|
static const uint8_t K[3][16] = {
|
||||||
{
|
/* Round 1: skipped (since it is simply sequential). */
|
||||||
/* 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 */
|
||||||
{ 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 */
|
||||||
{ 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 */
|
||||||
{ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 } /* R4 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t S[4][4] =
|
static const uint8_t S[4][4] = { { 7, 12, 17, 22 }, /* Round 1 */
|
||||||
{
|
{ 5, 9, 14, 20 }, /* Round 2 */
|
||||||
{ 7, 12, 17, 22 }, /* Round 1 */
|
{ 4, 11, 16, 23 }, /* Round 3 */
|
||||||
{ 5, 9, 14, 20 }, /* Round 2 */
|
{ 6, 10, 15, 21 } /* Round 4 */
|
||||||
{ 4, 11, 16, 23 }, /* Round 3 */
|
|
||||||
{ 6, 10, 15, 21 } /* Round 4 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32_t T[4][16] = { { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */
|
||||||
|
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
|
||||||
|
0xa679438e, 0x49b40821 },
|
||||||
|
|
||||||
static const uint32_t T[4][16] =
|
{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
|
||||||
{
|
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
|
||||||
{ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */
|
0x676f02d9, 0x8d2a4c8a },
|
||||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
|
||||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
|
||||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 },
|
|
||||||
|
|
||||||
{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
|
{ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */
|
||||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5,
|
||||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
0x1fa27cf8, 0xc4ac5665 },
|
||||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a },
|
|
||||||
|
|
||||||
{ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */
|
|
||||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
|
||||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
|
||||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 },
|
|
||||||
|
|
||||||
{ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */
|
|
||||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
|
||||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
|
||||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
{ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */
|
||||||
|
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235,
|
||||||
|
0x2ad7d2bb, 0xeb86d391 }, };
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- **
|
/* -------------------------------------------------------------------------- **
|
||||||
* Macros:
|
* Macros:
|
||||||
@ -172,12 +159,11 @@ static const uint32_t T[4][16] =
|
|||||||
|
|
||||||
#define STR2HEX(x) ((x >= 0x30) && (x <= 0x39)) ? x - 0x30 : toupper((int)x)-0x37
|
#define STR2HEX(x) ((x >= 0x30) && (x <= 0x39)) ? x - 0x30 : toupper((int)x)-0x37
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- **
|
/* -------------------------------------------------------------------------- **
|
||||||
* Static Functions:
|
* Static Functions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
static void Permute(uint32_t ABCD[4], const unsigned char block[64])
|
||||||
/* ------------------------------------------------------------------------ **
|
/* ------------------------------------------------------------------------ **
|
||||||
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
|
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
|
||||||
*
|
*
|
||||||
@ -220,19 +206,19 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
|||||||
|
|
||||||
/* Store the current ABCD values for later re-use.
|
/* 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];
|
KeepABCD[i] = ABCD[i];
|
||||||
|
|
||||||
/* Convert the input block into an array of unsigned longs, taking care
|
/* Convert the input block into an array of unsigned longs, taking care
|
||||||
* to read the block in Little Endian order (the algorithm assumes this).
|
* to read the block in Little Endian order (the algorithm assumes this).
|
||||||
* The uint32_t values are then handled in host order.
|
* 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++];
|
||||||
X[i] |= ( ( uint32_t )block[j++] << 8 );
|
X[i] |= ((uint32_t) block[j++] << 8);
|
||||||
X[i] |= ( ( uint32_t )block[j++] << 16 );
|
X[i] |= ((uint32_t) block[j++] << 16);
|
||||||
X[i] |= ( ( uint32_t )block[j++] << 24 );
|
X[i] |= ((uint32_t) block[j++] << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This loop performs the four rounds of permutations.
|
/* This loop performs the four rounds of permutations.
|
||||||
@ -249,21 +235,21 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
|||||||
* (My implementation appears to be a poor compromise between speed, size,
|
* (My implementation appears to be a poor compromise between speed, size,
|
||||||
* and clarity. Ugh. [crh])
|
* 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. */
|
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. */
|
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 */
|
c = ABCD[(j + 2) & 0x3]; /* This isn't really necessary, it just looks */
|
||||||
d = ABCD[( j+3 ) & 0x3]; /* clean & will hopefully be optimized away. */
|
d = ABCD[(j + 3) & 0x3]; /* clean & will hopefully be optimized away. */
|
||||||
|
|
||||||
/* The actual perumation function.
|
/* The actual perumation function.
|
||||||
* This is broken out to minimize the code within the switch().
|
* This is broken out to minimize the code within the switch().
|
||||||
*/
|
*/
|
||||||
switch ( round )
|
switch (round)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
/* round 1 */
|
/* round 1 */
|
||||||
@ -271,36 +257,35 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* round 2 */
|
/* round 2 */
|
||||||
a = md5G( b, c, d ) + X[ K[0][i] ];
|
a = md5G( b, c, d ) + X[K[0][i]];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* round 3 */
|
/* round 3 */
|
||||||
a = md5H( b, c, d ) + X[ K[1][i] ];
|
a = md5H( b, c, d ) + X[K[1][i]];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* round 4 */
|
/* round 4 */
|
||||||
a = md5I( b, c, d ) + X[ K[2][i] ];
|
a = md5I( b, c, d ) + X[K[2][i]];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
a = 0xFFFFFFFF & ( ABCD[j] + a + T[round][i] );
|
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
|
/* Use the stored original A, B, C, D values to perform
|
||||||
* one last convolution.
|
* one last convolution.
|
||||||
*/
|
*/
|
||||||
for ( i = 0; i < 4; i++ )
|
for (i = 0; i < 4; i++)
|
||||||
ABCD[i] = 0xFFFFFFFF & ( ABCD[i] + KeepABCD[i] );
|
ABCD[i] = 0xFFFFFFFF & (ABCD[i] + KeepABCD[i]);
|
||||||
|
|
||||||
} /* Permute */
|
} /* Permute */
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- **
|
/* -------------------------------------------------------------------------- **
|
||||||
* Functions:
|
* Functions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx )
|
auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx)
|
||||||
/* ------------------------------------------------------------------------ **
|
/* ------------------------------------------------------------------------ **
|
||||||
* Initialize an MD5 context.
|
* Initialize an MD5 context.
|
||||||
*
|
*
|
||||||
@ -344,13 +329,10 @@ auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx )
|
|||||||
/* confusing as all getout (to me, anyway). The values given */
|
/* confusing as all getout (to me, anyway). The values given */
|
||||||
/* here are provided as 32-bit values in C language format, */
|
/* here are provided as 32-bit values in C language format, */
|
||||||
/* so they are endian-agnostic. */
|
/* so they are endian-agnostic. */
|
||||||
return( ctx );
|
return (ctx);
|
||||||
} /* auth_md5InitCtx */
|
} /* auth_md5InitCtx */
|
||||||
|
|
||||||
|
auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len)
|
||||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
|
||||||
const unsigned char *src,
|
|
||||||
const int len )
|
|
||||||
/* ------------------------------------------------------------------------ **
|
/* ------------------------------------------------------------------------ **
|
||||||
* Build an MD5 Message Digest within the given context.
|
* Build an MD5 Message Digest within the given context.
|
||||||
*
|
*
|
||||||
@ -371,29 +353,28 @@ auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
|||||||
|
|
||||||
/* Add the new block's length to the total length.
|
/* 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.
|
/* Copy the new block's data into the context block.
|
||||||
* Call the Permute() function whenever the context block is full.
|
* 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->block[ctx->b_used] = src[i];
|
||||||
( ctx->b_used )++;
|
(ctx->b_used)++;
|
||||||
if ( 64 == ctx->b_used )
|
if (64 == ctx->b_used)
|
||||||
{
|
{
|
||||||
Permute( ctx->ABCD, ctx->block );
|
Permute(ctx->ABCD, ctx->block);
|
||||||
ctx->b_used = 0;
|
ctx->b_used = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the updated context.
|
/* Return the updated context.
|
||||||
*/
|
*/
|
||||||
return( ctx );
|
return (ctx);
|
||||||
} /* auth_md5SumCtx */
|
} /* auth_md5SumCtx */
|
||||||
|
|
||||||
|
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.
|
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||||
*
|
*
|
||||||
@ -422,20 +403,20 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
|||||||
* free byte in the context block.
|
* free byte in the context block.
|
||||||
*/
|
*/
|
||||||
ctx->block[ctx->b_used] = 0x80;
|
ctx->block[ctx->b_used] = 0x80;
|
||||||
( ctx->b_used )++;
|
(ctx->b_used)++;
|
||||||
|
|
||||||
/* Zero out any remaining free bytes in the context block.
|
/* 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;
|
ctx->block[i] = 0;
|
||||||
|
|
||||||
/* We need 8 bytes to store the length field.
|
/* We need 8 bytes to store the length field.
|
||||||
* If we don't have 8, call Permute() and reset the context block.
|
* 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 );
|
Permute(ctx->ABCD, ctx->block);
|
||||||
for ( i = 0; i < 64; i++ )
|
for (i = 0; i < 64; i++)
|
||||||
ctx->block[i] = 0;
|
ctx->block[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,29 +426,28 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
|||||||
* any MAXINT numeric overflow issues.
|
* any MAXINT numeric overflow issues.
|
||||||
*/
|
*/
|
||||||
l = ctx->len << 3;
|
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[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 );
|
Permute(ctx->ABCD, ctx->block);
|
||||||
|
|
||||||
/* Now copy the result into the output buffer and we're done.
|
/* 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[0 + i] = GetLongByte( ctx->ABCD[0], i );
|
||||||
dst[ 4+i] = GetLongByte( ctx->ABCD[1], i );
|
dst[4 + i] = GetLongByte( ctx->ABCD[1], i );
|
||||||
dst[ 8+i] = GetLongByte( ctx->ABCD[2], i );
|
dst[8 + i] = GetLongByte( ctx->ABCD[2], i );
|
||||||
dst[12+i] = GetLongByte( ctx->ABCD[3], i );
|
dst[12 + i] = GetLongByte( ctx->ABCD[3], i );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the context.
|
/* Return the context.
|
||||||
* This is done for compatibility with the other auth_md5*Ctx() functions.
|
* This is done for compatibility with the other auth_md5*Ctx() functions.
|
||||||
*/
|
*/
|
||||||
return( ctx );
|
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.
|
* Compute an MD5 message digest.
|
||||||
*
|
*
|
||||||
@ -503,16 +483,14 @@ unsigned char * MD5( unsigned char *dst, const unsigned char *src, const int len
|
|||||||
{
|
{
|
||||||
auth_md5Ctx ctx[1];
|
auth_md5Ctx ctx[1];
|
||||||
|
|
||||||
( void )auth_md5InitCtx( ctx ); /* Open a context. */
|
(void) auth_md5InitCtx(ctx); /* Open a context. */
|
||||||
( void )auth_md5SumCtx( ctx, src, len ); /* Pass only one block. */
|
(void) auth_md5SumCtx(ctx, src, len); /* Pass only one block. */
|
||||||
( void )auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
(void) auth_md5CloseCtx(ctx, dst); /* Close the context. */
|
||||||
|
|
||||||
return( dst ); /* Makes life easy. */
|
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.
|
* Compute an MD5 message digest.
|
||||||
*
|
*
|
||||||
@ -550,58 +528,55 @@ unsigned char * MD5fromFile( unsigned char *dst, const char *src )
|
|||||||
unsigned int blksize = 0;
|
unsigned int blksize = 0;
|
||||||
unsigned int read = 0;
|
unsigned int read = 0;
|
||||||
|
|
||||||
file = fopen( src, "rb" );
|
file = fopen(src, "rb");
|
||||||
|
|
||||||
if ( file == NULL )
|
if (file == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
( void )auth_md5InitCtx( ctx ); /* Open a context. */
|
(void) auth_md5InitCtx(ctx); /* Open a context. */
|
||||||
|
|
||||||
fseek ( file , 0 , SEEK_END );
|
fseek(file, 0, SEEK_END);
|
||||||
unsigned long long filesize = ftell( file );
|
unsigned long long filesize = ftell(file);
|
||||||
rewind ( 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;
|
blksize = filesize;
|
||||||
else
|
else blksize = 1048576;
|
||||||
blksize = 1048576;
|
|
||||||
|
|
||||||
unsigned char * buffer = malloc( blksize );
|
unsigned char * buffer = malloc(blksize);
|
||||||
|
|
||||||
if ( buffer == NULL )
|
if (buffer == NULL)
|
||||||
{
|
{
|
||||||
//no memory
|
//no memory
|
||||||
fclose( file );
|
fclose(file);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
read = fread( buffer, 1, blksize, file );
|
read = fread(buffer, 1, blksize, file);
|
||||||
( void )auth_md5SumCtx( ctx, buffer, read ); /* Pass only one block. */
|
(void) auth_md5SumCtx(ctx, buffer, read); /* Pass only one block. */
|
||||||
|
|
||||||
}
|
} while (read > 0);
|
||||||
while ( read > 0 );
|
|
||||||
|
|
||||||
fclose( file );
|
fclose(file);
|
||||||
free( buffer );
|
free(buffer);
|
||||||
|
|
||||||
( void )auth_md5CloseCtx( ctx, dst ); /* Close the context. */
|
(void) auth_md5CloseCtx(ctx, dst); /* Close the context. */
|
||||||
|
|
||||||
return( dst ); /* Makes life easy. */
|
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];
|
char hexchar[3];
|
||||||
short i = 0, n = 0;
|
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[0];
|
||||||
dst[n++] = hexchar[1];
|
dst[n++] = hexchar[1];
|
||||||
@ -612,12 +587,12 @@ const char * MD5ToString( const unsigned char * hash, char * dst )
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char * StringToMD5( const char * hash, unsigned char * dst )
|
unsigned char * StringToMD5(const char * hash, unsigned char * dst)
|
||||||
{
|
{
|
||||||
char hexchar[2];
|
char hexchar[2];
|
||||||
short i = 0, n = 0;
|
short i = 0, n = 0;
|
||||||
|
|
||||||
for ( i = 0; i < 16; i++ )
|
for (i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
hexchar[0] = hash[n++];
|
hexchar[0] = hash[n++];
|
||||||
hexchar[1] = hash[n++];
|
hexchar[1] = hash[n++];
|
||||||
@ -630,5 +605,4 @@ unsigned char * StringToMD5( const char * hash, unsigned char * dst )
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ========================================================================== */
|
/* ========================================================================== */
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ========================================================================== **
|
/* ========================================================================== **
|
||||||
*
|
*
|
||||||
* MD5.h
|
* MD5.h
|
||||||
@ -93,12 +94,11 @@ extern "C"
|
|||||||
unsigned char block[64];
|
unsigned char block[64];
|
||||||
} auth_md5Ctx;
|
} auth_md5Ctx;
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- **
|
/* -------------------------------------------------------------------------- **
|
||||||
* Functions:
|
* Functions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx );
|
auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx);
|
||||||
/* ------------------------------------------------------------------------ **
|
/* ------------------------------------------------------------------------ **
|
||||||
* Initialize an MD5 context.
|
* Initialize an MD5 context.
|
||||||
*
|
*
|
||||||
@ -127,10 +127,7 @@ extern "C"
|
|||||||
* ------------------------------------------------------------------------ **
|
* ------------------------------------------------------------------------ **
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len);
|
||||||
auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
|
||||||
const unsigned char *src,
|
|
||||||
const int len );
|
|
||||||
/* ------------------------------------------------------------------------ **
|
/* ------------------------------------------------------------------------ **
|
||||||
* Build an MD5 Message Digest within the given context.
|
* Build an MD5 Message Digest within the given context.
|
||||||
*
|
*
|
||||||
@ -147,8 +144,7 @@ extern "C"
|
|||||||
* ------------------------------------------------------------------------ **
|
* ------------------------------------------------------------------------ **
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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.
|
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||||
*
|
*
|
||||||
@ -168,8 +164,7 @@ extern "C"
|
|||||||
* ------------------------------------------------------------------------ **
|
* ------------------------------------------------------------------------ **
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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.
|
* Compute an MD5 message digest.
|
||||||
*
|
*
|
||||||
@ -203,7 +198,7 @@ extern "C"
|
|||||||
* ------------------------------------------------------------------------ **
|
* ------------------------------------------------------------------------ **
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned char * MD5fromFile( unsigned char *dst, const char *src );
|
unsigned char * MD5fromFile(unsigned char *dst, const char *src);
|
||||||
/* ------------------------------------------------------------------------ **
|
/* ------------------------------------------------------------------------ **
|
||||||
* Compute an MD5 message digest.
|
* Compute an MD5 message digest.
|
||||||
*
|
*
|
||||||
@ -235,10 +230,10 @@ extern "C"
|
|||||||
* ------------------------------------------------------------------------ **
|
* ------------------------------------------------------------------------ **
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char * MD5ToString( const unsigned char *hash, char *dst );
|
const char * MD5ToString(const unsigned char *hash, char *dst);
|
||||||
unsigned char * StringToMD5( const char * hash, unsigned char * dst );
|
unsigned char * StringToMD5(const char * hash, unsigned char * dst);
|
||||||
|
|
||||||
/* ========================================================================== */
|
/* ========================================================================== */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -22,106 +22,102 @@
|
|||||||
#include "patches/fst.h"
|
#include "patches/fst.h"
|
||||||
#include "usbloader/fstfile.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
|
// Mount the disc
|
||||||
//Disc_SetWBFS(1, (u8*)discid);
|
//Disc_SetWBFS(1, (u8*)discid);
|
||||||
Disc_SetUSB( discid );
|
Disc_SetUSB(discid);
|
||||||
|
|
||||||
Disc_Open();
|
Disc_Open();
|
||||||
|
|
||||||
u64 offset;
|
u64 offset;
|
||||||
s32 ret;
|
s32 ret;
|
||||||
|
|
||||||
ret = __Disc_FindPartition( &offset );
|
ret = __Disc_FindPartition(&offset);
|
||||||
if ( ret < 0 )
|
if (ret < 0) return ret;
|
||||||
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);
|
//printf("ERROR: OpenPartition(0x%llx) %d\n", offset, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read where to find the fst.bin
|
// 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
|
//Out of memory
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = WDVD_Read( buffer, 0x20, 0x420 );
|
ret = WDVD_Read(buffer, 0x20, 0x420);
|
||||||
if ( ret < 0 )
|
if (ret < 0) return ret;
|
||||||
return ret;
|
|
||||||
|
|
||||||
// Read fst.bin
|
// Read fst.bin
|
||||||
void *fstbuffer = memalign( 32, buffer[2] * 4 );
|
void *fstbuffer = memalign(32, buffer[2] * 4);
|
||||||
FST_ENTRY *fst = ( FST_ENTRY * )fstbuffer;
|
FST_ENTRY *fst = (FST_ENTRY *) fstbuffer;
|
||||||
|
|
||||||
if ( fst == NULL )
|
if (fst == NULL)
|
||||||
{
|
{
|
||||||
//Out of memory
|
//Out of memory
|
||||||
free( buffer );
|
free(buffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = WDVD_Read( fstbuffer, buffer[2] * 4, buffer[1] * 4 );
|
ret = WDVD_Read(fstbuffer, buffer[2] * 4, buffer[1] * 4);
|
||||||
if ( ret < 0 )
|
if (ret < 0) return ret;
|
||||||
return ret;
|
|
||||||
|
|
||||||
free( buffer );
|
free(buffer);
|
||||||
|
|
||||||
// Search the fst.bin
|
// Search the fst.bin
|
||||||
u32 count = fst[0].filelen;
|
u32 count = fst[0].filelen;
|
||||||
int i;
|
int i;
|
||||||
u32 index = 0;
|
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;
|
index = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( index == 0 )
|
if (index == 0)
|
||||||
{
|
{
|
||||||
//opening.bnr not found
|
//opening.bnr not found
|
||||||
free( fstbuffer );
|
free(fstbuffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the .bnr
|
// 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
|
//Out of memory
|
||||||
free( fstbuffer );
|
free(fstbuffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = WDVD_Read( ( void * )banner, fst[index].filelen, fst[index].fileoffset * 4 );
|
ret = WDVD_Read((void *) banner, fst[index].filelen, fst[index].fileoffset * 4);
|
||||||
if ( ret < 0 )
|
if (ret < 0) return ret;
|
||||||
return ret;
|
|
||||||
|
|
||||||
WDVD_Reset();
|
WDVD_Reset();
|
||||||
WDVD_ClosePartition();
|
WDVD_ClosePartition();
|
||||||
//fatInitDefault();
|
//fatInitDefault();
|
||||||
//SDCard_Init();
|
//SDCard_Init();
|
||||||
WDVD_SetUSBMode( NULL, 0 );
|
WDVD_SetUSBMode(NULL, 0);
|
||||||
FILE *fp = fopen( dest, "wb" );
|
FILE *fp = fopen(dest, "wb");
|
||||||
if ( fp )
|
if (fp)
|
||||||
{
|
{
|
||||||
fwrite( banner, 1, fst[index].filelen, fp );
|
fwrite(banner, 1, fst[index].filelen, fp);
|
||||||
fclose( fp );
|
fclose(fp);
|
||||||
}
|
}
|
||||||
free( fstbuffer );
|
free(fstbuffer);
|
||||||
free( banner );
|
free(banner);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s32 dump_banner( const u8 *discid, const char * dest );
|
s32 dump_banner(const u8 *discid, const char * dest);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -6,54 +6,54 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "gui_banner.h"
|
#include "gui_banner.h"
|
||||||
|
|
||||||
GuiBanner::GuiBanner( const char *tplfilepath )
|
GuiBanner::GuiBanner(const char *tplfilepath)
|
||||||
{
|
{
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
tplfilesize = 0;
|
tplfilesize = 0;
|
||||||
width = 0;
|
width = 0;
|
||||||
height = 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 heighttemp = 0;
|
||||||
unsigned short widthtemp = 0;
|
unsigned short widthtemp = 0;
|
||||||
|
|
||||||
fseek( tplfp , 0x14, SEEK_SET );
|
fseek(tplfp, 0x14, SEEK_SET);
|
||||||
fread( ( void* )&heighttemp, 1, 2, tplfp );
|
fread((void*) &heighttemp, 1, 2, tplfp);
|
||||||
fread( ( void* )&widthtemp, 1, 2, tplfp );
|
fread((void*) &widthtemp, 1, 2, tplfp);
|
||||||
fseek ( tplfp , 0 , SEEK_END );
|
fseek(tplfp, 0, SEEK_END);
|
||||||
tplfilesize = ftell ( tplfp );
|
tplfilesize = ftell(tplfp);
|
||||||
rewind ( tplfp );
|
rewind(tplfp);
|
||||||
memory = memalign( 32, tplfilesize );
|
memory = memalign(32, tplfilesize);
|
||||||
if ( !memory )
|
if (!memory)
|
||||||
{
|
{
|
||||||
fclose( tplfp );
|
fclose(tplfp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fread( memory, 1, tplfilesize, tplfp );
|
fread(memory, 1, tplfilesize, tplfp);
|
||||||
fclose( tplfp );
|
fclose(tplfp);
|
||||||
|
|
||||||
TPLFile tplfile;
|
TPLFile tplfile;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
ret = TPL_OpenTPLFromMemory(&tplfile, memory, tplfilesize);
|
||||||
if ( ret < 0 )
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
free( memory );
|
free(memory);
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
ret = TPL_GetTexture(&tplfile, 0, &texObj);
|
||||||
if ( ret < 0 )
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
free( memory );
|
free(memory);
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TPL_CloseTPLFile( &tplfile );
|
TPL_CloseTPLFile(&tplfile);
|
||||||
|
|
||||||
width = widthtemp;
|
width = widthtemp;
|
||||||
height = heighttemp;
|
height = heighttemp;
|
||||||
@ -64,14 +64,13 @@ GuiBanner::GuiBanner( const char *tplfilepath )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
filecheck = false;
|
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;
|
||||||
return;
|
|
||||||
memory = mem;
|
memory = mem;
|
||||||
tplfilesize = len;
|
tplfilesize = len;
|
||||||
width = w;
|
width = w;
|
||||||
@ -81,30 +80,30 @@ GuiBanner::GuiBanner( void *mem, u32 len, int w, int h )
|
|||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = TPL_OpenTPLFromMemory( &tplfile, memory, tplfilesize );
|
ret = TPL_OpenTPLFromMemory(&tplfile, memory, tplfilesize);
|
||||||
if ( ret < 0 )
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
free( memory );
|
free(memory);
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ret = TPL_GetTexture( &tplfile, 0, &texObj );
|
ret = TPL_GetTexture(&tplfile, 0, &texObj);
|
||||||
if ( ret < 0 )
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
free( memory );
|
free(memory);
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TPL_CloseTPLFile( &tplfile );
|
TPL_CloseTPLFile(&tplfile);
|
||||||
|
|
||||||
filecheck = true;
|
filecheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiBanner::~GuiBanner()
|
GuiBanner::~GuiBanner()
|
||||||
{
|
{
|
||||||
if ( memory != NULL )
|
if (memory != NULL)
|
||||||
{
|
{
|
||||||
free( memory );
|
free(memory);
|
||||||
memory = NULL;
|
memory = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,12 +111,12 @@ GuiBanner::~GuiBanner()
|
|||||||
void GuiBanner::Draw()
|
void GuiBanner::Draw()
|
||||||
{
|
{
|
||||||
LOCK( this );
|
LOCK( this );
|
||||||
if ( !filecheck || !this->IsVisible() )
|
if (!filecheck || !this->IsVisible()) return;
|
||||||
return;
|
|
||||||
|
|
||||||
float currScale = this->GetScale();
|
float currScale = this->GetScale();
|
||||||
|
|
||||||
Menu_DrawTPLImg( this->GetLeft(), this->GetTop(), 0, width, height, &texObj, imageangle, widescreen ? currScale*0.80 : currScale, currScale, this->GetAlpha(), xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4 );
|
Menu_DrawTPLImg(this->GetLeft(), this->GetTop(), 0, width, height, &texObj, imageangle, widescreen ? currScale
|
||||||
|
* 0.80 : currScale, currScale, this->GetAlpha(), xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4);
|
||||||
|
|
||||||
this->UpdateEffects();
|
this->UpdateEffects();
|
||||||
}
|
}
|
||||||
|
@ -10,18 +10,18 @@
|
|||||||
|
|
||||||
#include "libwiigui/gui.h"
|
#include "libwiigui/gui.h"
|
||||||
|
|
||||||
class GuiBanner : public GuiImage
|
class GuiBanner: public GuiImage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//!Constructor
|
//!Constructor
|
||||||
//!\param tplfilepath Path of the tpl file
|
//!\param tplfilepath Path of the tpl file
|
||||||
GuiBanner( const char *tplfilepath );
|
GuiBanner(const char *tplfilepath);
|
||||||
//!Constructor
|
//!Constructor
|
||||||
//!\param mem Memory of the loaded tpl
|
//!\param mem Memory of the loaded tpl
|
||||||
//!\param len Filesize of the tpl
|
//!\param len Filesize of the tpl
|
||||||
//!\param w Width of the tpl
|
//!\param w Width of the tpl
|
||||||
//!\param h Height 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
|
//!Destructor
|
||||||
~GuiBanner();
|
~GuiBanner();
|
||||||
void Draw();
|
void Draw();
|
||||||
|
@ -28,50 +28,49 @@
|
|||||||
#include "../ramdisk/ramdisk.h"
|
#include "../ramdisk/ramdisk.h"
|
||||||
#include "../listfiles.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[0] = x >> 8;
|
||||||
p[1] = x;
|
p[1] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wbe32( u8 *p, u32 x )
|
void wbe32(u8 *p, u32 x)
|
||||||
{
|
{
|
||||||
wbe16( p, x >> 16 );
|
wbe16(p, x >> 16);
|
||||||
wbe16( p + 2, x );
|
wbe16(p + 2, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wbe64( u8 *p, u64 x )
|
void wbe64(u8 *p, u64 x)
|
||||||
{
|
{
|
||||||
wbe32( p, x >> 32 );
|
wbe32(p, x >> 32);
|
||||||
wbe32( p + 4, x );
|
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];
|
u8 zeroes[0x40];
|
||||||
@ -117,20 +116,20 @@ typedef struct
|
|||||||
u8 zeroes[16];
|
u8 zeroes[16];
|
||||||
} U8_archive_header;
|
} 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;
|
FILE *out;
|
||||||
out = fopen( name, "wb" );
|
out = fopen(name, "wb");
|
||||||
if ( out )
|
if (out)
|
||||||
{
|
{
|
||||||
written = fwrite( data, 1, size, out );
|
written = fwrite(data, 1, size, out);
|
||||||
fclose( 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 *data_end;
|
||||||
u8 *decompressed_data;
|
u8 *decompressed_data;
|
||||||
@ -145,43 +144,43 @@ u8* decompress_lz77( u8 *data, size_t data_size, size_t* decompressed_size )
|
|||||||
// Assume this for now and grow when needed
|
// Assume this for now and grow when needed
|
||||||
unpacked_size = data_size;
|
unpacked_size = data_size;
|
||||||
|
|
||||||
decompressed_data = malloc( unpacked_size );
|
decompressed_data = malloc(unpacked_size);
|
||||||
out_end = decompressed_data + unpacked_size;
|
out_end = decompressed_data + unpacked_size;
|
||||||
|
|
||||||
out_ptr = decompressed_data;
|
out_ptr = decompressed_data;
|
||||||
|
|
||||||
while ( in_ptr < data_end )
|
while (in_ptr < data_end)
|
||||||
{
|
{
|
||||||
int bit;
|
int bit;
|
||||||
u8 bitmask = *in_ptr;
|
u8 bitmask = *in_ptr;
|
||||||
|
|
||||||
in_ptr++;
|
in_ptr++;
|
||||||
for ( bit = 0x80; bit != 0; bit >>= 1 )
|
for (bit = 0x80; bit != 0; bit >>= 1)
|
||||||
{
|
{
|
||||||
if ( bitmask & bit )
|
if (bitmask & bit)
|
||||||
{
|
{
|
||||||
// Next section is compressed
|
// Next section is compressed
|
||||||
u8 rep_length;
|
u8 rep_length;
|
||||||
u16 rep_offset;
|
u16 rep_offset;
|
||||||
|
|
||||||
rep_length = ( *in_ptr >> 4 ) + 3;
|
rep_length = (*in_ptr >> 4) + 3;
|
||||||
rep_offset = *in_ptr & 0x0f;
|
rep_offset = *in_ptr & 0x0f;
|
||||||
in_ptr++;
|
in_ptr++;
|
||||||
rep_offset = *in_ptr | ( rep_offset << 8 );
|
rep_offset = *in_ptr | (rep_offset << 8);
|
||||||
in_ptr++;
|
in_ptr++;
|
||||||
if ( out_ptr - decompressed_data < rep_offset )
|
if (out_ptr - decompressed_data < rep_offset)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( ; rep_length > 0; rep_length-- )
|
for (; rep_length > 0; rep_length--)
|
||||||
{
|
{
|
||||||
*out_ptr = out_ptr[-rep_offset-1];
|
*out_ptr = out_ptr[-rep_offset - 1];
|
||||||
out_ptr++;
|
out_ptr++;
|
||||||
if ( out_ptr >= out_end )
|
if (out_ptr >= out_end)
|
||||||
{
|
{
|
||||||
// Need to grow buffer
|
// 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;
|
out_ptr = decompressed_data + unpacked_size;
|
||||||
unpacked_size *= 2;
|
unpacked_size *= 2;
|
||||||
out_end = decompressed_data + unpacked_size;
|
out_end = decompressed_data + unpacked_size;
|
||||||
@ -193,10 +192,10 @@ u8* decompress_lz77( u8 *data, size_t data_size, size_t* decompressed_size )
|
|||||||
// Just copy byte
|
// Just copy byte
|
||||||
*out_ptr = *in_ptr;
|
*out_ptr = *in_ptr;
|
||||||
out_ptr++;
|
out_ptr++;
|
||||||
if ( out_ptr >= out_end )
|
if (out_ptr >= out_end)
|
||||||
{
|
{
|
||||||
// Need to grow buffer
|
// 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;
|
out_ptr = decompressed_data + unpacked_size;
|
||||||
unpacked_size *= 2;
|
unpacked_size *= 2;
|
||||||
out_end = decompressed_data + unpacked_size;
|
out_end = decompressed_data + unpacked_size;
|
||||||
@ -206,58 +205,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;
|
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 tag;
|
||||||
u32 size_in_imd5;
|
u32 size_in_imd5;
|
||||||
u8 md5_calc[16];
|
u8 md5_calc[16];
|
||||||
u8 *decompressed_data;
|
u8 *decompressed_data;
|
||||||
size_t decompressed_size;
|
size_t decompressed_size;
|
||||||
|
|
||||||
tag = be32( ( u8* ) & header->imd5_tag );
|
tag = be32((u8*) &header->imd5_tag);
|
||||||
if ( tag != 0x494D4435 )
|
if (tag != 0x494D4435)
|
||||||
{
|
{
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
md5( data + 32, size - 32, md5_calc );
|
md5(data + 32, size - 32, md5_calc);
|
||||||
if ( memcmp( &header->md5, md5_calc, 0x10 ) )
|
if (memcmp(&header->md5, md5_calc, 0x10))
|
||||||
{
|
{
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_in_imd5 = be32( ( u8* ) & header->size );
|
size_in_imd5 = be32((u8*) &header->size);
|
||||||
if ( size_in_imd5 != size - 32 )
|
if (size_in_imd5 != size - 32)
|
||||||
{
|
{
|
||||||
return -6;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
tag = be32( ( u8* ) & header->payload_tag );
|
tag = be32((u8*) &header->payload_tag);
|
||||||
if ( tag == 0x4C5A3737 )
|
if (tag == 0x4C5A3737)
|
||||||
{
|
{
|
||||||
// "LZ77" - uncompress
|
// "LZ77" - uncompress
|
||||||
decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size );
|
decompressed_data = decompress_lz77(data + sizeof(imd5_header_t), size - sizeof(imd5_header_t),
|
||||||
if ( decompressed_data == NULL )
|
&decompressed_size);
|
||||||
return -7;
|
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);
|
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
|
||||||
|
|
||||||
free( decompressed_data );
|
free(decompressed_data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_file( &header->payload_tag, size - 32, outname );
|
write_file(&header->payload_tag, size - 32, outname);
|
||||||
//printf(", md5 ok");
|
//printf(", md5 ok");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_U8_archive( FILE *fp )
|
static int do_U8_archive(FILE *fp)
|
||||||
{
|
{
|
||||||
U8_archive_header header;
|
U8_archive_header header;
|
||||||
U8_node root_node;
|
U8_node root_node;
|
||||||
@ -272,42 +271,42 @@ static int do_U8_archive( FILE *fp )
|
|||||||
u16 dir_stack[16];
|
u16 dir_stack[16];
|
||||||
int dir_index = 0;
|
int dir_index = 0;
|
||||||
|
|
||||||
fread( &header, 1, sizeof header, fp );
|
fread(&header, 1, sizeof header, fp);
|
||||||
tag = be32( ( u8* ) & header.tag );
|
tag = be32((u8*) &header.tag);
|
||||||
if ( tag != 0x55AA382D )
|
if (tag != 0x55AA382D)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fread( &root_node, 1, sizeof( root_node ), fp );
|
fread(&root_node, 1, sizeof(root_node), fp);
|
||||||
num_nodes = be32( ( u8* ) & root_node.size ) - 1;
|
num_nodes = be32((u8*) &root_node.size) - 1;
|
||||||
//printf("Number of files: %d\n", num_nodes);
|
//printf("Number of files: %d\n", num_nodes);
|
||||||
|
|
||||||
nodes = malloc( sizeof( U8_node ) * ( num_nodes ) );
|
nodes = malloc(sizeof(U8_node) * (num_nodes));
|
||||||
fread( nodes, 1, num_nodes * sizeof( U8_node ), fp );
|
fread(nodes, 1, num_nodes * sizeof(U8_node), fp);
|
||||||
|
|
||||||
data_offset = be32( ( u8* ) & header.data_offset );
|
data_offset = be32((u8*) &header.data_offset);
|
||||||
rest_size = data_offset - sizeof( header ) - ( num_nodes + 1 ) * sizeof( U8_node );
|
rest_size = data_offset - sizeof(header) - (num_nodes + 1) * sizeof(U8_node);
|
||||||
|
|
||||||
string_table = malloc( rest_size );
|
string_table = malloc(rest_size);
|
||||||
fread( string_table, 1, rest_size, fp );
|
fread(string_table, 1, rest_size, fp);
|
||||||
current_offset = data_offset;
|
current_offset = data_offset;
|
||||||
|
|
||||||
for ( i = 0; i < num_nodes; i++ )
|
for (i = 0; i < num_nodes; i++)
|
||||||
{
|
{
|
||||||
U8_node* node = &nodes[i];
|
U8_node* node = &nodes[i];
|
||||||
u16 type = be16( ( u8* ) & node->type );
|
u16 type = be16((u8*) &node->type);
|
||||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
u16 name_offset = be16((u8*) &node->name_offset);
|
||||||
u32 my_data_offset = be32( ( u8* ) & node->data_offset );
|
u32 my_data_offset = be32((u8*) &node->data_offset);
|
||||||
u32 size = be32( ( u8* ) & node->size );
|
u32 size = be32((u8*) &node->size);
|
||||||
char* name = ( char* ) & string_table[name_offset];
|
char* name = (char*) &string_table[name_offset];
|
||||||
u8* file_data;
|
u8* file_data;
|
||||||
|
|
||||||
if ( type == 0x0100 )
|
if (type == 0x0100)
|
||||||
{
|
{
|
||||||
// Directory
|
// Directory
|
||||||
mkdir( name, 0777 );
|
mkdir(name, 0777);
|
||||||
chdir( name );
|
chdir(name);
|
||||||
dir_stack[++dir_index] = size;
|
dir_stack[++dir_index] = size;
|
||||||
//printf("%*s%s/\n", dir_index, "", name);
|
//printf("%*s%s/\n", dir_index, "", name);
|
||||||
}
|
}
|
||||||
@ -316,59 +315,59 @@ static int do_U8_archive( FILE *fp )
|
|||||||
// Normal file
|
// Normal file
|
||||||
u8 padding[32];
|
u8 padding[32];
|
||||||
|
|
||||||
if ( type != 0x0000 )
|
if (type != 0x0000)
|
||||||
{
|
{
|
||||||
free( string_table );
|
free(string_table);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( current_offset < my_data_offset )
|
if (current_offset < my_data_offset)
|
||||||
{
|
{
|
||||||
int diff = my_data_offset - current_offset;
|
int diff = my_data_offset - current_offset;
|
||||||
|
|
||||||
if ( diff > 32 )
|
if (diff > 32)
|
||||||
{
|
{
|
||||||
free( string_table );
|
free(string_table);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
fread( padding, 1, diff, fp );
|
fread(padding, 1, diff, fp);
|
||||||
current_offset += diff;
|
current_offset += diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_data = malloc( size );
|
file_data = malloc(size);
|
||||||
fread( file_data, 1, size, fp );
|
fread(file_data, 1, size, fp);
|
||||||
//printf("%*s %s (%d bytes", dir_index, "", name, size);
|
//printf("%*s %s (%d bytes", dir_index, "", name, size);
|
||||||
int result;
|
int result;
|
||||||
result = write_imd5_lz77( file_data, size, name );
|
result = write_imd5_lz77(file_data, size, name);
|
||||||
if ( result < 0 )
|
if (result < 0)
|
||||||
{
|
{
|
||||||
free( string_table );
|
free(string_table);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
//printf(")\n");
|
//printf(")\n");
|
||||||
current_offset += size;
|
current_offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
while (dir_stack[dir_index] == i + 2 && dir_index > 0)
|
||||||
{
|
{
|
||||||
chdir( ".." );
|
chdir("..");
|
||||||
dir_index--;
|
dir_index--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free( string_table );
|
free(string_table);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_imet_header( FILE *fp )
|
static void do_imet_header(FILE *fp)
|
||||||
{
|
{
|
||||||
imet_data_t header;
|
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_archive_header header;
|
||||||
U8_node root_node;
|
U8_node root_node;
|
||||||
@ -382,42 +381,42 @@ void do_U8_archivebanner( FILE *fp )
|
|||||||
u16 dir_stack[16];
|
u16 dir_stack[16];
|
||||||
int dir_index = 0;
|
int dir_index = 0;
|
||||||
|
|
||||||
fread( &header, 1, sizeof header, fp );
|
fread(&header, 1, sizeof header, fp);
|
||||||
tag = be32( ( u8* ) & header.tag );
|
tag = be32((u8*) &header.tag);
|
||||||
if ( tag != 0x55AA382D )
|
if (tag != 0x55AA382D)
|
||||||
{
|
{
|
||||||
//printf("No U8 tag");
|
//printf("No U8 tag");
|
||||||
exit( 0 );
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fread( &root_node, 1, sizeof( root_node ), fp );
|
fread(&root_node, 1, sizeof(root_node), fp);
|
||||||
num_nodes = be32( ( u8* ) & root_node.size ) - 1;
|
num_nodes = be32((u8*) &root_node.size) - 1;
|
||||||
printf( "Number of files: %d\n", num_nodes );
|
printf("Number of files: %d\n", num_nodes);
|
||||||
|
|
||||||
nodes = malloc( sizeof( U8_node ) * ( num_nodes ) );
|
nodes = malloc(sizeof(U8_node) * (num_nodes));
|
||||||
fread( nodes, 1, num_nodes * sizeof( U8_node ), fp );
|
fread(nodes, 1, num_nodes * sizeof(U8_node), fp);
|
||||||
|
|
||||||
data_offset = be32( ( u8* ) & header.data_offset );
|
data_offset = be32((u8*) &header.data_offset);
|
||||||
rest_size = data_offset - sizeof( header ) - ( num_nodes + 1 ) * sizeof( U8_node );
|
rest_size = data_offset - sizeof(header) - (num_nodes + 1) * sizeof(U8_node);
|
||||||
|
|
||||||
string_table = malloc( rest_size );
|
string_table = malloc(rest_size);
|
||||||
fread( string_table, 1, rest_size, fp );
|
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];
|
U8_node* node = &nodes[i];
|
||||||
u16 type = be16( ( u8* ) & node->type );
|
u16 type = be16((u8*) &node->type);
|
||||||
u16 name_offset = be16( ( u8* ) & node->name_offset );
|
u16 name_offset = be16((u8*) &node->name_offset);
|
||||||
u32 my_data_offset = be32( ( u8* ) & node->data_offset );
|
u32 my_data_offset = be32((u8*) &node->data_offset);
|
||||||
u32 size = be32( ( u8* ) & node->size );
|
u32 size = be32((u8*) &node->size);
|
||||||
char* name = ( char* ) & string_table[name_offset];
|
char* name = (char*) &string_table[name_offset];
|
||||||
u8* file_data;
|
u8* file_data;
|
||||||
|
|
||||||
if ( type == 0x0100 )
|
if (type == 0x0100)
|
||||||
{
|
{
|
||||||
// Directory
|
// Directory
|
||||||
mkdir( name, 0777 );
|
mkdir(name, 0777);
|
||||||
chdir( name );
|
chdir(name);
|
||||||
dir_stack[++dir_index] = size;
|
dir_stack[++dir_index] = size;
|
||||||
//printf("%*s%s/\n", dir_index, "", name);
|
//printf("%*s%s/\n", dir_index, "", name);
|
||||||
}
|
}
|
||||||
@ -425,56 +424,57 @@ void do_U8_archivebanner( FILE *fp )
|
|||||||
{
|
{
|
||||||
// Normal file
|
// Normal file
|
||||||
|
|
||||||
if ( type != 0x0000 )
|
if (type != 0x0000)
|
||||||
{
|
{
|
||||||
printf( "Unknown type" );
|
printf("Unknown type");
|
||||||
exit( 0 );
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek( fp, my_data_offset, SEEK_SET );
|
fseek(fp, my_data_offset, SEEK_SET);
|
||||||
file_data = malloc( size );
|
file_data = malloc(size);
|
||||||
fread( file_data, 1, size, fp );
|
fread(file_data, 1, size, fp);
|
||||||
write_file( file_data, size, name );
|
write_file(file_data, size, name);
|
||||||
free( file_data );
|
free(file_data);
|
||||||
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
|
//printf("%*s %s (%d bytes)\n", dir_index, "", name, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( dir_stack[dir_index] == i + 2 && dir_index > 0 )
|
while (dir_stack[dir_index] == i + 2 && dir_index > 0)
|
||||||
{
|
{
|
||||||
chdir( ".." );
|
chdir("..");
|
||||||
dir_index--;
|
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;
|
int ret = -1;
|
||||||
FILE *fp = fopen( filepath, "rb" );
|
FILE *fp = fopen(filepath, "rb");
|
||||||
if ( fp )
|
if (fp)
|
||||||
{
|
{
|
||||||
subfoldercreate( destpath );
|
subfoldercreate(destpath);
|
||||||
chdir( destpath );
|
chdir(destpath);
|
||||||
|
|
||||||
do_imet_header( fp );
|
do_imet_header(fp);
|
||||||
ret = do_U8_archive( fp );
|
ret = do_U8_archive(fp);
|
||||||
|
|
||||||
fclose( fp );
|
fclose(fp);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unpackBin( const char * filename, const char * outdir )
|
int unpackBin(const char * filename, const char * outdir)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen( filename, "rb" );;
|
FILE *fp = fopen(filename, "rb");
|
||||||
if ( fp )
|
;
|
||||||
|
if (fp)
|
||||||
{
|
{
|
||||||
subfoldercreate( outdir );
|
subfoldercreate(outdir);
|
||||||
chdir( outdir );
|
chdir(outdir);
|
||||||
|
|
||||||
do_U8_archivebanner( fp );
|
do_U8_archivebanner(fp);
|
||||||
fclose( fp );
|
fclose(fp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -483,81 +483,79 @@ int unpackBin( const char * filename, const char * outdir )
|
|||||||
#define TMP_PATH(s) "BANNER:/dump"s
|
#define TMP_PATH(s) "BANNER:/dump"s
|
||||||
//#define TMP_PATH(s) "SD:/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];
|
char path[256];
|
||||||
if ( !ramdiskMount( "BANNER", NULL ) ) return -1;
|
if (!ramdiskMount("BANNER", NULL)) return -1;
|
||||||
|
|
||||||
subfoldercreate( TMP_PATH( "/" ) );
|
subfoldercreate(TMP_PATH( "/" ));
|
||||||
s32 ret = dump_banner( gameid, TMP_PATH( "/opening.bnr" ) );
|
s32 ret = dump_banner(gameid, TMP_PATH( "/opening.bnr" ));
|
||||||
if ( ret != 1 )
|
if (ret != 1)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = extractbnrfile( TMP_PATH( "/opening.bnr" ), TMP_PATH( "/" ) );
|
ret = extractbnrfile(TMP_PATH( "/opening.bnr" ), TMP_PATH( "/" ));
|
||||||
if ( ret != 0 )
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( what & UNPACK_BANNER_BIN )
|
if (what & UNPACK_BANNER_BIN)
|
||||||
{
|
{
|
||||||
snprintf( path, sizeof( path ), "%sbanner/", outdir );
|
snprintf(path, sizeof(path), "%sbanner/", outdir);
|
||||||
ret = unpackBin( TMP_PATH( "/meta/banner.bin" ), path );
|
ret = unpackBin(TMP_PATH( "/meta/banner.bin" ), path);
|
||||||
if ( ret != 1 )
|
if (ret != 1)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( what & UNPACK_ICON_BIN )
|
if (what & UNPACK_ICON_BIN)
|
||||||
{
|
{
|
||||||
snprintf( path, sizeof( path ), "%sicon/", outdir );
|
snprintf(path, sizeof(path), "%sicon/", outdir);
|
||||||
ret = unpackBin( TMP_PATH( "/meta/icon.bin" ), path );
|
ret = unpackBin(TMP_PATH( "/meta/icon.bin" ), path);
|
||||||
if ( ret != 1 )
|
if (ret != 1)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( what & UNPACK_SOUND_BIN )
|
if (what & UNPACK_SOUND_BIN)
|
||||||
{
|
{
|
||||||
snprintf( path, sizeof( path ), "%ssound.bin", outdir );
|
snprintf(path, sizeof(path), "%ssound.bin", outdir);
|
||||||
FILE *fp = fopen( TMP_PATH( "/meta/sound.bin" ), "rb" );
|
FILE *fp = fopen(TMP_PATH( "/meta/sound.bin" ), "rb");
|
||||||
if ( fp )
|
if (fp)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
u8 *data;
|
u8 *data;
|
||||||
fseek( fp, 0, SEEK_END );
|
fseek(fp, 0, SEEK_END);
|
||||||
size = ftell( fp );
|
size = ftell(fp);
|
||||||
if ( !size )
|
if (!size)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
fseek( fp, 0, SEEK_SET );
|
fseek(fp, 0, SEEK_SET);
|
||||||
data = ( u8 * )malloc( size );
|
data = (u8 *) malloc(size);
|
||||||
if ( !data )
|
if (!data)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if ( fread( data, 1, size, fp ) != size )
|
if (fread(data, 1, size, fp) != size)
|
||||||
{
|
{
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto error;
|
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:
|
error2: if (ret < 0) return ret;
|
||||||
if ( ret < 0 )
|
|
||||||
return ret;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -25,20 +25,20 @@ extern "C"
|
|||||||
* -7 Inconsistency in LZ77 encoding
|
* -7 Inconsistency in LZ77 encoding
|
||||||
************************************************************/
|
************************************************************/
|
||||||
|
|
||||||
//! Extract opening.bnr from filepath to destpath
|
//! Extract opening.bnr from filepath to destpath
|
||||||
//! Files extracted: banner.bin icon.bin and sound.bin
|
//! Files extracted: banner.bin icon.bin and sound.bin
|
||||||
int extractbnrfile( const char * filepath, const char * destpath );
|
int extractbnrfile(const char * filepath, const char * destpath);
|
||||||
int unpackBin( const char * filename, const char * outdir );
|
int unpackBin(const char * filename, const char * outdir);
|
||||||
#define UNPACK_BANNER_BIN 1 /* extract banner.bin to outdir/banner/ */
|
#define UNPACK_BANNER_BIN 1 /* extract banner.bin to outdir/banner/ */
|
||||||
#define UNPACK_ICON_BIN 2 /* extract icon.bin to outdir/icon/ */
|
#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_SOUND_BIN 4 /* copies sound.bin to outdir/sound.bin */
|
||||||
#define UNPACK_ALL (UNPACK_SOUND_BIN | UNPACK_ICON_BIN | UNPACK_BANNER_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
|
//! 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 );
|
u16 be16(const u8 *p);
|
||||||
u32 be32( const u8 *p );
|
u32 be32(const u8 *p);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -10,14 +10,13 @@
|
|||||||
#include "language/gettext.h"
|
#include "language/gettext.h"
|
||||||
#include "bannersound.h"
|
#include "bannersound.h"
|
||||||
|
|
||||||
|
|
||||||
struct IMD5Header
|
struct IMD5Header
|
||||||
{
|
{
|
||||||
u32 fcc;
|
u32 fcc;
|
||||||
u32 filesize;
|
u32 filesize;
|
||||||
u8 zeroes[8];
|
u8 zeroes[8];
|
||||||
u8 crypto[16];
|
u8 crypto[16];
|
||||||
} __attribute__( ( packed ) );
|
}__attribute__( ( packed ) );
|
||||||
|
|
||||||
struct IMETHeader
|
struct IMETHeader
|
||||||
{
|
{
|
||||||
@ -31,7 +30,7 @@ struct IMETHeader
|
|||||||
u8 names[7][84];
|
u8 names[7][84];
|
||||||
u8 zeroes_2[0x348];
|
u8 zeroes_2[0x348];
|
||||||
u8 crypto[16];
|
u8 crypto[16];
|
||||||
} __attribute__( ( packed ) );
|
}__attribute__( ( packed ) );
|
||||||
|
|
||||||
struct U8Header
|
struct U8Header
|
||||||
{
|
{
|
||||||
@ -40,14 +39,14 @@ struct U8Header
|
|||||||
u32 headerSize;
|
u32 headerSize;
|
||||||
u32 dataOffset;
|
u32 dataOffset;
|
||||||
u8 zeroes[16];
|
u8 zeroes[16];
|
||||||
} __attribute__( ( packed ) );
|
}__attribute__( ( packed ) );
|
||||||
|
|
||||||
struct U8Entry
|
struct U8Entry
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u32 fileType : 8;
|
u32 fileType :8;
|
||||||
u32 nameOffset : 24;
|
u32 nameOffset :24;
|
||||||
};
|
};
|
||||||
u32 fileOffset;
|
u32 fileOffset;
|
||||||
union
|
union
|
||||||
@ -55,59 +54,56 @@ struct U8Entry
|
|||||||
u32 fileLength;
|
u32 fileLength;
|
||||||
u32 numEntries;
|
u32 numEntries;
|
||||||
};
|
};
|
||||||
} __attribute__( ( packed ) );
|
}__attribute__( ( packed ) );
|
||||||
|
|
||||||
struct LZ77Info
|
struct LZ77Info
|
||||||
{
|
{
|
||||||
u16 length : 4;
|
u16 length :4;
|
||||||
u16 offset : 12;
|
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;
|
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;
|
||||||
return NULL;
|
u32 uncSize = le32(((const u32 *) inBuf)[1] << 8);
|
||||||
u32 uncSize = le32( ( ( const u32 * )inBuf )[1] << 8 );
|
|
||||||
|
|
||||||
const u8 *inBufEnd = inBuf + inLength;
|
const u8 *inBufEnd = inBuf + inLength;
|
||||||
inBuf += 8;
|
inBuf += 8;
|
||||||
buffer = new( std::nothrow ) u8[uncSize];
|
buffer = new (std::nothrow) u8[uncSize];
|
||||||
if ( !buffer )
|
if (!buffer) return buffer;
|
||||||
return buffer;
|
|
||||||
|
|
||||||
u8 *bufCur = buffer;
|
u8 *bufCur = buffer;
|
||||||
u8 *bufEnd = buffer + uncSize;
|
u8 *bufEnd = buffer + uncSize;
|
||||||
|
|
||||||
while ( bufCur < bufEnd && inBuf < inBufEnd )
|
while (bufCur < bufEnd && inBuf < inBufEnd)
|
||||||
{
|
{
|
||||||
u8 flags = *inBuf;
|
u8 flags = *inBuf;
|
||||||
++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;
|
const LZ77Info &info = *(const LZ77Info *) inBuf;
|
||||||
inBuf += sizeof ( LZ77Info );
|
inBuf += sizeof(LZ77Info);
|
||||||
int length = info.length + 3;
|
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;
|
||||||
return buffer;
|
memcpy(bufCur, bufCur - info.offset - 1, length);
|
||||||
memcpy( bufCur, bufCur - info.offset - 1, length );
|
|
||||||
bufCur += length;
|
bufCur += length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -123,87 +119,86 @@ static u8 *uncompressLZ77( const u8 *inBuf, u32 inLength, u32 &size )
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *LoadBannerSound( const u8 *discid, u32 *size )
|
const u8 *LoadBannerSound(const u8 *discid, u32 *size)
|
||||||
{
|
{
|
||||||
if ( !discid )
|
if (!discid) return NULL;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Disc_SetUSB( NULL );
|
Disc_SetUSB(NULL);
|
||||||
wbfs_disc_t *disc = WBFS_OpenDisc( ( u8 * ) discid );
|
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) discid);
|
||||||
if ( !disc )
|
if (!disc)
|
||||||
{
|
{
|
||||||
// WindowPrompt(tr("Can't find disc"), 0, tr("OK"));
|
// WindowPrompt(tr("Can't find disc"), 0, tr("OK"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
wiidisc_t *wdisc = wd_open_disc( ( int ( * )( void *, u32, u32, void * ) )wbfs_disc_read, disc );
|
wiidisc_t *wdisc = wd_open_disc((int(*)(void *, u32, u32, void *)) wbfs_disc_read, disc);
|
||||||
if ( !wdisc )
|
if (!wdisc)
|
||||||
{
|
{
|
||||||
//WindowPrompt(tr("Could not open Disc"), 0, tr("OK"));
|
//WindowPrompt(tr("Could not open Disc"), 0, tr("OK"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
u8 * opening_bnr = wd_extract_file( wdisc, ALL_PARTITIONS, ( char * ) "opening.bnr" );
|
u8 * opening_bnr = wd_extract_file(wdisc, ALL_PARTITIONS, (char *) "opening.bnr");
|
||||||
if ( !opening_bnr )
|
if (!opening_bnr)
|
||||||
{
|
{
|
||||||
//WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK"));
|
//WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wd_close_disc( wdisc );
|
wd_close_disc(wdisc);
|
||||||
WBFS_CloseDisc( disc );
|
WBFS_CloseDisc(disc);
|
||||||
|
|
||||||
const U8Entry *fst;
|
const U8Entry *fst;
|
||||||
|
|
||||||
const IMETHeader *imetHdr = ( IMETHeader * )opening_bnr;
|
const IMETHeader *imetHdr = (IMETHeader *) opening_bnr;
|
||||||
if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ )
|
if (imetHdr->fcc != 0x494D4554 /*"IMET"*/)
|
||||||
{
|
{
|
||||||
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
// WindowPrompt(tr("IMET Header wrong."), 0, tr("OK"));
|
||||||
free( opening_bnr );
|
free(opening_bnr);
|
||||||
return NULL;
|
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;
|
u32 i;
|
||||||
for ( i = 1; i < fst[0].numEntries; ++i )
|
for (i = 1; i < fst[0].numEntries; ++i)
|
||||||
if ( fst[i].fileType == 0 && strcasecmp( u8Filename( fst, i ), "sound.bin" ) == 0 )
|
if (fst[i].fileType == 0 && strcasecmp(u8Filename(fst, i), "sound.bin") == 0) break;
|
||||||
break;
|
if (i >= fst[0].numEntries)
|
||||||
if ( i >= fst[0].numEntries )
|
|
||||||
{
|
{
|
||||||
/* Not all games have a sound.bin and this message is annoying **/
|
/* Not all games have a sound.bin and this message is annoying **/
|
||||||
//WindowPrompt(tr("sound.bin not found."), 0, tr("OK"));
|
//WindowPrompt(tr("sound.bin not found."), 0, tr("OK"));
|
||||||
free( opening_bnr );
|
free(opening_bnr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const u8 *sound_bin = ( ( const u8 * )bnrArcHdr ) + fst[i].fileOffset;
|
const u8 *sound_bin = ((const u8 *) bnrArcHdr) + fst[i].fileOffset;
|
||||||
if ( ( ( IMD5Header * )sound_bin )->fcc != 0x494D4435 /*"IMD5"*/ )
|
if (((IMD5Header *) sound_bin)->fcc != 0x494D4435 /*"IMD5"*/)
|
||||||
{
|
{
|
||||||
// WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK"));
|
// WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK"));
|
||||||
free( opening_bnr );
|
free(opening_bnr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const u8 *soundChunk = sound_bin + sizeof ( IMD5Header );;
|
const u8 *soundChunk = sound_bin + sizeof(IMD5Header);
|
||||||
u32 soundChunkSize = fst[i].fileLength - sizeof ( IMD5Header );
|
;
|
||||||
|
u32 soundChunkSize = fst[i].fileLength - sizeof(IMD5Header);
|
||||||
|
|
||||||
if ( *( ( u32* )soundChunk ) == 0x4C5A3737 /*"LZ77"*/ )
|
if (*((u32*) soundChunk) == 0x4C5A3737 /*"LZ77"*/)
|
||||||
{
|
{
|
||||||
u32 uncSize = NULL;
|
u32 uncSize = NULL;
|
||||||
u8 * uncompressed_data = uncompressLZ77( soundChunk, soundChunkSize, uncSize );
|
u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, uncSize);
|
||||||
if ( !uncompressed_data )
|
if (!uncompressed_data)
|
||||||
{
|
{
|
||||||
// WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK"));
|
// WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK"));
|
||||||
free( opening_bnr );
|
free(opening_bnr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if ( size ) *size = uncSize;
|
if (size) *size = uncSize;
|
||||||
free( opening_bnr );
|
free(opening_bnr);
|
||||||
return uncompressed_data;
|
return uncompressed_data;
|
||||||
}
|
}
|
||||||
u8 *out = new( std::nothrow ) u8[soundChunkSize];
|
u8 *out = new (std::nothrow) u8[soundChunkSize];
|
||||||
if ( out )
|
if (out)
|
||||||
{
|
{
|
||||||
memcpy( out, soundChunk, soundChunkSize );
|
memcpy(out, soundChunk, soundChunkSize);
|
||||||
if ( size ) *size = soundChunkSize;
|
if (size) *size = soundChunkSize;
|
||||||
}
|
}
|
||||||
free( opening_bnr );
|
free(opening_bnr);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#ifndef BANNERSOUND_H
|
#ifndef BANNERSOUND_H
|
||||||
#define BANNERSOUND_H
|
#define BANNERSOUND_H
|
||||||
|
|
||||||
const u8 *LoadBannerSound( const u8 *discid, u32 *size );
|
const u8 *LoadBannerSound(const u8 *discid, u32 *size);
|
||||||
|
|
||||||
#endif /* BANNERSOUND_H */
|
#endif /* BANNERSOUND_H */
|
||||||
|
@ -23,148 +23,148 @@ extern GuiWindow * mainWindow;
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* CheatMenu
|
* CheatMenu
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
int CheatMenu( const char * gameID )
|
int CheatMenu(const char * gameID)
|
||||||
{
|
{
|
||||||
int choice = 0;
|
int choice = 0;
|
||||||
bool exit = false;
|
bool exit = false;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
|
||||||
// because destroy GuiSound must wait while sound playing is finished, we use a global sound
|
// 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);
|
// GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
|
||||||
|
|
||||||
char imgPath[100];
|
char imgPath[100];
|
||||||
snprintf( imgPath, sizeof( imgPath ), "%sbutton_dialogue_box.png", Settings.theme_path );
|
snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", Settings.theme_path);
|
||||||
GuiImageData btnOutline( imgPath, button_dialogue_box_png );
|
GuiImageData btnOutline(imgPath, button_dialogue_box_png);
|
||||||
snprintf( imgPath, sizeof( imgPath ), "%ssettings_background.png", Settings.theme_path );
|
snprintf(imgPath, sizeof(imgPath), "%ssettings_background.png", Settings.theme_path);
|
||||||
GuiImageData settingsbg( imgPath, settings_background_png );
|
GuiImageData settingsbg(imgPath, settings_background_png);
|
||||||
GuiImage settingsbackground( &settingsbg );
|
GuiImage settingsbackground(&settingsbg);
|
||||||
|
|
||||||
GuiTrigger trigA;
|
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;
|
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 );
|
GuiText backBtnTxt(tr( "Back" ), 22, THEME.prompttext);
|
||||||
backBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
|
backBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30);
|
||||||
GuiImage backBtnImg( &btnOutline );
|
GuiImage backBtnImg(&btnOutline);
|
||||||
GuiButton backBtn( &backBtnImg, &backBtnImg, 2, 3, -140, 400, &trigA, NULL, btnClick2, 1 );
|
GuiButton backBtn(&backBtnImg, &backBtnImg, 2, 3, -140, 400, &trigA, NULL, btnClick2, 1);
|
||||||
backBtn.SetLabel( &backBtnTxt );
|
backBtn.SetLabel(&backBtnTxt);
|
||||||
backBtn.SetTrigger( &trigB );
|
backBtn.SetTrigger(&trigB);
|
||||||
|
|
||||||
GuiText createBtnTxt( tr( "Create" ) , 22, THEME.prompttext );
|
GuiText createBtnTxt(tr( "Create" ), 22, THEME.prompttext);
|
||||||
createBtnTxt.SetMaxWidth( btnOutline.GetWidth() - 30 );
|
createBtnTxt.SetMaxWidth(btnOutline.GetWidth() - 30);
|
||||||
GuiImage createBtnImg( &btnOutline );
|
GuiImage createBtnImg(&btnOutline);
|
||||||
GuiButton createBtn( &createBtnImg, &createBtnImg, 2, 3, 160, 400, &trigA, NULL, btnClick2, 1 );
|
GuiButton createBtn(&createBtnImg, &createBtnImg, 2, 3, 160, 400, &trigA, NULL, btnClick2, 1);
|
||||||
createBtn.SetLabel( &createBtnTxt );
|
createBtn.SetLabel(&createBtnTxt);
|
||||||
|
|
||||||
char txtfilename[55];
|
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;
|
GCTCheats c;
|
||||||
int check = c.openTxtfile( txtfilename );
|
int check = c.openTxtfile(txtfilename);
|
||||||
|
|
||||||
int download = 0;
|
int download = 0;
|
||||||
|
|
||||||
switch ( check )
|
switch (check)
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
WindowPrompt( tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ) );
|
WindowPrompt(tr( "Error" ), tr( "Cheatfile is blank" ), tr( "OK" ));
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
download = WindowPrompt( tr( "Error" ), tr( "No Cheatfile found" ), tr( "Download Now" ), tr( "Cancel" ) );
|
download = WindowPrompt(tr( "Error" ), tr( "No Cheatfile found" ), tr( "Download Now" ), tr( "Cancel" ));
|
||||||
if ( download == 1 )
|
if (download == 1)
|
||||||
{
|
{
|
||||||
download = CodeDownload( gameID );
|
download = CodeDownload(gameID);
|
||||||
if ( download < 0 || c.openTxtfile( txtfilename ) != 1 )
|
if (download < 0 || c.openTxtfile(txtfilename) != 1) break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else
|
else break;
|
||||||
break;
|
|
||||||
case 1:
|
case 1:
|
||||||
int cntcheats = c.getCnt();
|
int cntcheats = c.getCnt();
|
||||||
customOptionList cheatslst( cntcheats );
|
customOptionList cheatslst(cntcheats);
|
||||||
GuiCustomOptionBrowser chtBrowser( 400, 280, &cheatslst, Settings.theme_path, "bg_options_settings.png", bg_options_settings_png, 1, 90 );
|
GuiCustomOptionBrowser chtBrowser(400, 280, &cheatslst, Settings.theme_path, "bg_options_settings.png",
|
||||||
chtBrowser.SetPosition( 0, 90 );
|
bg_options_settings_png, 1, 90);
|
||||||
chtBrowser.SetAlignment( ALIGN_CENTRE, ALIGN_TOP );
|
chtBrowser.SetPosition(0, 90);
|
||||||
chtBrowser.SetClickable( true );
|
chtBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||||
|
chtBrowser.SetClickable(true);
|
||||||
|
|
||||||
GuiText titleTxt( c.getGameName().c_str(), 28, ( GXColor ) {0, 0, 0, 255} );
|
GuiText titleTxt(c.getGameName().c_str(), 28, ( GXColor )
|
||||||
titleTxt.SetAlignment( ALIGN_CENTRE, ALIGN_TOP );
|
{ 0, 0, 0, 255});
|
||||||
titleTxt.SetMaxWidth( 350, SCROLL_HORIZONTAL );
|
titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||||
titleTxt.SetPosition( 12, 40 );
|
titleTxt.SetMaxWidth(350, SCROLL_HORIZONTAL);
|
||||||
|
titleTxt.SetPosition(12, 40);
|
||||||
|
|
||||||
for ( int i = 0; i <= cntcheats; i++ )
|
for (int i = 0; i <= cntcheats; i++)
|
||||||
{
|
{
|
||||||
cheatslst.SetValue( i, "%s", c.getCheatName( i ).c_str() );
|
cheatslst.SetValue(i, "%s", c.getCheatName(i).c_str());
|
||||||
cheatslst.SetName( i, "OFF" );
|
cheatslst.SetName(i, "OFF");
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltGui();
|
HaltGui();
|
||||||
GuiWindow w( screenwidth, screenheight );
|
GuiWindow w(screenwidth, screenheight);
|
||||||
w.Append( &settingsbackground );
|
w.Append(&settingsbackground);
|
||||||
w.Append( &titleTxt );
|
w.Append(&titleTxt);
|
||||||
w.Append( &backBtn );
|
w.Append(&backBtn);
|
||||||
w.Append( &createBtn );
|
w.Append(&createBtn);
|
||||||
w.Append( &chtBrowser );
|
w.Append(&chtBrowser);
|
||||||
mainWindow->SetState( STATE_DISABLED );
|
mainWindow->SetState(STATE_DISABLED);
|
||||||
mainWindow->ChangeFocus( &w );
|
mainWindow->ChangeFocus(&w);
|
||||||
mainWindow->Append( &w );
|
mainWindow->Append(&w);
|
||||||
ResumeGui();
|
ResumeGui();
|
||||||
|
|
||||||
while ( !exit )
|
while (!exit)
|
||||||
{
|
{
|
||||||
VIDEO_WaitVSync ();
|
VIDEO_WaitVSync();
|
||||||
|
|
||||||
ret = chtBrowser.GetClickedOption();
|
ret = chtBrowser.GetClickedOption();
|
||||||
if ( ret != -1 )
|
if (ret != -1)
|
||||||
{
|
{
|
||||||
const char *strCheck = cheatslst.GetName( ret );
|
const char *strCheck = cheatslst.GetName(ret);
|
||||||
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
if (strncmp(strCheck, "ON", 2) == 0)
|
||||||
{
|
{
|
||||||
cheatslst.SetName( ret, "%s", "OFF" );
|
cheatslst.SetName(ret, "%s", "OFF");
|
||||||
}
|
}
|
||||||
else if ( strncmp( strCheck, "OFF", 3 ) == 0 )
|
else if (strncmp(strCheck, "OFF", 3) == 0)
|
||||||
{
|
{
|
||||||
cheatslst.SetName( ret, "%s", "ON" );
|
cheatslst.SetName(ret, "%s", "ON");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( createBtn.GetState() == STATE_CLICKED )
|
if (createBtn.GetState() == STATE_CLICKED)
|
||||||
{
|
{
|
||||||
createBtn.ResetState();
|
createBtn.ResetState();
|
||||||
if ( cntcheats > 0 )
|
if (cntcheats > 0)
|
||||||
{
|
{
|
||||||
int selectednrs[30];
|
int selectednrs[30];
|
||||||
int x = 0;
|
int x = 0;
|
||||||
for ( int i = 0; i <= cntcheats; i++ )
|
for (int i = 0; i <= cntcheats; i++)
|
||||||
{
|
{
|
||||||
const char *strCheck = cheatslst.GetName( i );
|
const char *strCheck = cheatslst.GetName(i);
|
||||||
if ( strncmp( strCheck, "ON", 2 ) == 0 )
|
if (strncmp(strCheck, "ON", 2) == 0)
|
||||||
{
|
{
|
||||||
selectednrs[x] = i;
|
selectednrs[x] = i;
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( x == 0 )
|
if (x == 0)
|
||||||
{
|
{
|
||||||
WindowPrompt( tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ) );
|
WindowPrompt(tr( "Error" ), tr( "No cheats were selected" ), tr( "OK" ));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
subfoldercreate( Settings.Cheatcodespath );
|
subfoldercreate(Settings.Cheatcodespath);
|
||||||
string chtpath = Settings.Cheatcodespath;
|
string chtpath = Settings.Cheatcodespath;
|
||||||
string gctfname = chtpath + c.getGameID() + ".gct";
|
string gctfname = chtpath + c.getGameID() + ".gct";
|
||||||
c.createGCT( selectednrs, x, gctfname.c_str() );
|
c.createGCT(selectednrs, x, gctfname.c_str());
|
||||||
WindowPrompt( tr( "GCT File created" ), NULL, tr( "OK" ) );
|
WindowPrompt(tr( "GCT File created" ), NULL, tr( "OK" ));
|
||||||
exit = true;
|
exit = true;
|
||||||
break;
|
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();
|
backBtn.ResetState();
|
||||||
exit = true;
|
exit = true;
|
||||||
@ -172,8 +172,8 @@ int CheatMenu( const char * gameID )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
HaltGui();
|
HaltGui();
|
||||||
mainWindow->SetState( STATE_DEFAULT );
|
mainWindow->SetState(STATE_DEFAULT);
|
||||||
mainWindow->Remove( &w );
|
mainWindow->Remove(&w);
|
||||||
ResumeGui();
|
ResumeGui();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,6 @@
|
|||||||
#ifndef _CHEATMENU_H_
|
#ifndef _CHEATMENU_H_
|
||||||
#define _CHEATMENU_H_
|
#define _CHEATMENU_H_
|
||||||
|
|
||||||
int CheatMenu( const char * gameID );
|
int CheatMenu(const char * gameID);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,12 +12,12 @@
|
|||||||
|
|
||||||
#define ERRORRANGE "Error: CheatNr out of range"
|
#define ERRORRANGE "Error: CheatNr out of range"
|
||||||
|
|
||||||
GCTCheats::GCTCheats( void )
|
GCTCheats::GCTCheats(void)
|
||||||
{
|
{
|
||||||
iCntCheats = 0;
|
iCntCheats = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GCTCheats::~GCTCheats( void )
|
GCTCheats::~GCTCheats(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
string sGameID = "";
|
string sGameID = "";
|
||||||
@ -32,19 +32,19 @@ int GCTCheats::getCnt()
|
|||||||
return iCntCheats;
|
return iCntCheats;
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getGameName( void )
|
string GCTCheats::getGameName(void)
|
||||||
{
|
{
|
||||||
return sGameTitle;
|
return sGameTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getGameID( void )
|
string GCTCheats::getGameID(void)
|
||||||
{
|
{
|
||||||
return sGameID;
|
return sGameID;
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getCheat( int nr )
|
string GCTCheats::getCheat(int nr)
|
||||||
{
|
{
|
||||||
if ( nr <= ( iCntCheats - 1 ) )
|
if (nr <= (iCntCheats - 1))
|
||||||
{
|
{
|
||||||
return sCheats[nr];
|
return sCheats[nr];
|
||||||
}
|
}
|
||||||
@ -54,9 +54,9 @@ string GCTCheats::getCheat( int nr )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getCheatName( int nr )
|
string GCTCheats::getCheatName(int nr)
|
||||||
{
|
{
|
||||||
if ( nr <= ( iCntCheats - 1 ) )
|
if (nr <= (iCntCheats - 1))
|
||||||
{
|
{
|
||||||
return sCheatName[nr];
|
return sCheatName[nr];
|
||||||
}
|
}
|
||||||
@ -66,9 +66,9 @@ string GCTCheats::getCheatName( int nr )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string GCTCheats::getCheatComment( int nr )
|
string GCTCheats::getCheatComment(int nr)
|
||||||
{
|
{
|
||||||
if ( nr <= ( iCntCheats - 1 ) )
|
if (nr <= (iCntCheats - 1))
|
||||||
{
|
{
|
||||||
return sCheatComment[nr];
|
return sCheatComment[nr];
|
||||||
}
|
}
|
||||||
@ -78,210 +78,200 @@ string GCTCheats::getCheatComment( int nr )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::createGCT( int nr, const char * filename )
|
int GCTCheats::createGCT(int nr, const char * filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ( nr == 0 )
|
if (nr == 0) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
ofstream filestr;
|
ofstream filestr;
|
||||||
filestr.open( filename );
|
filestr.open(filename);
|
||||||
|
|
||||||
if ( filestr.fail() )
|
if (filestr.fail()) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
//Header and Footer
|
//Header and Footer
|
||||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde};
|
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde };
|
||||||
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
string buf = getCheat( nr );
|
string buf = getCheat(nr);
|
||||||
filestr.write( header, sizeof( header ) );
|
filestr.write(header, sizeof(header));
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
long int li;
|
long int li;
|
||||||
int len = buf.size();
|
int len = buf.size();
|
||||||
|
|
||||||
while ( x < len )
|
while (x < len)
|
||||||
{
|
{
|
||||||
string temp = buf.substr( x, 2 );
|
string temp = buf.substr(x, 2);
|
||||||
li = strtol( temp.c_str(), NULL, 16 );
|
li = strtol(temp.c_str(), NULL, 16);
|
||||||
temp = li;
|
temp = li;
|
||||||
filestr.write( temp.c_str(), 1 );
|
filestr.write(temp.c_str(), 1);
|
||||||
x += 2;
|
x += 2;
|
||||||
}
|
}
|
||||||
filestr.write( footer, sizeof( footer ) );
|
filestr.write(footer, sizeof(footer));
|
||||||
|
|
||||||
filestr.close();
|
filestr.close();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::createGCT( const char * chtbuffer, const char * filename )
|
int GCTCheats::createGCT(const char * chtbuffer, const char * filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
ofstream filestr;
|
ofstream filestr;
|
||||||
filestr.open( filename );
|
filestr.open(filename);
|
||||||
|
|
||||||
if ( filestr.fail() )
|
if (filestr.fail()) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
//Header and Footer
|
//Header and Footer
|
||||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde};
|
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde };
|
||||||
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
string buf = chtbuffer;
|
string buf = chtbuffer;
|
||||||
filestr.write( header, sizeof( header ) );
|
filestr.write(header, sizeof(header));
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
long int li;
|
long int li;
|
||||||
int len = buf.size();
|
int len = buf.size();
|
||||||
|
|
||||||
while ( x < len )
|
while (x < len)
|
||||||
{
|
{
|
||||||
string temp = buf.substr( x, 2 );
|
string temp = buf.substr(x, 2);
|
||||||
li = strtol( temp.c_str(), NULL, 16 );
|
li = strtol(temp.c_str(), NULL, 16);
|
||||||
temp = li;
|
temp = li;
|
||||||
filestr.write( temp.c_str(), 1 );
|
filestr.write(temp.c_str(), 1);
|
||||||
x += 2;
|
x += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
filestr.write( footer, sizeof( footer ) );
|
filestr.write(footer, sizeof(footer));
|
||||||
|
|
||||||
filestr.close();
|
filestr.close();
|
||||||
|
|
||||||
return 1;
|
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;
|
||||||
return 0;
|
|
||||||
|
|
||||||
ofstream filestr;
|
ofstream filestr;
|
||||||
filestr.open( filename );
|
filestr.open(filename);
|
||||||
|
|
||||||
if ( filestr.fail() )
|
if (filestr.fail()) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
//Header and Footer
|
//Header and Footer
|
||||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde};
|
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde };
|
||||||
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
filestr.write( header, sizeof( header ) );
|
filestr.write(header, sizeof(header));
|
||||||
|
|
||||||
int c = 0;
|
int c = 0;
|
||||||
while ( c != cnt )
|
while (c != cnt)
|
||||||
{
|
{
|
||||||
int actnr = nr[c];
|
int actnr = nr[c];
|
||||||
string buf = getCheat( actnr );
|
string buf = getCheat(actnr);
|
||||||
long int li;
|
long int li;
|
||||||
int len = buf.size();
|
int len = buf.size();
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
|
||||||
while ( x < len )
|
while (x < len)
|
||||||
{
|
{
|
||||||
string temp = buf.substr( x, 2 );
|
string temp = buf.substr(x, 2);
|
||||||
li = strtol( temp.c_str(), NULL, 16 );
|
li = strtol(temp.c_str(), NULL, 16);
|
||||||
temp = li;
|
temp = li;
|
||||||
filestr.write( temp.c_str(), 1 );
|
filestr.write(temp.c_str(), 1);
|
||||||
x += 2;
|
x += 2;
|
||||||
}
|
}
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
filestr.write( footer, sizeof( footer ) );
|
filestr.write(footer, sizeof(footer));
|
||||||
filestr.close();
|
filestr.close();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GCTCheats::openTxtfile( const char * filename )
|
int GCTCheats::openTxtfile(const char * filename)
|
||||||
{
|
{
|
||||||
ifstream filestr;
|
ifstream filestr;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
string str;
|
string str;
|
||||||
filestr.open( filename );
|
filestr.open(filename);
|
||||||
|
|
||||||
if ( filestr.fail() )
|
if (filestr.fail()) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
filestr.seekg( 0, ios_base::end );
|
filestr.seekg(0, ios_base::end);
|
||||||
int size = filestr.tellg();
|
int size = filestr.tellg();
|
||||||
if ( size <= 0 ) return -1;
|
if (size <= 0) return -1;
|
||||||
filestr.seekg( 0, ios_base::beg );
|
filestr.seekg(0, ios_base::beg);
|
||||||
|
|
||||||
getline( filestr, sGameID );
|
getline(filestr, sGameID);
|
||||||
if ( sGameID[sGameID.length() - 1] == '\r' )
|
if (sGameID[sGameID.length() - 1] == '\r') sGameID.erase(sGameID.length() - 1);
|
||||||
sGameID.erase( sGameID.length() - 1 );
|
|
||||||
|
|
||||||
getline( filestr, sGameTitle );
|
getline(filestr, sGameTitle);
|
||||||
if ( sGameTitle[sGameTitle.length() - 1] == '\r' )
|
if (sGameTitle[sGameTitle.length() - 1] == '\r') sGameTitle.erase(sGameTitle.length() - 1);
|
||||||
sGameTitle.erase( sGameTitle.length() - 1 );
|
|
||||||
|
|
||||||
getline( filestr, sCheatName[i] ); // skip first line if file uses CRLF
|
getline(filestr, sCheatName[i]); // skip first line if file uses CRLF
|
||||||
if ( !sGameTitle[sGameTitle.length() - 1] == '\r' )
|
if (!sGameTitle[sGameTitle.length() - 1] == '\r') filestr.seekg(0, ios_base::beg);
|
||||||
filestr.seekg( 0, ios_base::beg );
|
|
||||||
|
|
||||||
while ( !filestr.eof() )
|
while (!filestr.eof())
|
||||||
{
|
{
|
||||||
getline( filestr, sCheatName[i] ); // '\n' delimiter by default
|
getline(filestr, sCheatName[i]); // '\n' delimiter by default
|
||||||
if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' )
|
if (sCheatName[i][sCheatName[i].length() - 1] == '\r') sCheatName[i].erase(sCheatName[i].length() - 1);
|
||||||
sCheatName[i].erase( sCheatName[i].length() - 1 );
|
|
||||||
|
|
||||||
string cheatdata;
|
string cheatdata;
|
||||||
bool emptyline = false;
|
bool emptyline = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
getline( filestr, str );
|
getline(filestr, str);
|
||||||
if ( str[str.length() - 1] == '\r' )
|
if (str[str.length() - 1] == '\r') str.erase(str.length() - 1);
|
||||||
str.erase( str.length() - 1 );
|
|
||||||
|
|
||||||
if ( str == "" || str[0] == '\r' || str[0] == '\n' )
|
if (str == "" || str[0] == '\r' || str[0] == '\n')
|
||||||
{
|
{
|
||||||
emptyline = true;
|
emptyline = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( IsCode( str ) )
|
if (IsCode(str))
|
||||||
{
|
{
|
||||||
// remove any garbage (comment) after code
|
// remove any garbage (comment) after code
|
||||||
while ( str.size() > 17 )
|
while (str.size() > 17)
|
||||||
{
|
{
|
||||||
str.erase( str.length() - 1 );
|
str.erase(str.length() - 1);
|
||||||
}
|
}
|
||||||
cheatdata.append( str );
|
cheatdata.append(str);
|
||||||
size_t found = cheatdata.find( ' ' );
|
size_t found = cheatdata.find(' ');
|
||||||
cheatdata.replace( found, 1, "" );
|
cheatdata.replace(found, 1, "");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//printf("%i",str.size());
|
//printf("%i",str.size());
|
||||||
sCheatComment[i] = str;
|
sCheatComment[i] = str;
|
||||||
}
|
}
|
||||||
if ( filestr.eof() ) break;
|
if (filestr.eof()) break;
|
||||||
|
|
||||||
}
|
} while (!emptyline);
|
||||||
while ( !emptyline );
|
|
||||||
|
|
||||||
sCheats[i] = cheatdata;
|
sCheats[i] = cheatdata;
|
||||||
i++;
|
i++;
|
||||||
if ( i == MAXCHEATS ) break;
|
if (i == MAXCHEATS) break;
|
||||||
}
|
}
|
||||||
iCntCheats = i;
|
iCntCheats = i;
|
||||||
filestr.close();
|
filestr.close();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCTCheats::IsCode( const std::string& str )
|
bool GCTCheats::IsCode(const std::string& str)
|
||||||
{
|
{
|
||||||
if ( str[8] == ' ' && str.size() >= 17 )
|
if (str[8] == ' ' && str.size() >= 17)
|
||||||
{
|
{
|
||||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||||
char part1[9];
|
char part1[9];
|
||||||
char part2[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(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],
|
||||||
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] );
|
str[7]);
|
||||||
if ( ( strtok( part1, "0123456789ABCDEFabcdef" ) == NULL ) && ( strtok( part2, "0123456789ABCDEFabcdef" ) == NULL ) )
|
snprintf(part2, sizeof(part2), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14],
|
||||||
|
str[15], str[16]);
|
||||||
|
if ((strtok(part1, "0123456789ABCDEFabcdef") == NULL) && (strtok(part2, "0123456789ABCDEFabcdef") == NULL))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -26,50 +26,50 @@ class GCTCheats
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
//!Constructor
|
//!Constructor
|
||||||
GCTCheats( void );
|
GCTCheats(void);
|
||||||
//!Destructor
|
//!Destructor
|
||||||
~GCTCheats( void );
|
~GCTCheats(void);
|
||||||
//!Open txt file with cheats
|
//!Open txt file with cheats
|
||||||
//!\param filename name of TXT file
|
//!\param filename name of TXT file
|
||||||
//!\return error code
|
//!\return error code
|
||||||
int openTxtfile( const char * filename );
|
int openTxtfile(const char * filename);
|
||||||
//!Creates GCT file for one cheat
|
//!Creates GCT file for one cheat
|
||||||
//!\param nr selected Cheat Numbers
|
//!\param nr selected Cheat Numbers
|
||||||
//!\param filename name of GCT file
|
//!\param filename name of GCT file
|
||||||
//!\return error code
|
//!\return error code
|
||||||
int createGCT( int nr, const char * filename );
|
int createGCT(int nr, const char * filename);
|
||||||
//!Creates GCT file from a buffer
|
//!Creates GCT file from a buffer
|
||||||
//!\param chtbuffer buffer that holds the cheat data
|
//!\param chtbuffer buffer that holds the cheat data
|
||||||
//!\param filename name of GCT file
|
//!\param filename name of GCT file
|
||||||
//!\return error code
|
//!\return error code
|
||||||
int createGCT( const char * chtbuffer, const char * filename );
|
int createGCT(const char * chtbuffer, const char * filename);
|
||||||
//!Creates GCT file
|
//!Creates GCT file
|
||||||
//!\param nr[] array of selected Cheat Numbers
|
//!\param nr[] array of selected Cheat Numbers
|
||||||
//!\param cnt size of array
|
//!\param cnt size of array
|
||||||
//!\param filename name of GCT file
|
//!\param filename name of GCT file
|
||||||
//!\return error code
|
//!\return error code
|
||||||
int createGCT( int nr[], int cnt, const char * filename );
|
int createGCT(int nr[], int cnt, const char * filename);
|
||||||
//!Gets Count cheats
|
//!Gets Count cheats
|
||||||
//!\return Count cheats
|
//!\return Count cheats
|
||||||
int getCnt();
|
int getCnt();
|
||||||
//!Gets Game Name
|
//!Gets Game Name
|
||||||
//!\return Game Name
|
//!\return Game Name
|
||||||
string getGameName( void );
|
string getGameName(void);
|
||||||
//!Gets GameID
|
//!Gets GameID
|
||||||
//!\return GameID
|
//!\return GameID
|
||||||
string getGameID( void );
|
string getGameID(void);
|
||||||
//!Gets cheat data
|
//!Gets cheat data
|
||||||
//!\return cheat data
|
//!\return cheat data
|
||||||
string getCheat( int nr );
|
string getCheat(int nr);
|
||||||
//!Gets Cheat Name
|
//!Gets Cheat Name
|
||||||
//!\return Cheat Name
|
//!\return Cheat Name
|
||||||
string getCheatName( int nr );
|
string getCheatName(int nr);
|
||||||
//!Gets Cheat Comment
|
//!Gets Cheat Comment
|
||||||
//!\return Cheat Comment
|
//!\return Cheat Comment
|
||||||
string getCheatComment( int nr );
|
string getCheatComment(int nr);
|
||||||
//!Check if string is a code
|
//!Check if string is a code
|
||||||
//!\return true/false
|
//!\return true/false
|
||||||
bool IsCode( const std::string& s );
|
bool IsCode(const std::string& s);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _GCT_H */
|
#endif /* _GCT_H */
|
||||||
|
@ -47,28 +47,28 @@ sec_t fs_ntfs_sec = 0;
|
|||||||
int USBDevice_Init()
|
int USBDevice_Init()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "USBDevice_Init()" );
|
gprintf("USBDevice_Init()");
|
||||||
#endif
|
#endif
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "USB:/" );
|
fatUnmount("USB:/");
|
||||||
//right now mounts first FAT-partition
|
//right now mounts first FAT-partition
|
||||||
|
|
||||||
//try first mount with cIOS
|
//try first mount with cIOS
|
||||||
// if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
// if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||||
// //try now mount with libogc
|
// //try now mount with libogc
|
||||||
if ( !fatMount( "USB", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
if (!fatMount("USB", &__io_usbstorage2, 0, CACHE, SECTORS))
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( ":-1\n" );
|
gprintf(":-1\n");
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fat_usb_mount = 1;
|
fat_usb_mount = 1;
|
||||||
fat_usb_sec = _FAT_startSector;
|
fat_usb_sec = _FAT_startSector;
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( ":0\n" );
|
gprintf(":0\n");
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -76,36 +76,36 @@ int USBDevice_Init()
|
|||||||
void USBDevice_deInit()
|
void USBDevice_deInit()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "USBDevice_deInit(): " );
|
gprintf("USBDevice_deInit(): ");
|
||||||
#endif
|
#endif
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "USB:/" );
|
fatUnmount("USB:/");
|
||||||
|
|
||||||
fat_usb_mount = 0;
|
fat_usb_mount = 0;
|
||||||
fat_usb_sec = 0;
|
fat_usb_sec = 0;
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "ok\n" );
|
gprintf("ok\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int WBFSDevice_Init( u32 sector )
|
int WBFSDevice_Init(u32 sector)
|
||||||
{
|
{
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "WBFS:/" );
|
fatUnmount("WBFS:/");
|
||||||
//right now mounts first FAT-partition
|
//right now mounts first FAT-partition
|
||||||
|
|
||||||
//try first mount with cIOS
|
//try first mount with cIOS
|
||||||
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
// if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||||
//try now mount with libogc
|
//try now mount with libogc
|
||||||
if ( !fatMount( "WBFS", &__io_usbstorage2, 0, CACHE, SECTORS ) )
|
if (!fatMount("WBFS", &__io_usbstorage2, 0, CACHE, SECTORS))
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fat_wbfs_mount = 1;
|
fat_wbfs_mount = 1;
|
||||||
fat_wbfs_sec = _FAT_startSector;
|
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
|
// This is an error situation...actually, but is ignored in Config loader also
|
||||||
// Should ask Oggzee about it...
|
// Should ask Oggzee about it...
|
||||||
@ -116,16 +116,15 @@ int WBFSDevice_Init( u32 sector )
|
|||||||
void WBFSDevice_deInit()
|
void WBFSDevice_deInit()
|
||||||
{
|
{
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "WBFS:/" );
|
fatUnmount("WBFS:/");
|
||||||
|
|
||||||
fat_wbfs_mount = 0;
|
fat_wbfs_mount = 0;
|
||||||
fat_wbfs_sec = 0;
|
fat_wbfs_sec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isInserted( const char *path )
|
int isInserted(const char *path)
|
||||||
{
|
{
|
||||||
if ( !strncmp( path, "USB:", 4 ) )
|
if (!strncmp(path, "USB:", 4)) return 1;
|
||||||
return 1;
|
|
||||||
|
|
||||||
return __io_sdhc.isInserted() || __io_wiisd.isInserted();
|
return __io_sdhc.isInserted() || __io_wiisd.isInserted();
|
||||||
}
|
}
|
||||||
@ -134,33 +133,33 @@ static u8 sdIsInited = 0;
|
|||||||
int SDCard_Init()
|
int SDCard_Init()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "SDCard_Init()" );
|
gprintf("SDCard_Init()");
|
||||||
#endif
|
#endif
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
fatUnmount( "SD:/" );
|
fatUnmount("SD:/");
|
||||||
//right now mounts first FAT-partition
|
//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_mount = MOUNT_SD;
|
||||||
fat_sd_sec = _FAT_startSector;
|
fat_sd_sec = _FAT_startSector;
|
||||||
sdIsInited = 1;
|
sdIsInited = 1;
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( ":1\n" );
|
gprintf(":1\n");
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
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_mount = MOUNT_SDHC;
|
||||||
fat_sd_sec = _FAT_startSector;
|
fat_sd_sec = _FAT_startSector;
|
||||||
sdIsInited = 1;
|
sdIsInited = 1;
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( ":1\n" );
|
gprintf(":1\n");
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( ":-1\n" );
|
gprintf(":-1\n");
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -168,29 +167,29 @@ int SDCard_Init()
|
|||||||
void SDCard_deInit()
|
void SDCard_deInit()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "SDCard_deInit( %d ): ", sdIsInited );
|
gprintf("SDCard_deInit( %d ): ", sdIsInited);
|
||||||
#endif
|
#endif
|
||||||
//closing all open Files write back the cache and then shutdown em!
|
//closing all open Files write back the cache and then shutdown em!
|
||||||
if( sdIsInited )
|
if (sdIsInited)
|
||||||
{
|
{
|
||||||
fatUnmount( "SD:/" );
|
fatUnmount("SD:/");
|
||||||
|
|
||||||
fat_sd_mount = MOUNT_NONE;
|
fat_sd_mount = MOUNT_NONE;
|
||||||
fat_sd_sec = 0;
|
fat_sd_sec = 0;
|
||||||
sdIsInited = 0;
|
sdIsInited = 0;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_FAT
|
#ifdef DEBUG_FAT
|
||||||
gprintf( "ok\n" );
|
gprintf("ok\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ntfsInit();
|
void ntfsInit();
|
||||||
|
|
||||||
s32 MountNTFS( u32 sector )
|
s32 MountNTFS(u32 sector)
|
||||||
{
|
{
|
||||||
s32 ret;
|
s32 ret;
|
||||||
|
|
||||||
if ( fs_ntfs_mount ) return 0;
|
if (fs_ntfs_mount) return 0;
|
||||||
//printf("mounting NTFS\n");
|
//printf("mounting NTFS\n");
|
||||||
//Wpad_WaitButtons();
|
//Wpad_WaitButtons();
|
||||||
_FAT_mem_init();
|
_FAT_mem_init();
|
||||||
@ -200,39 +199,39 @@ s32 MountNTFS( u32 sector )
|
|||||||
// ntfsInit resets locale settings
|
// ntfsInit resets locale settings
|
||||||
// which breaks unicode in console
|
// which breaks unicode in console
|
||||||
// so we change it back to C-UTF-8
|
// so we change it back to C-UTF-8
|
||||||
setlocale( LC_CTYPE, "C-UTF-8" );
|
setlocale(LC_CTYPE, "C-UTF-8");
|
||||||
setlocale( LC_MESSAGES, "C-UTF-8" );
|
setlocale(LC_MESSAGES, "C-UTF-8");
|
||||||
|
|
||||||
if ( wbfsDev == WBFS_DEVICE_USB )
|
if (wbfsDev == WBFS_DEVICE_USB)
|
||||||
{
|
{
|
||||||
/* Initialize WBFS interface */
|
/* Initialize WBFS interface */
|
||||||
// if (!__io_wiiums.startup()) {
|
// if (!__io_wiiums.startup()) {
|
||||||
ret = __io_usbstorage2.startup();
|
ret = __io_usbstorage2.startup();
|
||||||
if ( !ret )
|
if (!ret)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
/* Mount device */
|
/* Mount device */
|
||||||
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
// 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_RECOVER );
|
ret = ntfsMount("NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||||
if ( !ret )
|
if (!ret)
|
||||||
{
|
{
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
else if ( wbfsDev == WBFS_DEVICE_SDHC )
|
else if (wbfsDev == WBFS_DEVICE_SDHC)
|
||||||
{
|
{
|
||||||
if ( sdhc_mode_sd == 0 )
|
if (sdhc_mode_sd == 0)
|
||||||
{
|
{
|
||||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER );
|
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER );
|
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||||
}
|
}
|
||||||
if ( !ret )
|
if (!ret)
|
||||||
{
|
{
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
@ -244,10 +243,10 @@ s32 MountNTFS( u32 sector )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 UnmountNTFS( void )
|
s32 UnmountNTFS(void)
|
||||||
{
|
{
|
||||||
/* Unmount device */
|
/* Unmount device */
|
||||||
ntfsUnmount( "NTFS:/", true );
|
ntfsUnmount("NTFS:/", true);
|
||||||
|
|
||||||
fs_ntfs_mount = 0;
|
fs_ntfs_mount = 0;
|
||||||
fs_ntfs_sec = 0;
|
fs_ntfs_sec = 0;
|
||||||
@ -259,17 +258,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);
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,14 @@ extern "C"
|
|||||||
|
|
||||||
int USBDevice_Init();
|
int USBDevice_Init();
|
||||||
void USBDevice_deInit();
|
void USBDevice_deInit();
|
||||||
int WBFSDevice_Init( u32 sector );
|
int WBFSDevice_Init(u32 sector);
|
||||||
void WBFSDevice_deInit();
|
void WBFSDevice_deInit();
|
||||||
int isInserted( const char *path );
|
int isInserted(const char *path);
|
||||||
int SDCard_Init();
|
int SDCard_Init();
|
||||||
void SDCard_deInit();
|
void SDCard_deInit();
|
||||||
|
|
||||||
s32 MountNTFS( u32 sector );
|
s32 MountNTFS(u32 sector);
|
||||||
s32 UnmountNTFS( void );
|
s32 UnmountNTFS(void);
|
||||||
|
|
||||||
extern int fat_usb_mount;
|
extern int fat_usb_mount;
|
||||||
extern sec_t fat_usb_sec;
|
extern sec_t fat_usb_sec;
|
||||||
|
@ -125,21 +125,21 @@ extern const u32 icon_archives_png_size;
|
|||||||
extern const u8 icon_folder_png[];
|
extern const u8 icon_folder_png[];
|
||||||
extern const u32 icon_folder_png_size;
|
extern const u32 icon_folder_png_size;
|
||||||
/*
|
/*
|
||||||
extern const u8 icon_gfx_png[];
|
extern const u8 icon_gfx_png[];
|
||||||
extern const u32 icon_gfx_png_size;
|
extern const u32 icon_gfx_png_size;
|
||||||
|
|
||||||
extern const u8 icon_pls_png[];
|
extern const u8 icon_pls_png[];
|
||||||
extern const u32 icon_pls_png_size;
|
extern const u32 icon_pls_png_size;
|
||||||
|
|
||||||
extern const u8 icon_sfx_png[];
|
extern const u8 icon_sfx_png[];
|
||||||
extern const u32 icon_sfx_png_size;
|
extern const u32 icon_sfx_png_size;
|
||||||
|
|
||||||
extern const u8 icon_txt_png[];
|
extern const u8 icon_txt_png[];
|
||||||
extern const u32 icon_txt_png_size;
|
extern const u32 icon_txt_png_size;
|
||||||
|
|
||||||
extern const u8 icon_xml_png[];
|
extern const u8 icon_xml_png[];
|
||||||
extern const u32 icon_xml_png_size;
|
extern const u32 icon_xml_png_size;
|
||||||
*/
|
*/
|
||||||
extern const u8 bg_browser_selection_png[];
|
extern const u8 bg_browser_selection_png[];
|
||||||
extern const u32 bg_browser_selection_png_size;
|
extern const u32 bg_browser_selection_png_size;
|
||||||
|
|
||||||
@ -478,11 +478,11 @@ extern const u32 nintendods_png_size;
|
|||||||
extern const u8 nintendodsR_png[];
|
extern const u8 nintendodsR_png[];
|
||||||
extern const u32 nintendodsR_png_size;
|
extern const u32 nintendodsR_png_size;
|
||||||
/*
|
/*
|
||||||
extern const u8 vitalitysensor_png[];
|
extern const u8 vitalitysensor_png[];
|
||||||
extern const u32 vitalitysensor_png_size;
|
extern const u32 vitalitysensor_png_size;
|
||||||
extern const u8 vitalitysensor_png[];
|
extern const u8 vitalitysensor_png[];
|
||||||
extern const u32 vitalitysensorR_png_size;
|
extern const u32 vitalitysensorR_png_size;
|
||||||
*/
|
*/
|
||||||
extern const u8 esrb_ec_png[];
|
extern const u8 esrb_ec_png[];
|
||||||
extern const u32 esrb_ec_png_size;
|
extern const u32 esrb_ec_png_size;
|
||||||
|
|
||||||
|
@ -10,72 +10,66 @@ bool textVideoInit = false;
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
//using the gprintf from crediar because it is smaller than mine
|
//using the gprintf from crediar because it is smaller than mine
|
||||||
void gprintf( const char *str, ... )
|
void gprintf(const char *str, ...)
|
||||||
{
|
{
|
||||||
if ( !( geckoinit ) )return;
|
if (!(geckoinit)) return;
|
||||||
|
|
||||||
char astr[ 0x100 ];
|
char astr[0x100];
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start( ap, str );
|
va_start( ap, str );
|
||||||
|
|
||||||
vsprintf( astr, str, ap );
|
vsprintf(astr, str, ap);
|
||||||
|
|
||||||
va_end( ap );
|
va_end( ap );
|
||||||
|
|
||||||
usb_sendbuffer( 1, astr, strlen( astr ) );
|
usb_sendbuffer(1, astr, strlen(astr));
|
||||||
//usb_sendbuffer_safe( 1, astr, strlen(astr) );
|
//usb_sendbuffer_safe( 1, astr, strlen(astr) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InitGecko()
|
bool InitGecko()
|
||||||
{
|
{
|
||||||
u32 geckoattached = usb_isgeckoalive( EXI_CHANNEL_1 );
|
u32 geckoattached = usb_isgeckoalive(EXI_CHANNEL_1);
|
||||||
if ( geckoattached )
|
if (geckoattached)
|
||||||
{
|
{
|
||||||
usb_flush( EXI_CHANNEL_1 );
|
usb_flush(EXI_CHANNEL_1);
|
||||||
CON_EnableGecko( 1, true );
|
CON_EnableGecko(1, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char ascii( char s )
|
char ascii(char s)
|
||||||
{
|
{
|
||||||
if ( s < 0x20 )
|
if (s < 0x20) return '.';
|
||||||
return '.';
|
if (s > 0x7E) return '.';
|
||||||
if ( s > 0x7E )
|
|
||||||
return '.';
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hexdump( void *d, int len )
|
void hexdump(void *d, int len)
|
||||||
{
|
{
|
||||||
u8 *data;
|
u8 *data;
|
||||||
int i, off;
|
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 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF");
|
||||||
gprintf( "\n==== =============================================== ================\n" );
|
gprintf("\n==== =============================================== ================\n");
|
||||||
|
|
||||||
for ( off = 0; off < len; off += 16 )
|
for (off = 0; off < len; off += 16)
|
||||||
{
|
{
|
||||||
gprintf( "%04x ", off );
|
gprintf("%04x ", off);
|
||||||
for ( i = 0; i < 16; i++ )
|
for (i = 0; i < 16; i++)
|
||||||
if ( ( i + off ) >= len )
|
if ((i + off) >= len)
|
||||||
gprintf( " " );
|
gprintf(" ");
|
||||||
else
|
else gprintf("%02x ", data[off + i]);
|
||||||
gprintf( "%02x ", data[off+i] );
|
|
||||||
|
|
||||||
gprintf( " " );
|
gprintf(" ");
|
||||||
for ( i = 0; i < 16; i++ )
|
for (i = 0; i < 16; i++)
|
||||||
if ( ( i + off ) >= len )
|
if ((i + off) >= len)
|
||||||
gprintf( " " );
|
gprintf(" ");
|
||||||
else
|
else gprintf("%c", ascii(data[off + i]));
|
||||||
gprintf( "%c", ascii( data[off+i] ) );
|
gprintf("\n");
|
||||||
gprintf( "\n" );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* NO_DEBUG */
|
#endif /* NO_DEBUG */
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifndef _GECKO_H_
|
#ifndef _GECKO_H_
|
||||||
#define _GECKO_H_
|
#define _GECKO_H_
|
||||||
|
|
||||||
@ -8,21 +7,19 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char ascii( char s );
|
char ascii(char s);
|
||||||
|
|
||||||
#ifndef NO_DEBUG
|
#ifndef NO_DEBUG
|
||||||
//use this just like printf();
|
//use this just like printf();
|
||||||
void gprintf( const char *str, ... );
|
void gprintf(const char *str, ...);
|
||||||
bool InitGecko();
|
bool InitGecko();
|
||||||
void hexdump( void *d, int len );
|
void hexdump(void *d, int len);
|
||||||
#else
|
#else
|
||||||
#define gprintf(...)
|
#define gprintf(...)
|
||||||
#define InitGecko() false
|
#define InitGecko() false
|
||||||
#define hexdump( x, y )
|
#define hexdump( x, y )
|
||||||
#endif /* NO_DEBUG */
|
#endif /* NO_DEBUG */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -153,83 +153,79 @@ int BootHomebrew( const char * filepath )
|
|||||||
#include "fatmounter.h"
|
#include "fatmounter.h"
|
||||||
#include "dolloader.h"
|
#include "dolloader.h"
|
||||||
|
|
||||||
|
|
||||||
void *innetbuffer = NULL;
|
void *innetbuffer = NULL;
|
||||||
static u8 *homebrewbuffer = ( u8 * )0x92000000;
|
static u8 *homebrewbuffer = (u8 *) 0x92000000;
|
||||||
u32 homebrewsize = 0;
|
u32 homebrewsize = 0;
|
||||||
static std::vector<std::string> Arguments;
|
static std::vector<std::string> Arguments;
|
||||||
|
|
||||||
extern const u8 app_booter_dol[];
|
extern const u8 app_booter_dol[];
|
||||||
|
|
||||||
int AllocHomebrewMemory( u32 filesize )
|
int AllocHomebrewMemory(u32 filesize)
|
||||||
{
|
{
|
||||||
|
|
||||||
innetbuffer = malloc( filesize );
|
innetbuffer = malloc(filesize);
|
||||||
|
|
||||||
if ( !innetbuffer )
|
if (!innetbuffer) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
homebrewsize = filesize;
|
homebrewsize = filesize;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddBootArgument( const char * argv )
|
void AddBootArgument(const char * argv)
|
||||||
{
|
{
|
||||||
std::string arg( argv );
|
std::string arg(argv);
|
||||||
Arguments.push_back( arg );
|
Arguments.push_back(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CopyHomebrewMemory( u8 *temp, u32 pos, u32 len )
|
int CopyHomebrewMemory(u8 *temp, u32 pos, u32 len)
|
||||||
{
|
{
|
||||||
homebrewsize += len;
|
homebrewsize += len;
|
||||||
memcpy( ( homebrewbuffer ) + pos, temp, len );
|
memcpy((homebrewbuffer) + pos, temp, len);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeHomebrewBuffer()
|
void FreeHomebrewBuffer()
|
||||||
{
|
{
|
||||||
homebrewbuffer = ( u8 * ) 0x92000000;
|
homebrewbuffer = (u8 *) 0x92000000;
|
||||||
homebrewsize = 0;
|
homebrewsize = 0;
|
||||||
|
|
||||||
if ( innetbuffer )
|
if (innetbuffer)
|
||||||
{
|
{
|
||||||
free( innetbuffer );
|
free(innetbuffer);
|
||||||
innetbuffer = NULL;
|
innetbuffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arguments.clear();
|
Arguments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SetupARGV( struct __argv * args )
|
static int SetupARGV(struct __argv * args)
|
||||||
{
|
{
|
||||||
if ( !args )
|
if (!args) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
bzero( args, sizeof( struct __argv ) );
|
bzero(args, sizeof(struct __argv));
|
||||||
args->argvMagic = ARGV_MAGIC;
|
args->argvMagic = ARGV_MAGIC;
|
||||||
|
|
||||||
u32 stringlength = 1;
|
u32 stringlength = 1;
|
||||||
|
|
||||||
/** Append Arguments **/
|
/** 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->length = stringlength;
|
||||||
args->commandLine = ( char* ) malloc( args->length );
|
args->commandLine = (char*) malloc(args->length);
|
||||||
|
|
||||||
if ( !args->commandLine )
|
if (!args->commandLine) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
u32 argc = 0;
|
u32 argc = 0;
|
||||||
u32 position = 0;
|
u32 position = 0;
|
||||||
|
|
||||||
/** Append Arguments **/
|
/** 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() );
|
strcpy(&args->commandLine[position], Arguments[i].c_str());
|
||||||
position += Arguments[i].size() + 1;
|
position += Arguments[i].size() + 1;
|
||||||
argc++;
|
argc++;
|
||||||
}
|
}
|
||||||
@ -247,17 +243,16 @@ static int SetupARGV( struct __argv * args )
|
|||||||
|
|
||||||
static int RunAppbooter()
|
static int RunAppbooter()
|
||||||
{
|
{
|
||||||
if ( homebrewsize == 0 )
|
if (homebrewsize == 0) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
struct __argv args;
|
struct __argv args;
|
||||||
SetupARGV( &args );
|
SetupARGV(&args);
|
||||||
|
|
||||||
u32 cpu_isr;
|
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 )
|
if (!entry)
|
||||||
{
|
{
|
||||||
FreeHomebrewBuffer();
|
FreeHomebrewBuffer();
|
||||||
return -1;
|
return -1;
|
||||||
@ -266,25 +261,24 @@ static int RunAppbooter()
|
|||||||
u64 currentStub = getStubDest();
|
u64 currentStub = getStubDest();
|
||||||
loadStub();
|
loadStub();
|
||||||
|
|
||||||
if ( Set_Stub_Split( 0x00010001, "UNEO" ) < 0 )
|
if (Set_Stub_Split(0x00010001, "UNEO") < 0)
|
||||||
{
|
{
|
||||||
if ( Set_Stub_Split( 0x00010001, "ULNR" ) < 0 )
|
if (Set_Stub_Split(0x00010001, "ULNR") < 0)
|
||||||
{
|
{
|
||||||
if ( !currentStub )
|
if (!currentStub) currentStub = 0x100000002ULL;
|
||||||
currentStub = 0x100000002ULL;
|
|
||||||
|
|
||||||
Set_Stub( currentStub );
|
Set_Stub(currentStub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDCard_deInit();
|
SDCard_deInit();
|
||||||
USBDevice_deInit();
|
USBDevice_deInit();
|
||||||
|
|
||||||
WPAD_Flush( 0 );
|
WPAD_Flush(0);
|
||||||
WPAD_Disconnect( 0 );
|
WPAD_Disconnect(0);
|
||||||
WPAD_Shutdown();
|
WPAD_Shutdown();
|
||||||
|
|
||||||
SYS_ResetSystem( SYS_SHUTDOWN, 0, 0 );
|
SYS_ResetSystem(SYS_SHUTDOWN, 0, 0);
|
||||||
_CPU_ISR_Disable( cpu_isr );
|
_CPU_ISR_Disable( cpu_isr );
|
||||||
__exception_closeall();
|
__exception_closeall();
|
||||||
entry();
|
entry();
|
||||||
@ -293,59 +287,58 @@ static int RunAppbooter()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BootHomebrew( char * filepath )
|
int BootHomebrew(char * filepath)
|
||||||
{
|
{
|
||||||
void *buffer = NULL;
|
void *buffer = NULL;
|
||||||
u32 filesize = 0;
|
u32 filesize = 0;
|
||||||
|
|
||||||
FILE *file = fopen( filepath, "rb" );
|
FILE *file = fopen(filepath, "rb");
|
||||||
|
|
||||||
if ( !file )
|
if (!file) Sys_BackToLoader();
|
||||||
Sys_BackToLoader();
|
|
||||||
|
|
||||||
fseek( file, 0, SEEK_END );
|
fseek(file, 0, SEEK_END);
|
||||||
filesize = ftell( file );
|
filesize = ftell(file);
|
||||||
rewind( file );
|
rewind(file);
|
||||||
|
|
||||||
buffer = malloc( filesize );
|
buffer = malloc(filesize);
|
||||||
|
|
||||||
if ( fread( buffer, 1, filesize, file ) != filesize )
|
if (fread(buffer, 1, filesize, file) != filesize)
|
||||||
{
|
{
|
||||||
fclose( file );
|
fclose(file);
|
||||||
free( buffer );
|
free(buffer);
|
||||||
SDCard_deInit();
|
SDCard_deInit();
|
||||||
USBDevice_deInit();
|
USBDevice_deInit();
|
||||||
Sys_BackToLoader();
|
Sys_BackToLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose( file );
|
fclose(file);
|
||||||
|
|
||||||
CopyHomebrewMemory( ( u8* ) buffer, 0, filesize );
|
CopyHomebrewMemory((u8*) buffer, 0, filesize);
|
||||||
|
|
||||||
if ( buffer )
|
if (buffer)
|
||||||
{
|
{
|
||||||
free( buffer );
|
free(buffer);
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddBootArgument( filepath );
|
AddBootArgument(filepath);
|
||||||
return RunAppbooter();
|
return RunAppbooter();
|
||||||
}
|
}
|
||||||
|
|
||||||
int BootHomebrewFromMem()
|
int BootHomebrewFromMem()
|
||||||
{
|
{
|
||||||
gprintf( "BootHomebrewFromMem()\n %p, %08x\n", innetbuffer, homebrewsize );
|
gprintf("BootHomebrewFromMem()\n %p, %08x\n", innetbuffer, homebrewsize);
|
||||||
|
|
||||||
if ( !innetbuffer )
|
if (!innetbuffer)
|
||||||
{
|
{
|
||||||
gprintf( "!innetbuffer\n" );
|
gprintf("!innetbuffer\n");
|
||||||
SDCard_deInit();
|
SDCard_deInit();
|
||||||
USBDevice_deInit();
|
USBDevice_deInit();
|
||||||
Sys_BackToLoader();
|
Sys_BackToLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyHomebrewMemory( ( u8* ) innetbuffer, 0, homebrewsize );
|
CopyHomebrewMemory((u8*) innetbuffer, 0, homebrewsize);
|
||||||
free( innetbuffer );
|
free(innetbuffer);
|
||||||
|
|
||||||
return RunAppbooter();
|
return RunAppbooter();
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
//int BootHomebrew();
|
//int BootHomebrew();
|
||||||
int BootHomebrewFromMem();
|
int BootHomebrewFromMem();
|
||||||
int BootHomebrew( char * filepath );
|
int BootHomebrew(char * filepath);
|
||||||
int CopyHomebrewMemory( u8 *temp, u32 pos, u32 len );
|
int CopyHomebrewMemory(u8 *temp, u32 pos, u32 len);
|
||||||
void AddBootArgument( const char * arg );
|
void AddBootArgument(const char * arg);
|
||||||
void FreeHomebrewBuffer();
|
void FreeHomebrewBuffer();
|
||||||
int LoadHomebrew( const char * filepath );
|
int LoadHomebrew(const char * filepath);
|
||||||
int AllocHomebrewMemory( u32 filesize );
|
int AllocHomebrewMemory(u32 filesize);
|
||||||
extern void *innetbuffer;
|
extern void *innetbuffer;
|
||||||
extern u32 homebrewsize;
|
extern u32 homebrewsize;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@
|
|||||||
#ifndef _HOMEBREWBROWSE_H_
|
#ifndef _HOMEBREWBROWSE_H_
|
||||||
#define _HOMEBREWBROWSE_H_
|
#define _HOMEBREWBROWSE_H_
|
||||||
|
|
||||||
int roundup( float number );
|
int roundup(float number);
|
||||||
int MenuHomebrewBrowse();
|
int MenuHomebrewBrowse();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,113 +9,110 @@
|
|||||||
|
|
||||||
#include "HomebrewFiles.h"
|
#include "HomebrewFiles.h"
|
||||||
|
|
||||||
HomebrewFiles::HomebrewFiles( const char * path )
|
HomebrewFiles::HomebrewFiles(const char * path)
|
||||||
{
|
{
|
||||||
filecount = 0;
|
filecount = 0;
|
||||||
|
|
||||||
FileInfo = ( FileInfos * ) malloc( sizeof( FileInfos ) );
|
FileInfo = (FileInfos *) malloc(sizeof(FileInfos));
|
||||||
if ( !FileInfo )
|
if (!FileInfo)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset( &FileInfo[filecount], 0, sizeof( FileInfos ) );
|
memset(&FileInfo[filecount], 0, sizeof(FileInfos));
|
||||||
|
|
||||||
this->LoadPath( path );
|
this->LoadPath(path);
|
||||||
this->SortList();
|
this->SortList();
|
||||||
}
|
}
|
||||||
|
|
||||||
HomebrewFiles::~HomebrewFiles()
|
HomebrewFiles::~HomebrewFiles()
|
||||||
{
|
{
|
||||||
if ( FileInfo )
|
if (FileInfo)
|
||||||
{
|
{
|
||||||
free( FileInfo );
|
free(FileInfo);
|
||||||
FileInfo = NULL;
|
FileInfo = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HomebrewFiles::LoadPath( const char * folderpath )
|
bool HomebrewFiles::LoadPath(const char * folderpath)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
DIR_ITER *dir = NULL;
|
DIR_ITER *dir = NULL;
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
|
|
||||||
dir = diropen( folderpath );
|
dir = diropen(folderpath);
|
||||||
if ( dir == NULL )
|
if (dir == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( dirnext( dir, filename, &st ) == 0 )
|
while (dirnext(dir, filename, &st) == 0)
|
||||||
{
|
{
|
||||||
if ( ( st.st_mode & S_IFDIR ) != 0 )
|
if ((st.st_mode & S_IFDIR) != 0)
|
||||||
{
|
{
|
||||||
if ( strcmp( filename, "." ) != 0 && strcmp( filename, ".." ) != 0 )
|
if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0)
|
||||||
{
|
{
|
||||||
char currentname[200];
|
char currentname[200];
|
||||||
snprintf( currentname, sizeof( currentname ), "%s%s/", folderpath, filename );
|
snprintf(currentname, sizeof(currentname), "%s%s/", folderpath, filename);
|
||||||
this->LoadPath( currentname );
|
this->LoadPath(currentname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char temp[5];
|
char temp[5];
|
||||||
for ( int i = 0; i < 5; i++ )
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
temp[i] = filename[strlen( filename )-4+i];
|
temp[i] = filename[strlen(filename) - 4 + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 )
|
if ((strncasecmp(temp, ".dol", 4) == 0 || strncasecmp(temp, ".elf", 4) == 0) && filecount < MAXHOMEBREWS
|
||||||
&& filecount < MAXHOMEBREWS && filename[0] != '.' )
|
&& filename[0] != '.')
|
||||||
{
|
{
|
||||||
|
|
||||||
FileInfo = ( FileInfos * ) realloc( FileInfo, ( filecount + 1 ) * sizeof( FileInfos ) );
|
FileInfo = (FileInfos *) realloc(FileInfo, (filecount + 1) * sizeof(FileInfos));
|
||||||
|
|
||||||
if ( !FileInfo )
|
if (!FileInfo)
|
||||||
{
|
{
|
||||||
free( FileInfo );
|
free(FileInfo);
|
||||||
FileInfo = NULL;
|
FileInfo = NULL;
|
||||||
filecount = 0;
|
filecount = 0;
|
||||||
dirclose( dir );
|
dirclose(dir);
|
||||||
return false;
|
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].FilePath, folderpath, sizeof(FileInfo[filecount].FilePath));
|
||||||
strlcpy( FileInfo[filecount].FileName, filename, sizeof( FileInfo[filecount].FileName ) );
|
strlcpy(FileInfo[filecount].FileName, filename, sizeof(FileInfo[filecount].FileName));
|
||||||
FileInfo[filecount].FileSize = st.st_size;
|
FileInfo[filecount].FileSize = st.st_size;
|
||||||
filecount++;
|
filecount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dirclose( dir );
|
dirclose(dir);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * HomebrewFiles::GetFilename( int ind )
|
char * HomebrewFiles::GetFilename(int ind)
|
||||||
{
|
{
|
||||||
if ( ind > filecount )
|
if (ind > filecount)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else return FileInfo[ind].FileName;
|
||||||
return FileInfo[ind].FileName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char * HomebrewFiles::GetFilepath( int ind )
|
char * HomebrewFiles::GetFilepath(int ind)
|
||||||
{
|
{
|
||||||
if ( ind > filecount )
|
if (ind > filecount)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else return FileInfo[ind].FilePath;
|
||||||
return FileInfo[ind].FilePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int HomebrewFiles::GetFilesize( int ind )
|
unsigned int HomebrewFiles::GetFilesize(int ind)
|
||||||
{
|
{
|
||||||
if ( ind > filecount || !filecount || !FileInfo )
|
if (ind > filecount || !filecount || !FileInfo)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else return FileInfo[ind].FileSize;
|
||||||
return FileInfo[ind].FileSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int HomebrewFiles::GetFilecount()
|
int HomebrewFiles::GetFilecount()
|
||||||
@ -123,14 +120,14 @@ int HomebrewFiles::GetFilecount()
|
|||||||
return filecount;
|
return filecount;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ListCompare( const void *a, const void *b )
|
static int ListCompare(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
FileInfos *ab = ( FileInfos* ) a;
|
FileInfos *ab = (FileInfos*) a;
|
||||||
FileInfos *bb = ( FileInfos* ) b;
|
FileInfos *bb = (FileInfos*) b;
|
||||||
|
|
||||||
return stricmp( ( char * ) ab->FilePath, ( char * ) bb->FilePath );
|
return stricmp((char *) ab->FilePath, (char *) bb->FilePath);
|
||||||
}
|
}
|
||||||
void HomebrewFiles::SortList()
|
void HomebrewFiles::SortList()
|
||||||
{
|
{
|
||||||
qsort( FileInfo, filecount, sizeof( FileInfos ), ListCompare );
|
qsort(FileInfo, filecount, sizeof(FileInfos), ListCompare);
|
||||||
}
|
}
|
||||||
|
@ -19,21 +19,21 @@ class HomebrewFiles
|
|||||||
public:
|
public:
|
||||||
//!Constructor
|
//!Constructor
|
||||||
//!\param path Path where to check for homebrew files
|
//!\param path Path where to check for homebrew files
|
||||||
HomebrewFiles( const char * path );
|
HomebrewFiles(const char * path);
|
||||||
//!Destructor
|
//!Destructor
|
||||||
~HomebrewFiles();
|
~HomebrewFiles();
|
||||||
//! Load the dol/elf list of a path
|
//! Load the dol/elf list of a path
|
||||||
//!\param path Path where to check for homebrew files
|
//!\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
|
//! Get the a filename of the list
|
||||||
//!\param list index
|
//!\param list index
|
||||||
char * GetFilename( int index );
|
char * GetFilename(int index);
|
||||||
//! Get the a filepath of the list
|
//! Get the a filepath of the list
|
||||||
//!\param list index
|
//!\param list index
|
||||||
char * GetFilepath( int index );
|
char * GetFilepath(int index);
|
||||||
//! Get the a filesize of the list
|
//! Get the a filesize of the list
|
||||||
//!\param list index
|
//!\param list index
|
||||||
unsigned int GetFilesize( int index );
|
unsigned int GetFilesize(int index);
|
||||||
//! Get the filecount of the whole list
|
//! Get the filecount of the whole list
|
||||||
int GetFilecount();
|
int GetFilecount();
|
||||||
//! Sort list by filepath
|
//! Sort list by filepath
|
||||||
|
@ -11,60 +11,110 @@
|
|||||||
|
|
||||||
#define ENTRIE_SIZE 8192
|
#define ENTRIE_SIZE 8192
|
||||||
|
|
||||||
int HomebrewXML::LoadHomebrewXMLData( const char* filename )
|
/* Initializes a new instance of the HomebrewXML class. */
|
||||||
|
HomebrewXML::HomebrewXML()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalizes an instance of the HomebrewXML class. */
|
||||||
|
HomebrewXML::~HomebrewXML()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qparam filename Filepath of the XML file */
|
||||||
|
int HomebrewXML::LoadHomebrewXMLData(const char* filename)
|
||||||
{
|
{
|
||||||
mxml_node_t *nodedataHB = NULL;
|
mxml_node_t *nodedataHB = NULL;
|
||||||
mxml_node_t *nodetreeHB = NULL;
|
mxml_node_t *nodetreeHB = NULL;
|
||||||
|
|
||||||
/* Load XML file */
|
/* Load XML file */
|
||||||
FILE *filexml;
|
FILE *filexml;
|
||||||
filexml = fopen( filename, "rb" );
|
filexml = fopen(filename, "rb");
|
||||||
if ( !filexml )
|
if (!filexml) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
nodetreeHB = mxmlLoadFile( NULL, filexml, MXML_OPAQUE_CALLBACK );
|
nodetreeHB = mxmlLoadFile(NULL, filexml, MXML_OPAQUE_CALLBACK);
|
||||||
fclose( filexml );
|
fclose(filexml);
|
||||||
|
|
||||||
if ( nodetreeHB == NULL )
|
if (nodetreeHB == NULL) return -2;
|
||||||
return -2;
|
|
||||||
|
|
||||||
nodedataHB = mxmlFindElement( nodetreeHB, nodetreeHB, "app", NULL, NULL, MXML_DESCEND );
|
nodedataHB = mxmlFindElement(nodetreeHB, nodetreeHB, "app", NULL, NULL, MXML_DESCEND);
|
||||||
if ( nodedataHB == NULL )
|
if (nodedataHB == NULL) return -5;
|
||||||
return -5;
|
|
||||||
|
|
||||||
char * Entrie = new char[ENTRIE_SIZE];
|
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;
|
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;
|
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;
|
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;
|
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;
|
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
|
int len = (strlen(Entrie) - 6); //length of the date string without the 200000 at the end
|
||||||
if ( len == 8 )
|
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] );
|
snprintf(Entrie, ENTRIE_SIZE, "%c%c/%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[6], Entrie[7], Entrie[0],
|
||||||
else if ( len == 6 )
|
Entrie[1], Entrie[2], Entrie[3]);
|
||||||
snprintf( Entrie, ENTRIE_SIZE, "%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[0], Entrie[1], Entrie[2], Entrie[3] );
|
else if (len == 6)
|
||||||
else
|
snprintf(Entrie, ENTRIE_SIZE, "%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[0], Entrie[1], Entrie[2], Entrie[3]);
|
||||||
snprintf( Entrie, ENTRIE_SIZE, "%s", Entrie );
|
else snprintf(Entrie, ENTRIE_SIZE, "%s", Entrie);
|
||||||
|
|
||||||
Releasedate = Entrie;
|
Releasedate = Entrie;
|
||||||
|
|
||||||
free( nodedataHB );
|
free(nodedataHB);
|
||||||
free( nodetreeHB );
|
free(nodetreeHB);
|
||||||
|
|
||||||
delete [] Entrie;
|
delete[] Entrie;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get name */
|
||||||
|
const char * HomebrewXML::GetName()
|
||||||
|
{
|
||||||
|
return Name.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Name */
|
||||||
|
void HomebrewXML::SetName(char * newName)
|
||||||
|
{
|
||||||
|
Name = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get coder */
|
||||||
|
const char * HomebrewXML::GetCoder()
|
||||||
|
{
|
||||||
|
return Coder.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get version */
|
||||||
|
const char * HomebrewXML::GetVersion()
|
||||||
|
{
|
||||||
|
return Version.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get releasedate */
|
||||||
|
const char * HomebrewXML::GetReleasedate()
|
||||||
|
{
|
||||||
|
return Releasedate.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get shortdescription */
|
||||||
|
const char * HomebrewXML::GetShortDescription()
|
||||||
|
{
|
||||||
|
return ShortDescription.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get longdescription */
|
||||||
|
const char * HomebrewXML::GetLongDescription()
|
||||||
|
{
|
||||||
|
return LongDescription.c_str();
|
||||||
|
}
|
||||||
|
@ -10,27 +10,19 @@
|
|||||||
class HomebrewXML
|
class HomebrewXML
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//!Constructor
|
HomebrewXML();
|
||||||
//!\param path Path for the xml file
|
~HomebrewXML();
|
||||||
HomebrewXML() { };
|
|
||||||
//!Destructor
|
int LoadHomebrewXMLData(const char* filename);
|
||||||
~HomebrewXML() { };
|
|
||||||
//!\param filename Filepath of the XML file
|
const char * GetName();
|
||||||
int LoadHomebrewXMLData( const char* filename );
|
void SetName(char * newName);
|
||||||
//! Get name
|
const char * GetCoder();
|
||||||
const char * GetName() { return Name.c_str(); };
|
const char * GetVersion();
|
||||||
//! Get coder
|
const char * GetReleasedate();
|
||||||
const char * GetCoder() { return Coder.c_str(); };
|
const char * GetShortDescription();
|
||||||
//! Get version
|
const char * GetLongDescription();
|
||||||
const char * GetVersion() { return Version.c_str(); };
|
|
||||||
//! Get releasedate
|
|
||||||
const char * GetReleasedate() { return Releasedate.c_str(); };
|
|
||||||
//! Get shortdescription
|
|
||||||
const char * GetShortDescription() { return ShortDescription.c_str(); };
|
|
||||||
//! Get longdescription
|
|
||||||
const char * GetLongDescription() { return LongDescription.c_str(); };
|
|
||||||
//! Set Name
|
|
||||||
void SetName( char * newName ) { Name = newName; };
|
|
||||||
protected:
|
protected:
|
||||||
std::string Name;
|
std::string Name;
|
||||||
std::string Coder;
|
std::string Coder;
|
||||||
|
@ -21,36 +21,36 @@ typedef struct _dolheader
|
|||||||
u32 entry_point;
|
u32 entry_point;
|
||||||
} dolheader;
|
} dolheader;
|
||||||
|
|
||||||
u32 load_dol( const void *dolstart, struct __argv *argv )
|
u32 load_dol(const void *dolstart, struct __argv *argv)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
dolheader *dolfile;
|
dolheader *dolfile;
|
||||||
|
|
||||||
if ( dolstart )
|
if (dolstart)
|
||||||
{
|
{
|
||||||
dolfile = ( dolheader * ) dolstart;
|
dolfile = (dolheader *) dolstart;
|
||||||
for ( i = 0; i < 7; i++ )
|
for (i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
if ( ( !dolfile->text_size[i] ) || ( dolfile->text_start[i] < 0x100 ) ) continue;
|
if ((!dolfile->text_size[i]) || (dolfile->text_start[i] < 0x100)) continue;
|
||||||
ICInvalidateRange ( ( void * ) dolfile->text_start[i], dolfile->text_size[i] );
|
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] );
|
memcpy((void *) dolfile->text_start[i], dolstart + dolfile->text_pos[i], dolfile->text_size[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( i = 0; i < 11; i++ )
|
for (i = 0; i < 11; i++)
|
||||||
{
|
{
|
||||||
if ( ( !dolfile->data_size[i] ) || ( dolfile->data_start[i] < 0x100 ) ) continue;
|
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] );
|
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] );
|
DCFlushRangeNoSync((void *) dolfile->data_start[i], dolfile->data_size[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset ( ( void * ) dolfile->bss_start, 0, dolfile->bss_size );
|
memset((void *) dolfile->bss_start, 0, dolfile->bss_size);
|
||||||
DCFlushRange( ( void * ) dolfile->bss_start, dolfile->bss_size );
|
DCFlushRange((void *) dolfile->bss_start, dolfile->bss_size);
|
||||||
|
|
||||||
if ( argv && argv->argvMagic == ARGV_MAGIC )
|
if (argv && argv->argvMagic == ARGV_MAGIC)
|
||||||
{
|
{
|
||||||
void *new_argv = ( void * )( dolfile->entry_point + 8 );
|
void *new_argv = (void *) (dolfile->entry_point + 8);
|
||||||
memcpy( new_argv, argv, sizeof( *argv ) );
|
memcpy(new_argv, argv, sizeof(*argv));
|
||||||
DCFlushRange( new_argv, sizeof( *argv ) );
|
DCFlushRange(new_argv, sizeof(*argv));
|
||||||
}
|
}
|
||||||
|
|
||||||
return dolfile->entry_point;
|
return dolfile->entry_point;
|
||||||
|
@ -7,10 +7,9 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void __exception_closeall();
|
extern void __exception_closeall();
|
||||||
typedef void ( *entrypoint ) ( void );
|
typedef void (*entrypoint)(void);
|
||||||
|
|
||||||
u32 load_dol( const void *dolstart, struct __argv *argv );
|
|
||||||
|
|
||||||
|
u32 load_dol(const void *dolstart, struct __argv *argv);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "libwiigui/gui.h"
|
#include "libwiigui/gui.h"
|
||||||
|
|
||||||
int rumbleRequest[4] = {0, 0, 0, 0};
|
int rumbleRequest[4] = { 0, 0, 0, 0 };
|
||||||
GuiTrigger userInput[4];
|
GuiTrigger userInput[4];
|
||||||
static int rumbleCount[4] = {0, 0, 0, 0};
|
static int rumbleCount[4] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* UpdatePads
|
* UpdatePads
|
||||||
@ -34,22 +34,21 @@ void UpdatePads()
|
|||||||
WPAD_ScanPads();
|
WPAD_ScanPads();
|
||||||
PAD_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].chan = i;
|
||||||
userInput[i].pad.btns_d = PAD_ButtonsDown( i );
|
userInput[i].pad.btns_d = PAD_ButtonsDown(i);
|
||||||
userInput[i].pad.btns_u = PAD_ButtonsUp( i );
|
userInput[i].pad.btns_u = PAD_ButtonsUp(i);
|
||||||
userInput[i].pad.btns_h = PAD_ButtonsHeld( i );
|
userInput[i].pad.btns_h = PAD_ButtonsHeld(i);
|
||||||
userInput[i].pad.stickX = PAD_StickX( i );
|
userInput[i].pad.stickX = PAD_StickX(i);
|
||||||
userInput[i].pad.stickY = PAD_StickY( i );
|
userInput[i].pad.stickY = PAD_StickY(i);
|
||||||
userInput[i].pad.substickX = PAD_SubStickX( i );
|
userInput[i].pad.substickX = PAD_SubStickX(i);
|
||||||
userInput[i].pad.substickY = PAD_SubStickY( i );
|
userInput[i].pad.substickY = PAD_SubStickY(i);
|
||||||
userInput[i].pad.triggerL = PAD_TriggerL( i );
|
userInput[i].pad.triggerL = PAD_TriggerL(i);
|
||||||
userInput[i].pad.triggerR = PAD_TriggerR( i );
|
userInput[i].pad.triggerR = PAD_TriggerR(i);
|
||||||
|
|
||||||
if ( Settings.rumble == RumbleOn )
|
if (Settings.rumble == RumbleOn) DoRumble(i);
|
||||||
DoRumble( i );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,10 +63,10 @@ void SetupPads()
|
|||||||
WPAD_Init();
|
WPAD_Init();
|
||||||
|
|
||||||
// read wiimote accelerometer and IR data
|
// read wiimote accelerometer and IR data
|
||||||
WPAD_SetDataFormat( WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR );
|
WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR);
|
||||||
WPAD_SetVRes( WPAD_CHAN_ALL, screenwidth, screenheight );
|
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;
|
userInput[i].chan = i;
|
||||||
}
|
}
|
||||||
@ -79,9 +78,9 @@ void SetupPads()
|
|||||||
|
|
||||||
void ShutoffRumble()
|
void ShutoffRumble()
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < 4; i++ )
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
WPAD_Rumble( i, 0 );
|
WPAD_Rumble(i, 0);
|
||||||
rumbleCount[i] = 0;
|
rumbleCount[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,23 +89,22 @@ void ShutoffRumble()
|
|||||||
* DoRumble
|
* DoRumble
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
void DoRumble( int i )
|
void DoRumble(int i)
|
||||||
{
|
{
|
||||||
if ( rumbleRequest[i] && rumbleCount[i] < 3 )
|
if (rumbleRequest[i] && rumbleCount[i] < 3)
|
||||||
{
|
{
|
||||||
WPAD_Rumble( i, 1 ); // rumble on
|
WPAD_Rumble(i, 1); // rumble on
|
||||||
rumbleCount[i]++;
|
rumbleCount[i]++;
|
||||||
}
|
}
|
||||||
else if ( rumbleRequest[i] )
|
else if (rumbleRequest[i])
|
||||||
{
|
{
|
||||||
rumbleCount[i] = 20;
|
rumbleCount[i] = 20;
|
||||||
rumbleRequest[i] = 0;
|
rumbleRequest[i] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( rumbleCount[i] )
|
if (rumbleCount[i]) rumbleCount[i]--;
|
||||||
rumbleCount[i]--;
|
WPAD_Rumble(i, 0); // rumble off
|
||||||
WPAD_Rumble( i, 0 ); // rumble off
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,17 +114,17 @@ void DoRumble( int i )
|
|||||||
* Get X/Y value from Wii Joystick (classic, nunchuk) input
|
* 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 mag = 0.0;
|
||||||
float ang = 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_NUNCHUK:
|
||||||
case WPAD_EXP_GUITARHERO3:
|
case WPAD_EXP_GUITARHERO3:
|
||||||
if ( right == 0 )
|
if (right == 0)
|
||||||
{
|
{
|
||||||
mag = data->exp.nunchuk.js.mag;
|
mag = data->exp.nunchuk.js.mag;
|
||||||
ang = data->exp.nunchuk.js.ang;
|
ang = data->exp.nunchuk.js.ang;
|
||||||
@ -134,7 +132,7 @@ s8 WPAD_Stick( u8 chan, u8 right, int axis )
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WPAD_EXP_CLASSIC:
|
case WPAD_EXP_CLASSIC:
|
||||||
if ( right == 0 )
|
if (right == 0)
|
||||||
{
|
{
|
||||||
mag = data->exp.classic.ljs.mag;
|
mag = data->exp.classic.ljs.mag;
|
||||||
ang = data->exp.classic.ljs.ang;
|
ang = data->exp.classic.ljs.ang;
|
||||||
@ -151,14 +149,15 @@ s8 WPAD_Stick( u8 chan, u8 right, int axis )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* calculate x/y value (angle need to be converted into radian) */
|
/* calculate x/y value (angle need to be converted into radian) */
|
||||||
if ( mag > 1.0 ) mag = 1.0;
|
if (mag > 1.0)
|
||||||
else if ( mag < -1.0 ) mag = -1.0;
|
mag = 1.0;
|
||||||
|
else if (mag < -1.0) mag = -1.0;
|
||||||
double val;
|
double val;
|
||||||
|
|
||||||
if ( axis == 0 ) // x-axis
|
if (axis == 0) // x-axis
|
||||||
val = mag * sin( ( PI * ang ) / 180.0f );
|
val = mag * sin((PI * ang) / 180.0f);
|
||||||
else // y-axis
|
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 SetupPads();
|
||||||
void UpdatePads();
|
void UpdatePads();
|
||||||
void ShutoffRumble();
|
void ShutoffRumble();
|
||||||
void DoRumble( int i );
|
void DoRumble(int i);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,48 +18,49 @@ int updateLanguageFiles()
|
|||||||
char languageFiles[50][MAXLANGUAGEFILES];
|
char languageFiles[50][MAXLANGUAGEFILES];
|
||||||
|
|
||||||
//get all the files in the language path
|
//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
|
//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
|
//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];
|
char filename[64];
|
||||||
strlcpy( filename, GetFileName( cnt ), sizeof( filename ) );
|
strlcpy(filename, GetFileName(cnt), sizeof(filename));
|
||||||
if ( strcasestr( filename, ".lang" ) )
|
if (strcasestr(filename, ".lang"))
|
||||||
{
|
{
|
||||||
strcpy( languageFiles[cnt], filename );
|
strcpy(languageFiles[cnt], filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subfoldercreate( Settings.languagefiles_path );
|
subfoldercreate(Settings.languagefiles_path);
|
||||||
|
|
||||||
//we assume that the network will already be init by another function
|
//we assume that the network will already be init by another function
|
||||||
// ( that has gui eletents in it because this one doesn't)
|
// ( that has gui eletents in it because this one doesn't)
|
||||||
int done = 0, j = 0;
|
int done = 0, j = 0;
|
||||||
if ( IsNetworkInit() )
|
if (IsNetworkInit())
|
||||||
{
|
{
|
||||||
//build the URL, save path, and download each file and save it
|
//build the URL, save path, and download each file and save it
|
||||||
while ( j < countfiles )
|
while (j < countfiles)
|
||||||
{
|
{
|
||||||
char savepath[150];
|
char savepath[150];
|
||||||
char codeurl[200];
|
char codeurl[200];
|
||||||
snprintf( codeurl, sizeof( codeurl ), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s", languageFiles[j] );
|
snprintf(codeurl, sizeof(codeurl), "http://usbloader-gui.googlecode.com/svn/trunk/Languages/%s",
|
||||||
snprintf( savepath, sizeof( savepath ), "%s%s", Settings.languagefiles_path, languageFiles[j] );
|
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;
|
FILE * pfile;
|
||||||
pfile = fopen( savepath, "wb" );
|
pfile = fopen(savepath, "wb");
|
||||||
if ( pfile != NULL )
|
if (pfile != NULL)
|
||||||
{
|
{
|
||||||
fwrite( file.data, 1, file.size, pfile );
|
fwrite(file.data, 1, file.size, pfile);
|
||||||
fclose( pfile );
|
fclose(pfile);
|
||||||
free( file.data );
|
free(file.data);
|
||||||
done++;
|
done++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,5 +76,3 @@ int updateLanguageFiles()
|
|||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,28 +12,26 @@ typedef struct _MSG
|
|||||||
} MSG;
|
} MSG;
|
||||||
static MSG *baseMSG = 0;
|
static MSG *baseMSG = 0;
|
||||||
|
|
||||||
|
|
||||||
#define HASHWORDBITS 32
|
#define HASHWORDBITS 32
|
||||||
|
|
||||||
/* Defines the so called `hashpjw' function by P.J. Weinberger
|
/* Defines the so called `hashpjw' function by P.J. Weinberger
|
||||||
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
||||||
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
||||||
static inline u32
|
static inline u32 hash_string(const char *str_param)
|
||||||
hash_string ( const char *str_param )
|
|
||||||
{
|
{
|
||||||
u32 hval, g;
|
u32 hval, g;
|
||||||
const char *str = str_param;
|
const char *str = str_param;
|
||||||
|
|
||||||
/* Compute the hash value for the given string. */
|
/* Compute the hash value for the given string. */
|
||||||
hval = 0;
|
hval = 0;
|
||||||
while ( *str != '\0' )
|
while (*str != '\0')
|
||||||
{
|
{
|
||||||
hval <<= 4;
|
hval <<= 4;
|
||||||
hval += ( u8 ) * str++;
|
hval += (u8) *str++;
|
||||||
g = hval & ( ( u32 ) 0xf << ( HASHWORDBITS - 4 ) );
|
g = hval & ((u32) 0xf << (HASHWORDBITS - 4));
|
||||||
if ( g != 0 )
|
if (g != 0)
|
||||||
{
|
{
|
||||||
hval ^= g >> ( HASHWORDBITS - 8 );
|
hval ^= g >> (HASHWORDBITS - 8);
|
||||||
hval ^= g;
|
hval ^= g;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,24 +40,23 @@ hash_string ( const char *str_param )
|
|||||||
|
|
||||||
/* Expand some escape sequences found in the argument string. */
|
/* Expand some escape sequences found in the argument string. */
|
||||||
static char *
|
static char *
|
||||||
expand_escape ( const char *str )
|
expand_escape(const char *str)
|
||||||
{
|
{
|
||||||
char *retval, *rp;
|
char *retval, *rp;
|
||||||
const char *cp = str;
|
const char *cp = str;
|
||||||
|
|
||||||
retval = ( char * ) malloc ( strlen ( str ) + 1 );
|
retval = (char *) malloc(strlen(str) + 1);
|
||||||
if ( retval == NULL ) return NULL;
|
if (retval == NULL) return NULL;
|
||||||
rp = retval;
|
rp = retval;
|
||||||
|
|
||||||
while ( cp[0] != '\0' && cp[0] != '\\' )
|
while (cp[0] != '\0' && cp[0] != '\\')
|
||||||
*rp++ = *cp++;
|
*rp++ = *cp++;
|
||||||
if ( cp[0] == '\0' )
|
if (cp[0] == '\0') goto terminate;
|
||||||
goto terminate;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Here cp[0] == '\\'. */
|
/* Here cp[0] == '\\'. */
|
||||||
switch ( *++cp )
|
switch (*++cp)
|
||||||
{
|
{
|
||||||
case '\"': /* " */
|
case '\"': /* " */
|
||||||
*rp++ = '\"';
|
*rp++ = '\"';
|
||||||
@ -108,12 +105,12 @@ expand_escape ( const char *str )
|
|||||||
{
|
{
|
||||||
int ch = *cp++ - '0';
|
int ch = *cp++ - '0';
|
||||||
|
|
||||||
if ( *cp >= '0' && *cp <= '7' )
|
if (*cp >= '0' && *cp <= '7')
|
||||||
{
|
{
|
||||||
ch *= 8;
|
ch *= 8;
|
||||||
ch += *cp++ - '0';
|
ch += *cp++ - '0';
|
||||||
|
|
||||||
if ( *cp >= '0' && *cp <= '7' )
|
if (*cp >= '0' && *cp <= '7')
|
||||||
{
|
{
|
||||||
ch *= 8;
|
ch *= 8;
|
||||||
ch += *cp++ - '0';
|
ch += *cp++ - '0';
|
||||||
@ -127,125 +124,117 @@ expand_escape ( const char *str )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( cp[0] != '\0' && cp[0] != '\\' )
|
while (cp[0] != '\0' && cp[0] != '\\')
|
||||||
*rp++ = *cp++;
|
*rp++ = *cp++;
|
||||||
}
|
} while (cp[0] != '\0');
|
||||||
while ( cp[0] != '\0' );
|
|
||||||
|
|
||||||
/* Terminate string. */
|
/* Terminate string. */
|
||||||
terminate:
|
terminate: *rp = '\0';
|
||||||
*rp = '\0';
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MSG *findMSG( u32 id )
|
static MSG *findMSG(u32 id)
|
||||||
{
|
{
|
||||||
MSG *msg;
|
MSG *msg;
|
||||||
for ( msg = baseMSG; msg; msg = msg->next )
|
for (msg = baseMSG; msg; msg = msg->next)
|
||||||
{
|
{
|
||||||
if ( msg->id == id )
|
if (msg->id == id) return msg;
|
||||||
return msg;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MSG *setMSG( const char *msgid, const char *msgstr )
|
static MSG *setMSG(const char *msgid, const char *msgstr)
|
||||||
{
|
{
|
||||||
u32 id = hash_string( msgid );
|
u32 id = hash_string(msgid);
|
||||||
MSG *msg = findMSG( id );
|
MSG *msg = findMSG(id);
|
||||||
if ( !msg )
|
if (!msg)
|
||||||
{
|
{
|
||||||
msg = ( MSG * )malloc( sizeof( MSG ) );
|
msg = (MSG *) malloc(sizeof(MSG));
|
||||||
msg->id = id;
|
msg->id = id;
|
||||||
msg->msgstr = NULL;
|
msg->msgstr = NULL;
|
||||||
msg->next = baseMSG;
|
msg->next = baseMSG;
|
||||||
baseMSG = msg;
|
baseMSG = msg;
|
||||||
}
|
}
|
||||||
if ( msg )
|
if (msg)
|
||||||
{
|
{
|
||||||
if ( msgstr )
|
if (msgstr)
|
||||||
{
|
{
|
||||||
if ( msg->msgstr ) free( msg->msgstr );
|
if (msg->msgstr) free(msg->msgstr);
|
||||||
//msg->msgstr = strdup(msgstr);
|
//msg->msgstr = strdup(msgstr);
|
||||||
msg->msgstr = expand_escape( msgstr );
|
msg->msgstr = expand_escape(msgstr);
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void gettextCleanUp( void )
|
void gettextCleanUp(void)
|
||||||
{
|
{
|
||||||
while ( baseMSG )
|
while (baseMSG)
|
||||||
{
|
{
|
||||||
MSG *nextMsg = baseMSG->next;
|
MSG *nextMsg = baseMSG->next;
|
||||||
free( baseMSG->msgstr );
|
free(baseMSG->msgstr);
|
||||||
free( baseMSG );
|
free(baseMSG);
|
||||||
baseMSG = nextMsg;
|
baseMSG = nextMsg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool gettextLoadLanguage(const char* langFile)
|
||||||
bool gettextLoadLanguage( const char* langFile )
|
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char line[200];
|
char line[200];
|
||||||
char *lastID = NULL;
|
char *lastID = NULL;
|
||||||
|
|
||||||
gettextCleanUp();
|
gettextCleanUp();
|
||||||
f = fopen( langFile, "r" );
|
f = fopen(langFile, "r");
|
||||||
if ( !f )
|
if (!f) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
while ( fgets( line, sizeof( line ), f ) )
|
while (fgets(line, sizeof(line), f))
|
||||||
{
|
{
|
||||||
// lines starting with # are comments
|
// lines starting with # are comments
|
||||||
if ( line[0] == '#' )
|
if (line[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
else if ( strncmp( line, "msgid \"", 7 ) == 0 )
|
else if (strncmp(line, "msgid \"", 7) == 0)
|
||||||
{
|
{
|
||||||
char *msgid, *end;
|
char *msgid, *end;
|
||||||
if ( lastID )
|
if (lastID)
|
||||||
{
|
{
|
||||||
free( lastID );
|
free(lastID);
|
||||||
lastID = NULL;
|
lastID = NULL;
|
||||||
}
|
}
|
||||||
msgid = &line[7];
|
msgid = &line[7];
|
||||||
end = strrchr( msgid, '"' );
|
end = strrchr(msgid, '"');
|
||||||
if ( end && end - msgid > 1 )
|
if (end && end - msgid > 1)
|
||||||
{
|
{
|
||||||
*end = 0;
|
*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;
|
char *msgstr, *end;
|
||||||
|
|
||||||
if ( lastID == NULL )
|
if (lastID == NULL) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
msgstr = &line[8];
|
msgstr = &line[8];
|
||||||
end = strrchr( msgstr, '"' );
|
end = strrchr(msgstr, '"');
|
||||||
if ( end && end - msgstr > 1 )
|
if (end && end - msgstr > 1)
|
||||||
{
|
{
|
||||||
*end = 0;
|
*end = 0;
|
||||||
setMSG( lastID, msgstr );
|
setMSG(lastID, msgstr);
|
||||||
}
|
}
|
||||||
free( lastID );
|
free(lastID);
|
||||||
lastID = NULL;
|
lastID = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose( f );
|
fclose(f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const char *gettext( const char *msgid )
|
const char *gettext(const char *msgid)
|
||||||
{
|
{
|
||||||
MSG *msg = findMSG( hash_string( msgid ) );
|
MSG *msg = findMSG(hash_string(msgid));
|
||||||
if ( msg && msg->msgstr ) return msg->msgstr;
|
if (msg && msg->msgstr) return msg->msgstr;
|
||||||
return msgid;
|
return msgid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,18 +6,16 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool gettextLoadLanguage(const char* langFile);
|
||||||
bool gettextLoadLanguage( const char* langFile );
|
void gettextCleanUp(void);
|
||||||
void gettextCleanUp( void );
|
|
||||||
/*
|
/*
|
||||||
* input msg = a text in ASCII
|
* input msg = a text in ASCII
|
||||||
* output = the translated msg in utf-8
|
* 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 tr(s) gettext(s)
|
||||||
#define trNOOP(s) (s)
|
#define trNOOP(s) (s)
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __BIT_OPS_H
|
#ifndef __BIT_OPS_H
|
||||||
#define __BIT_OPS_H
|
#define __BIT_OPS_H
|
||||||
@ -32,30 +32,30 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
Functions to deal with little endian values stored in uint8_t arrays
|
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 )
|
static inline uint16_t u8array_to_u16(const uint8_t* item, int offset)
|
||||||
{
|
{
|
||||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
return (item[offset] | (item[offset + 1] << 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
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 ) );
|
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 )
|
static inline void u16_to_u8array(uint8_t* item, int offset, uint16_t value)
|
||||||
{
|
{
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset] = (uint8_t) value;
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
item[offset + 1] = (uint8_t) (value >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
static inline void u32_to_u8array(uint8_t* item, int offset, uint32_t value)
|
||||||
{
|
{
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset] = (uint8_t) value;
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
item[offset + 1] = (uint8_t) (value >> 8);
|
||||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
item[offset + 2] = (uint8_t) (value >> 16);
|
||||||
item[offset + 3] = ( uint8_t )( value >> 24 );
|
item[offset + 3] = (uint8_t) (value >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _BIT_OPS_H
|
#endif // _BIT_OPS_H
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _CACHE_H
|
#ifndef _CACHE_H
|
||||||
#define _CACHE_H
|
#define _CACHE_H
|
||||||
@ -61,74 +61,76 @@ typedef struct
|
|||||||
} CACHE;
|
} CACHE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read data from a sector in the cache
|
Read data from a sector in the cache
|
||||||
If the sector is not in the cache, it will be swapped in
|
If the sector is not in the cache, it will be swapped in
|
||||||
offset is the position to start reading from
|
offset is the position to start reading from
|
||||||
size is the amount of data to read
|
size is the amount of data to read
|
||||||
Precondition: offset + size <= BYTES_PER_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
|
Write data to a sector in the cache
|
||||||
If the sector is not in the cache, it will be swapped in.
|
If the sector is not in the cache, it will be swapped in.
|
||||||
When the sector is swapped out, the data will be written to the disc
|
When the sector is swapped out, the data will be written to the disc
|
||||||
offset is the position to start writing to
|
offset is the position to start writing to
|
||||||
size is the amount of data to write
|
size is the amount of data to write
|
||||||
Precondition: offset + size <= BYTES_PER_READ
|
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
|
Write data to a sector in the cache, zeroing the sector first
|
||||||
If the sector is not in the cache, it will be swapped in.
|
If the sector is not in the cache, it will be swapped in.
|
||||||
When the sector is swapped out, the data will be written to the disc
|
When the sector is swapped out, the data will be written to the disc
|
||||||
offset is the position to start writing to
|
offset is the position to start writing to
|
||||||
size is the amount of data to write
|
size is the amount of data to write
|
||||||
Precondition: offset + size <= BYTES_PER_READ
|
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
|
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
|
Read a full sector from the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
|
static inline bool _FAT_cache_readSector(CACHE* cache, void* buffer, sec_t sector)
|
||||||
{
|
{
|
||||||
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
return _FAT_cache_readPartialSector(cache, buffer, sector, 0, BYTES_PER_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write a full sector to the cache
|
Write a full sector to the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
|
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 );
|
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
|
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
|
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
|
#endif // _CACHE_H
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __COMMON_H
|
#ifndef __COMMON_H
|
||||||
#define __COMMON_H
|
#define __COMMON_H
|
||||||
@ -34,7 +34,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
// Platform specific includes
|
// Platform specific includes
|
||||||
#include <gctypes.h>
|
#include <gctypes.h>
|
||||||
#include <ogc/disc_io.h>
|
#include <ogc/disc_io.h>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DIRECTORY_H
|
#ifndef __DIRECTORY_H
|
||||||
#define __DIRECTORY_H
|
#define __DIRECTORY_H
|
||||||
@ -56,8 +56,10 @@
|
|||||||
#define ATTRIB_SYS 0x04 // System
|
#define ATTRIB_SYS 0x04 // System
|
||||||
#define ATTRIB_HID 0x02 // Hidden
|
#define ATTRIB_HID 0x02 // Hidden
|
||||||
#define ATTRIB_RO 0x01 // Read only
|
#define ATTRIB_RO 0x01 // Read only
|
||||||
|
typedef enum
|
||||||
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
{
|
||||||
|
FT_DIRECTORY, FT_FILE
|
||||||
|
} FILE_TYPE;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -93,87 +95,87 @@ enum DIR_ENTRY_offset
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns true if the file specified by entry is a directory
|
Returns true if the file specified by entry is a directory
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_directory_isDirectory ( DIR_ENTRY* entry )
|
static inline bool _FAT_directory_isDirectory(DIR_ENTRY* entry)
|
||||||
{
|
{
|
||||||
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR ) != 0 );
|
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _FAT_directory_isWritable ( DIR_ENTRY* entry )
|
static inline bool _FAT_directory_isWritable(DIR_ENTRY* entry)
|
||||||
{
|
{
|
||||||
return ( ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO ) == 0 );
|
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _FAT_directory_isDot ( DIR_ENTRY* entry )
|
static inline bool _FAT_directory_isDot(DIR_ENTRY* entry)
|
||||||
{
|
{
|
||||||
return ( ( entry->filename[0] == '.' ) && ( ( entry->filename[1] == '\0' ) ||
|
return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') || ((entry->filename[1] == '.')
|
||||||
( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) );
|
&& entry->filename[2] == '\0')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reads the first directory entry from the directory starting at dirCluster
|
Reads the first directory entry from the directory starting at dirCluster
|
||||||
Places result in entry
|
Places result in entry
|
||||||
entry will be destroyed even if no directory entry is found
|
entry will be destroyed even if no directory entry is found
|
||||||
Returns true on success, false on failure
|
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
|
Reads the next directory entry after the one already pointed to by entry
|
||||||
Places result in entry
|
Places result in entry
|
||||||
entry will be destroyed even if no directory entry is found
|
entry will be destroyed even if no directory entry is found
|
||||||
Returns true on success, false on failure
|
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
|
Gets the directory entry corrsponding to the supplied path
|
||||||
entry will be destroyed even if no directory entry is found
|
entry will be destroyed even if no directory entry is found
|
||||||
pathEnd specifies the end of the path string, for cutting strings short if needed
|
pathEnd specifies the end of the path string, for cutting strings short if needed
|
||||||
specify NULL to use the full length of path
|
specify NULL to use the full length of path
|
||||||
pathEnd is only a suggestion, and the path string will be searched up until the next PATH_SEPARATOR
|
pathEnd is only a suggestion, and the path string will be searched up until the next PATH_SEPARATOR
|
||||||
after pathEND.
|
after pathEND.
|
||||||
Returns true on success, false on failure
|
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
|
Changes the current directory to the one specified by path
|
||||||
Returns true on success, false on failure
|
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
|
Removes the directory entry specified by entry
|
||||||
Assumes that entry is valid
|
Assumes that entry is valid
|
||||||
Returns true on success, false on failure
|
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
|
Add a directory entry to the directory specified by dirCluster
|
||||||
The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are
|
The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are
|
||||||
updated with the new directory entry position and alias.
|
updated with the new directory entry position and alias.
|
||||||
Returns true on success, false on failure
|
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
|
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.
|
Fill in the file name and entry data of DIR_ENTRY* entry.
|
||||||
Assumes that the entry's dataStart and dataEnd are correct
|
Assumes that the entry's dataStart and dataEnd are correct
|
||||||
Returns true on success, false on failure
|
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
|
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
|
#endif // _DIRECTORY_H
|
||||||
|
@ -25,93 +25,94 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#ifndef _DISC_H
|
#ifndef _DISC_H
|
||||||
#define _DISC_H
|
#define _DISC_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A list of all default devices to try at startup,
|
A list of all default devices to try at startup,
|
||||||
terminated by a {NULL,NULL} entry.
|
terminated by a {NULL,NULL} entry.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
const DISC_INTERFACE* ( *getInterface )( void );
|
const DISC_INTERFACE* (*getInterface)(void);
|
||||||
} INTERFACE_ID;
|
} INTERFACE_ID;
|
||||||
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if a disc is inserted
|
Check if a disc is inserted
|
||||||
Return true if a disc is inserted and ready, false otherwise
|
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();
|
return disc->isInserted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read numSectors sectors from a disc, starting at sector.
|
Read numSectors sectors from a disc, starting at sector.
|
||||||
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||||
else it is at least 1
|
else it is at least 1
|
||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to fill
|
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 )
|
static inline bool _FAT_disc_readSectors(const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer)
|
||||||
{
|
{
|
||||||
return disc->readSectors ( sector, numSectors, buffer );
|
return disc->readSectors(sector, numSectors, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write numSectors sectors to a disc, starting at sector.
|
Write numSectors sectors to a disc, starting at sector.
|
||||||
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||||
else it is at least 1
|
else it is at least 1
|
||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to read from
|
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 )
|
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 );
|
return disc->writeSectors(sector, numSectors, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reset the card back to a ready state
|
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();
|
return disc->clearStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise the disc to a state ready for data reading or writing
|
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();
|
return disc->startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Put the disc in a state ready for power down.
|
Put the disc in a state ready for power down.
|
||||||
Complete any pending writes and disable the disc if necessary
|
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 disc->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value unique to each type of interface
|
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 disc->ioType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value that specifies the capabilities of the disc
|
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;
|
return disc->features;
|
||||||
}
|
}
|
||||||
|
@ -25,48 +25,42 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "disc_fat.h"
|
#include "disc_fat.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The list of interfaces consists of a series of name/interface pairs.
|
The list of interfaces consists of a series of name/interface pairs.
|
||||||
The interface is returned via a simple function. This allows for
|
The interface is returned via a simple function. This allows for
|
||||||
platforms where the interface has to be "assembled" before it can
|
platforms where the interface has to be "assembled" before it can
|
||||||
be used, like DLDI on the NDS. For cases where a simple struct
|
be used, like DLDI on the NDS. For cases where a simple struct
|
||||||
is available, wrapper functions are used.
|
is available, wrapper functions are used.
|
||||||
The list is terminated by a NULL/NULL entry.
|
The list is terminated by a NULL/NULL entry.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ====================== Wii ====================== */
|
/* ====================== Wii ====================== */
|
||||||
#include <sdcard/wiisd_io.h>
|
#include <sdcard/wiisd_io.h>
|
||||||
#include "usbloader/usbstorage2.h"
|
#include "usbloader/usbstorage2.h"
|
||||||
#include <sdcard/gcsd.h>
|
#include <sdcard/gcsd.h>
|
||||||
|
|
||||||
static const DISC_INTERFACE* get_io_wiisd ( void )
|
static const DISC_INTERFACE* get_io_wiisd(void)
|
||||||
{
|
{
|
||||||
return &__io_wiisd;
|
return &__io_wiisd;
|
||||||
}
|
}
|
||||||
static const DISC_INTERFACE* get_io_usbstorage ( void )
|
static const DISC_INTERFACE* get_io_usbstorage(void)
|
||||||
{
|
{
|
||||||
return &__io_usbstorage2;
|
return &__io_usbstorage2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const DISC_INTERFACE* get_io_gcsda ( void )
|
static const DISC_INTERFACE* get_io_gcsda(void)
|
||||||
{
|
{
|
||||||
return &__io_gcsda;
|
return &__io_gcsda;
|
||||||
}
|
}
|
||||||
static const DISC_INTERFACE* get_io_gcsdb ( void )
|
static const DISC_INTERFACE* get_io_gcsdb(void)
|
||||||
{
|
{
|
||||||
return &__io_gcsdb;
|
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 }, { "cardb", get_io_gcsdb }, { NULL, NULL } };
|
||||||
{"sd", get_io_wiisd},
|
|
||||||
{"usb", get_io_usbstorage},
|
|
||||||
{"carda", get_io_gcsda},
|
|
||||||
{"cardb", get_io_gcsdb},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@ -25,93 +25,94 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#ifndef __DISC_H
|
#ifndef __DISC_H
|
||||||
#define __DISC_H
|
#define __DISC_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A list of all default devices to try at startup,
|
A list of all default devices to try at startup,
|
||||||
terminated by a {NULL,NULL} entry.
|
terminated by a {NULL,NULL} entry.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
const DISC_INTERFACE* ( *getInterface )( void );
|
const DISC_INTERFACE* (*getInterface)(void);
|
||||||
} INTERFACE_ID;
|
} INTERFACE_ID;
|
||||||
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if a disc is inserted
|
Check if a disc is inserted
|
||||||
Return true if a disc is inserted and ready, false otherwise
|
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();
|
return disc->isInserted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read numSectors sectors from a disc, starting at sector.
|
Read numSectors sectors from a disc, starting at sector.
|
||||||
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||||
else it is at least 1
|
else it is at least 1
|
||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to fill
|
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 )
|
static inline bool _FAT_disc_readSectors(const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer)
|
||||||
{
|
{
|
||||||
return disc->readSectors ( sector, numSectors, buffer );
|
return disc->readSectors(sector, numSectors, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write numSectors sectors to a disc, starting at sector.
|
Write numSectors sectors to a disc, starting at sector.
|
||||||
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||||
else it is at least 1
|
else it is at least 1
|
||||||
sector is 0 or greater
|
sector is 0 or greater
|
||||||
buffer is a pointer to the memory to read from
|
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 )
|
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 );
|
return disc->writeSectors(sector, numSectors, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reset the card back to a ready state
|
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();
|
return disc->clearStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise the disc to a state ready for data reading or writing
|
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();
|
return disc->startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Put the disc in a state ready for power down.
|
Put the disc in a state ready for power down.
|
||||||
Complete any pending writes and disable the disc if necessary
|
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 disc->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value unique to each type of interface
|
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 disc->ioType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return a 32 bit value that specifies the capabilities of the disc
|
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;
|
return disc->features;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _LIBFAT_H
|
#ifndef _LIBFAT_H
|
||||||
#define _LIBFAT_H
|
#define _LIBFAT_H
|
||||||
@ -44,12 +43,12 @@ extern "C"
|
|||||||
cacheSize: The number of pages to allocate for each inserted block-device
|
cacheSize: The number of pages to allocate for each inserted block-device
|
||||||
setAsDefaultDevice: if true, make this the default device driver for file operations
|
setAsDefaultDevice: if true, make this the default device driver for file operations
|
||||||
*/
|
*/
|
||||||
extern bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice );
|
extern bool fatInit(uint32_t cacheSize, bool setAsDefaultDevice);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
|
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
|
||||||
*/
|
*/
|
||||||
extern bool fatInitDefault ( void );
|
extern bool fatInitDefault(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||||
@ -57,7 +56,7 @@ extern "C"
|
|||||||
This will mount the active partition or the first valid partition on the disc,
|
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.
|
and will use a cache size optimized for the host system.
|
||||||
*/
|
*/
|
||||||
extern bool fatMountSimple ( const char* name, const DISC_INTERFACE* interface );
|
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:".
|
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||||
@ -67,12 +66,13 @@ extern "C"
|
|||||||
cacheSize specifies the number of pages to allocate for the cache.
|
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.
|
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 );
|
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.
|
Unmount the partition specified by name.
|
||||||
If there are open files, it will attempt to synchronise them to disc.
|
If there are open files, it will attempt to synchronise them to disc.
|
||||||
*/
|
*/
|
||||||
extern void fatUnmount ( const char* name );
|
extern void fatUnmount(const char* name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -46,24 +46,25 @@
|
|||||||
|
|
||||||
#define CACHE_FREE UINT_MAX
|
#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;
|
CACHE* cache;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
CACHE_ENTRY* cacheEntries;
|
CACHE_ENTRY* cacheEntries;
|
||||||
|
|
||||||
if ( numberOfPages < 2 )
|
if (numberOfPages < 2)
|
||||||
{
|
{
|
||||||
numberOfPages = 2;
|
numberOfPages = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sectorsPerPage < 8 )
|
if (sectorsPerPage < 8)
|
||||||
{
|
{
|
||||||
sectorsPerPage = 8;
|
sectorsPerPage = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = ( CACHE* ) _FAT_mem_allocate ( sizeof( CACHE ) );
|
cache = (CACHE*) _FAT_mem_allocate(sizeof(CACHE));
|
||||||
if ( cache == NULL )
|
if (cache == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -73,21 +74,20 @@ CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectors
|
|||||||
cache->numberOfPages = numberOfPages;
|
cache->numberOfPages = numberOfPages;
|
||||||
cache->sectorsPerPage = sectorsPerPage;
|
cache->sectorsPerPage = sectorsPerPage;
|
||||||
|
|
||||||
|
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate(sizeof(CACHE_ENTRY) * numberOfPages);
|
||||||
cacheEntries = ( CACHE_ENTRY* ) _FAT_mem_allocate ( sizeof( CACHE_ENTRY ) * numberOfPages );
|
if (cacheEntries == NULL)
|
||||||
if ( cacheEntries == NULL )
|
|
||||||
{
|
{
|
||||||
_FAT_mem_free ( cache );
|
_FAT_mem_free(cache);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( i = 0; i < numberOfPages; i++ )
|
for (i = 0; i < numberOfPages; i++)
|
||||||
{
|
{
|
||||||
cacheEntries[i].sector = CACHE_FREE;
|
cacheEntries[i].sector = CACHE_FREE;
|
||||||
cacheEntries[i].count = 0;
|
cacheEntries[i].count = 0;
|
||||||
cacheEntries[i].last_access = 0;
|
cacheEntries[i].last_access = 0;
|
||||||
cacheEntries[i].dirty = false;
|
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;
|
cache->cacheEntries = cacheEntries;
|
||||||
@ -95,22 +95,21 @@ CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectors
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _FAT_cache_destructor ( CACHE* cache )
|
void _FAT_cache_destructor(CACHE* cache)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
// Clear out cache before destroying it
|
// Clear out cache before destroying it
|
||||||
_FAT_cache_flush( cache );
|
_FAT_cache_flush(cache);
|
||||||
|
|
||||||
// Free memory in reverse allocation order
|
// Free memory in reverse allocation order
|
||||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
{
|
{
|
||||||
_FAT_mem_free ( cache->cacheEntries[i].cache );
|
_FAT_mem_free(cache->cacheEntries[i].cache);
|
||||||
}
|
}
|
||||||
_FAT_mem_free ( cache->cacheEntries );
|
_FAT_mem_free(cache->cacheEntries);
|
||||||
_FAT_mem_free ( cache );
|
_FAT_mem_free(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static u32 accessCounter = 0;
|
static u32 accessCounter = 0;
|
||||||
|
|
||||||
static u32 accessTime()
|
static u32 accessTime()
|
||||||
@ -119,8 +118,7 @@ static u32 accessTime()
|
|||||||
return 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;
|
unsigned int i;
|
||||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
@ -131,60 +129,61 @@ static CACHE_ENTRY* _FAT_cache_getPage( CACHE *cache, sec_t sector )
|
|||||||
unsigned int oldUsed = 0;
|
unsigned int oldUsed = 0;
|
||||||
unsigned int oldAccess = UINT_MAX;
|
unsigned int oldAccess = UINT_MAX;
|
||||||
|
|
||||||
for ( i = 0; i < numberOfPages; i++ )
|
for (i = 0; i < numberOfPages; i++)
|
||||||
{
|
{
|
||||||
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
if (sector >= cacheEntries[i].sector && sector < (cacheEntries[i].sector + cacheEntries[i].count))
|
||||||
{
|
{
|
||||||
cacheEntries[i].last_access = accessTime();
|
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 (foundFree == false && (cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess))
|
||||||
{
|
{
|
||||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
if (cacheEntries[i].sector == CACHE_FREE) foundFree = true;
|
||||||
oldUsed = i;
|
oldUsed = i;
|
||||||
oldAccess = cacheEntries[i].last_access;
|
oldAccess = cacheEntries[i].last_access;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
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 (!_FAT_disc_writeSectors(cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count,
|
||||||
|
cacheEntries[oldUsed].cache)) return NULL;
|
||||||
cacheEntries[oldUsed].dirty = false;
|
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;
|
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].sector = sector;
|
||||||
cacheEntries[oldUsed].count = next_page - sector;
|
cacheEntries[oldUsed].count = next_page - sector;
|
||||||
cacheEntries[oldUsed].last_access = accessTime();
|
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 sec;
|
||||||
sec_t secs_to_read;
|
sec_t secs_to_read;
|
||||||
CACHE_ENTRY *entry;
|
CACHE_ENTRY *entry;
|
||||||
uint8_t *dest = buffer;
|
uint8_t *dest = buffer;
|
||||||
|
|
||||||
while ( numSectors > 0 )
|
while (numSectors > 0)
|
||||||
{
|
{
|
||||||
entry = _FAT_cache_getPage( cache, sector );
|
entry = _FAT_cache_getPage(cache, sector);
|
||||||
if ( entry == NULL ) return false;
|
if (entry == NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
secs_to_read = entry->count - sec;
|
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;
|
sector += secs_to_read;
|
||||||
numSectors -= secs_to_read;
|
numSectors -= secs_to_read;
|
||||||
}
|
}
|
||||||
@ -193,97 +192,111 @@ bool _FAT_cache_readSectors( CACHE *cache, sec_t sector, sec_t numSectors, void
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reads some data from a cache page, determined by the sector number
|
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;
|
sec_t sec;
|
||||||
CACHE_ENTRY *entry;
|
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 );
|
entry = _FAT_cache_getPage(cache, sector);
|
||||||
if ( entry == NULL ) return false;
|
if (entry == NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
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;
|
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];
|
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 1:
|
||||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
*value = buf[0];
|
||||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
break;
|
||||||
default: return false;
|
case 2:
|
||||||
|
*value = u8array_to_u16(buf, 0);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*value = u8array_to_u32(buf, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
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;
|
sec_t sec;
|
||||||
CACHE_ENTRY *entry;
|
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 );
|
entry = _FAT_cache_getPage(cache, sector);
|
||||||
if ( entry == NULL ) return false;
|
if (entry == NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
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;
|
entry->dirty = true;
|
||||||
return 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};
|
uint8_t buf[4] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
switch ( size )
|
switch (size)
|
||||||
{
|
{
|
||||||
case 1: buf[0] = value; break;
|
case 1:
|
||||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
buf[0] = value;
|
||||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
break;
|
||||||
default: return false;
|
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
|
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;
|
sec_t sec;
|
||||||
CACHE_ENTRY *entry;
|
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 );
|
entry = _FAT_cache_getPage(cache, sector);
|
||||||
if ( entry == NULL ) return false;
|
if (entry == NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
memset( entry->cache + ( sec*BYTES_PER_READ ), 0, BYTES_PER_READ );
|
memset(entry->cache + (sec * BYTES_PER_READ), 0, BYTES_PER_READ);
|
||||||
memcpy( entry->cache + ( ( sec*BYTES_PER_READ ) + offset ), buffer, size );
|
memcpy(entry->cache + ((sec * BYTES_PER_READ) + offset), buffer, size);
|
||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
return 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;
|
unsigned int i;
|
||||||
@ -292,12 +305,12 @@ static CACHE_ENTRY* _FAT_cache_findPage( CACHE *cache, sec_t sector, sec_t count
|
|||||||
CACHE_ENTRY *entry = NULL;
|
CACHE_ENTRY *entry = NULL;
|
||||||
sec_t lowest = UINT_MAX;
|
sec_t lowest = UINT_MAX;
|
||||||
|
|
||||||
for ( i = 0; i < numberOfPages; i++ )
|
for (i = 0; i < numberOfPages; i++)
|
||||||
{
|
{
|
||||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
if (cacheEntries[i].sector != CACHE_FREE)
|
||||||
{
|
{
|
||||||
bool intersect;
|
bool intersect;
|
||||||
if ( sector > cacheEntries[i].sector )
|
if (sector > cacheEntries[i].sector)
|
||||||
{
|
{
|
||||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||||
}
|
}
|
||||||
@ -306,7 +319,7 @@ static CACHE_ENTRY* _FAT_cache_findPage( CACHE *cache, sec_t sector, sec_t count
|
|||||||
intersect = cacheEntries[i].sector - sector < count;
|
intersect = cacheEntries[i].sector - sector < count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
if (intersect && (cacheEntries[i].sector < lowest))
|
||||||
{
|
{
|
||||||
lowest = cacheEntries[i].sector;
|
lowest = cacheEntries[i].sector;
|
||||||
entry = &cacheEntries[i];
|
entry = &cacheEntries[i];
|
||||||
@ -317,27 +330,27 @@ static CACHE_ENTRY* _FAT_cache_findPage( CACHE *cache, sec_t sector, sec_t count
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _FAT_cache_writeSectors ( CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer )
|
bool _FAT_cache_writeSectors(CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||||
{
|
{
|
||||||
sec_t sec;
|
sec_t sec;
|
||||||
sec_t secs_to_write;
|
sec_t secs_to_write;
|
||||||
CACHE_ENTRY* entry;
|
CACHE_ENTRY* entry;
|
||||||
const uint8_t *src = buffer;
|
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;
|
secs_to_write = entry->sector - sector;
|
||||||
|
|
||||||
_FAT_disc_writeSectors( cache->disc, sector, secs_to_write, src );
|
_FAT_disc_writeSectors(cache->disc, sector, secs_to_write, src);
|
||||||
src += ( secs_to_write * BYTES_PER_READ );
|
src += (secs_to_write * BYTES_PER_READ);
|
||||||
sector += secs_to_write;
|
sector += secs_to_write;
|
||||||
numSectors -= secs_to_write;
|
numSectors -= secs_to_write;
|
||||||
}
|
}
|
||||||
@ -345,11 +358,11 @@ bool _FAT_cache_writeSectors ( CACHE* cache, sec_t sector, sec_t numSectors, con
|
|||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
secs_to_write = entry->count - sec;
|
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;
|
sector += secs_to_write;
|
||||||
numSectors -= secs_to_write;
|
numSectors -= secs_to_write;
|
||||||
|
|
||||||
@ -358,7 +371,7 @@ bool _FAT_cache_writeSectors ( CACHE* cache, sec_t sector, sec_t numSectors, con
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_FAT_disc_writeSectors( cache->disc, sector, numSectors, src );
|
_FAT_disc_writeSectors(cache->disc, sector, numSectors, src);
|
||||||
numSectors = 0;
|
numSectors = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,17 +379,18 @@ bool _FAT_cache_writeSectors ( CACHE* cache, sec_t sector, sec_t numSectors, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
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;
|
unsigned int i;
|
||||||
|
|
||||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
{
|
{
|
||||||
if ( cache->cacheEntries[i].dirty )
|
if (cache->cacheEntries[i].dirty)
|
||||||
{
|
{
|
||||||
if ( !_FAT_disc_writeSectors ( cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
if (!_FAT_disc_writeSectors(cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count,
|
||||||
|
cache->cacheEntries[i].cache))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -387,11 +401,11 @@ bool _FAT_cache_flush ( CACHE* cache )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _FAT_cache_invalidate ( CACHE* cache )
|
void _FAT_cache_invalidate(CACHE* cache)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
_FAT_cache_flush( cache );
|
_FAT_cache_flush(cache);
|
||||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
{
|
{
|
||||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||||
cache->cacheEntries[i].last_access = 0;
|
cache->cacheEntries[i].last_access = 0;
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CACHE_H
|
#ifndef __CACHE_H
|
||||||
#define __CACHE_H
|
#define __CACHE_H
|
||||||
@ -61,74 +61,76 @@ typedef struct
|
|||||||
} CACHE;
|
} CACHE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read data from a sector in the cache
|
Read data from a sector in the cache
|
||||||
If the sector is not in the cache, it will be swapped in
|
If the sector is not in the cache, it will be swapped in
|
||||||
offset is the position to start reading from
|
offset is the position to start reading from
|
||||||
size is the amount of data to read
|
size is the amount of data to read
|
||||||
Precondition: offset + size <= BYTES_PER_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
|
Write data to a sector in the cache
|
||||||
If the sector is not in the cache, it will be swapped in.
|
If the sector is not in the cache, it will be swapped in.
|
||||||
When the sector is swapped out, the data will be written to the disc
|
When the sector is swapped out, the data will be written to the disc
|
||||||
offset is the position to start writing to
|
offset is the position to start writing to
|
||||||
size is the amount of data to write
|
size is the amount of data to write
|
||||||
Precondition: offset + size <= BYTES_PER_READ
|
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
|
Write data to a sector in the cache, zeroing the sector first
|
||||||
If the sector is not in the cache, it will be swapped in.
|
If the sector is not in the cache, it will be swapped in.
|
||||||
When the sector is swapped out, the data will be written to the disc
|
When the sector is swapped out, the data will be written to the disc
|
||||||
offset is the position to start writing to
|
offset is the position to start writing to
|
||||||
size is the amount of data to write
|
size is the amount of data to write
|
||||||
Precondition: offset + size <= BYTES_PER_READ
|
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
|
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
|
Read a full sector from the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_readSector ( CACHE* cache, void* buffer, sec_t sector )
|
static inline bool _FAT_cache_readSector(CACHE* cache, void* buffer, sec_t sector)
|
||||||
{
|
{
|
||||||
return _FAT_cache_readPartialSector ( cache, buffer, sector, 0, BYTES_PER_READ );
|
return _FAT_cache_readPartialSector(cache, buffer, sector, 0, BYTES_PER_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write a full sector to the cache
|
Write a full sector to the cache
|
||||||
*/
|
*/
|
||||||
static inline bool _FAT_cache_writeSector ( CACHE* cache, const void* buffer, sec_t sector )
|
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 );
|
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
|
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
|
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
|
#endif // _CACHE_H
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -44,55 +44,54 @@
|
|||||||
#include "filetime.h"
|
#include "filetime.h"
|
||||||
#include "lock.h"
|
#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;
|
PARTITION* partition = NULL;
|
||||||
DIR_ENTRY dirEntry;
|
DIR_ENTRY dirEntry;
|
||||||
|
|
||||||
// Get the partition this file is on
|
// Get the partition this file is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath(path);
|
||||||
if ( partition == NULL )
|
if (partition == NULL)
|
||||||
{
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr(path, ':') + 1;
|
||||||
}
|
}
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
// Search for the file on the disc
|
// Search for the file on the disc
|
||||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
|
if (!_FAT_directory_entryFromPath(partition, &dirEntry, path, NULL))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the stat struct
|
// 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;
|
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;
|
r->_errno = ENOTSUP;
|
||||||
return -1;
|
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;
|
PARTITION* partition = NULL;
|
||||||
DIR_ENTRY dirEntry;
|
DIR_ENTRY dirEntry;
|
||||||
@ -102,66 +101,65 @@ int _FAT_unlink_r ( struct _reent *r, const char *path )
|
|||||||
bool errorOccured = false;
|
bool errorOccured = false;
|
||||||
|
|
||||||
// Get the partition this directory is on
|
// Get the partition this directory is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath(path);
|
||||||
if ( partition == NULL )
|
if (partition == NULL)
|
||||||
{
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we aren't trying to write to a read-only disc
|
// Make sure we aren't trying to write to a read-only disc
|
||||||
if ( partition->readOnly )
|
if (partition->readOnly)
|
||||||
{
|
{
|
||||||
r->_errno = EROFS;
|
r->_errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr(path, ':') + 1;
|
||||||
}
|
}
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
// Search for the file on the disc
|
// Search for the file on the disc
|
||||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, NULL ) )
|
if (!_FAT_directory_entryFromPath(partition, &dirEntry, path, NULL))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
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 this is a directory, make sure it is empty
|
||||||
if ( _FAT_directory_isDirectory ( &dirEntry ) )
|
if (_FAT_directory_isDirectory(&dirEntry))
|
||||||
{
|
{
|
||||||
nextEntry = _FAT_directory_getFirstEntry ( partition, &dirContents, cluster );
|
nextEntry = _FAT_directory_getFirstEntry(partition, &dirContents, cluster);
|
||||||
|
|
||||||
while ( nextEntry )
|
while (nextEntry)
|
||||||
{
|
{
|
||||||
if ( !_FAT_directory_isDot ( &dirContents ) )
|
if (!_FAT_directory_isDot(&dirContents))
|
||||||
{
|
{
|
||||||
// The directory had something in it that isn't a reference to itself or it's parent
|
// 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;
|
r->_errno = EPERM;
|
||||||
return -1;
|
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
|
// Remove the cluster chain for this file
|
||||||
if ( !_FAT_fat_clearLinks ( partition, cluster ) )
|
if (!_FAT_fat_clearLinks(partition, cluster))
|
||||||
{
|
{
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
errorOccured = true;
|
errorOccured = true;
|
||||||
@ -169,21 +167,21 @@ int _FAT_unlink_r ( struct _reent *r, const char *path )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the directory entry for this file
|
// Remove the directory entry for this file
|
||||||
if ( !_FAT_directory_removeEntry ( partition, &dirEntry ) )
|
if (!_FAT_directory_removeEntry(partition, &dirEntry))
|
||||||
{
|
{
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
errorOccured = true;
|
errorOccured = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush any sectors in the disc cache
|
// Flush any sectors in the disc cache
|
||||||
if ( !_FAT_cache_flush( partition->cache ) )
|
if (!_FAT_cache_flush(partition->cache))
|
||||||
{
|
{
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
errorOccured = true;
|
errorOccured = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
if ( errorOccured )
|
if (errorOccured)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -193,48 +191,48 @@ int _FAT_unlink_r ( struct _reent *r, const char *path )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_chdir_r ( struct _reent *r, const char *path )
|
int _FAT_chdir_r(struct _reent *r, const char *path)
|
||||||
{
|
{
|
||||||
PARTITION* partition = NULL;
|
PARTITION* partition = NULL;
|
||||||
|
|
||||||
// Get the partition this directory is on
|
// Get the partition this directory is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath(path);
|
||||||
if ( partition == NULL )
|
if (partition == NULL)
|
||||||
{
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr(path, ':') + 1;
|
||||||
}
|
}
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
// Try changing directory
|
// Try changing directory
|
||||||
if ( _FAT_directory_chdir ( partition, path ) )
|
if (_FAT_directory_chdir(partition, path))
|
||||||
{
|
{
|
||||||
// Successful
|
// Successful
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Failed
|
// Failed
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return -1;
|
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;
|
PARTITION* partition = NULL;
|
||||||
DIR_ENTRY oldDirEntry;
|
DIR_ENTRY oldDirEntry;
|
||||||
@ -243,73 +241,73 @@ int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName )
|
|||||||
uint32_t dirCluster;
|
uint32_t dirCluster;
|
||||||
|
|
||||||
// Get the partition this directory is on
|
// Get the partition this directory is on
|
||||||
partition = _FAT_partition_getPartitionFromPath ( oldName );
|
partition = _FAT_partition_getPartitionFromPath(oldName);
|
||||||
if ( partition == NULL )
|
if (partition == NULL)
|
||||||
{
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
// Make sure the same partition is used for the old and new names
|
// Make sure the same partition is used for the old and new names
|
||||||
if ( partition != _FAT_partition_getPartitionFromPath ( newName ) )
|
if (partition != _FAT_partition_getPartitionFromPath(newName))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EXDEV;
|
r->_errno = EXDEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we aren't trying to write to a read-only disc
|
// Make sure we aren't trying to write to a read-only disc
|
||||||
if ( partition->readOnly )
|
if (partition->readOnly)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EROFS;
|
r->_errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if ( strchr ( oldName, ':' ) != NULL )
|
if (strchr(oldName, ':') != NULL)
|
||||||
{
|
{
|
||||||
oldName = strchr ( oldName, ':' ) + 1;
|
oldName = strchr(oldName, ':') + 1;
|
||||||
}
|
}
|
||||||
if ( strchr ( oldName, ':' ) != NULL )
|
if (strchr(oldName, ':') != NULL)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( strchr ( newName, ':' ) != NULL )
|
if (strchr(newName, ':') != NULL)
|
||||||
{
|
{
|
||||||
newName = strchr ( newName, ':' ) + 1;
|
newName = strchr(newName, ':') + 1;
|
||||||
}
|
}
|
||||||
if ( strchr ( newName, ':' ) != NULL )
|
if (strchr(newName, ':') != NULL)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for the file on the disc
|
// Search for the file on the disc
|
||||||
if ( !_FAT_directory_entryFromPath ( partition, &oldDirEntry, oldName, NULL ) )
|
if (!_FAT_directory_entryFromPath(partition, &oldDirEntry, oldName, NULL))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there is no existing file / directory with the new name
|
// Make sure there is no existing file / directory with the new name
|
||||||
if ( _FAT_directory_entryFromPath ( partition, &newDirEntry, newName, NULL ) )
|
if (_FAT_directory_entryFromPath(partition, &newDirEntry, newName, NULL))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the new file entry
|
// Create the new file entry
|
||||||
// Get the directory it has to go in
|
// Get the directory it has to go in
|
||||||
pathEnd = strrchr ( newName, DIR_SEPARATOR );
|
pathEnd = strrchr(newName, DIR_SEPARATOR);
|
||||||
if ( pathEnd == NULL )
|
if (pathEnd == NULL)
|
||||||
{
|
{
|
||||||
// No path was specified
|
// No path was specified
|
||||||
dirCluster = partition->cwdCluster;
|
dirCluster = partition->cwdCluster;
|
||||||
@ -319,53 +317,53 @@ int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName )
|
|||||||
{
|
{
|
||||||
// Path was specified -- get the right dirCluster
|
// Path was specified -- get the right dirCluster
|
||||||
// Recycling newDirEntry, since it needs to be recreated anyway
|
// Recycling newDirEntry, since it needs to be recreated anyway
|
||||||
if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) ||
|
if (!_FAT_directory_entryFromPath(partition, &newDirEntry, newName, pathEnd) || !_FAT_directory_isDirectory(
|
||||||
!_FAT_directory_isDirectory( &newDirEntry ) )
|
&newDirEntry))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dirCluster = _FAT_directory_entryGetCluster ( partition, newDirEntry.entryData );
|
dirCluster = _FAT_directory_entryGetCluster(partition, newDirEntry.entryData);
|
||||||
// Move the pathEnd past the last DIR_SEPARATOR
|
// Move the pathEnd past the last DIR_SEPARATOR
|
||||||
pathEnd += 1;
|
pathEnd += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the entry data
|
// Copy the entry data
|
||||||
memcpy ( &newDirEntry, &oldDirEntry, sizeof( DIR_ENTRY ) );
|
memcpy(&newDirEntry, &oldDirEntry, sizeof(DIR_ENTRY));
|
||||||
|
|
||||||
// Set the new name
|
// Set the new name
|
||||||
strncpy ( newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 );
|
strncpy(newDirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1);
|
||||||
|
|
||||||
// Write the new entry
|
// Write the new entry
|
||||||
if ( !_FAT_directory_addEntry ( partition, &newDirEntry, dirCluster ) )
|
if (!_FAT_directory_addEntry(partition, &newDirEntry, dirCluster))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOSPC;
|
r->_errno = ENOSPC;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the old entry
|
// Remove the old entry
|
||||||
if ( !_FAT_directory_removeEntry ( partition, &oldDirEntry ) )
|
if (!_FAT_directory_removeEntry(partition, &oldDirEntry))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush any sectors in the disc cache
|
// Flush any sectors in the disc cache
|
||||||
if ( !_FAT_cache_flush ( partition->cache ) )
|
if (!_FAT_cache_flush(partition->cache))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
return 0;
|
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;
|
PARTITION* partition = NULL;
|
||||||
bool fileExists;
|
bool fileExists;
|
||||||
@ -374,48 +372,48 @@ int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
|
|||||||
uint32_t parentCluster, dirCluster;
|
uint32_t parentCluster, dirCluster;
|
||||||
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
||||||
|
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath(path);
|
||||||
if ( partition == NULL )
|
if (partition == NULL)
|
||||||
{
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr(path, ':') + 1;
|
||||||
}
|
}
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
// Search for the file/directory on the disc
|
// 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
|
// Make sure it doesn't exist
|
||||||
if ( fileExists )
|
if (fileExists)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( partition->readOnly )
|
if (partition->readOnly)
|
||||||
{
|
{
|
||||||
// We can't write to a read-only partition
|
// We can't write to a read-only partition
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EROFS;
|
r->_errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the directory it has to go in
|
// Get the directory it has to go in
|
||||||
pathEnd = strrchr ( path, DIR_SEPARATOR );
|
pathEnd = strrchr(path, DIR_SEPARATOR);
|
||||||
if ( pathEnd == NULL )
|
if (pathEnd == NULL)
|
||||||
{
|
{
|
||||||
// No path was specified
|
// No path was specified
|
||||||
parentCluster = partition->cwdCluster;
|
parentCluster = partition->cwdCluster;
|
||||||
@ -425,107 +423,105 @@ int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
|
|||||||
{
|
{
|
||||||
// Path was specified -- get the right parentCluster
|
// Path was specified -- get the right parentCluster
|
||||||
// Recycling dirEntry, since it needs to be recreated anyway
|
// Recycling dirEntry, since it needs to be recreated anyway
|
||||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
|
if (!_FAT_directory_entryFromPath(partition, &dirEntry, path, pathEnd)
|
||||||
!_FAT_directory_isDirectory( &dirEntry ) )
|
|| !_FAT_directory_isDirectory(&dirEntry))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
parentCluster = _FAT_directory_entryGetCluster ( partition, dirEntry.entryData );
|
parentCluster = _FAT_directory_entryGetCluster(partition, dirEntry.entryData);
|
||||||
// Move the pathEnd past the last DIR_SEPARATOR
|
// Move the pathEnd past the last DIR_SEPARATOR
|
||||||
pathEnd += 1;
|
pathEnd += 1;
|
||||||
}
|
}
|
||||||
// Create the entry data
|
// Create the entry data
|
||||||
strncpy ( dirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1 );
|
strncpy(dirEntry.filename, pathEnd, MAX_FILENAME_LENGTH - 1);
|
||||||
memset ( dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE );
|
memset(dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||||
|
|
||||||
// Set the creation time and date
|
// Set the creation time and date
|
||||||
dirEntry.entryData[DIR_ENTRY_cTime_ms] = 0;
|
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_cTime, _FAT_filetime_getTimeFromRTC());
|
||||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC() );
|
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_mTime, _FAT_filetime_getTimeFromRTC());
|
||||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_mDate, _FAT_filetime_getDateFromRTC() );
|
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_aDate, _FAT_filetime_getDateFromRTC());
|
||||||
|
|
||||||
// Set the directory attribute
|
// Set the directory attribute
|
||||||
dirEntry.entryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
dirEntry.entryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||||
|
|
||||||
// Get a cluster for the new directory
|
// Get a cluster for the new directory
|
||||||
dirCluster = _FAT_fat_linkFreeClusterCleared ( partition, CLUSTER_FREE );
|
dirCluster = _FAT_fat_linkFreeClusterCleared(partition, CLUSTER_FREE);
|
||||||
if ( !_FAT_fat_isValidCluster( partition, dirCluster ) )
|
if (!_FAT_fat_isValidCluster(partition, dirCluster))
|
||||||
{
|
{
|
||||||
// No space left on disc for the cluster
|
// No space left on disc for the cluster
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOSPC;
|
r->_errno = ENOSPC;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
u16_to_u8array ( dirEntry.entryData, DIR_ENTRY_cluster, dirCluster );
|
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_clusterHigh, dirCluster >> 16);
|
||||||
|
|
||||||
// Write the new directory's entry to it's parent
|
// Write the new directory's entry to it's parent
|
||||||
if ( !_FAT_directory_addEntry ( partition, &dirEntry, parentCluster ) )
|
if (!_FAT_directory_addEntry(partition, &dirEntry, parentCluster))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = ENOSPC;
|
r->_errno = ENOSPC;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the dot entry within the directory
|
// Create the dot entry within the directory
|
||||||
memset ( newEntryData, 0, DIR_ENTRY_DATA_SIZE );
|
memset(newEntryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||||
memset ( newEntryData, ' ', 11 );
|
memset(newEntryData, ' ', 11);
|
||||||
newEntryData[DIR_ENTRY_name] = '.';
|
newEntryData[DIR_ENTRY_name] = '.';
|
||||||
newEntryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
newEntryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||||
u16_to_u8array ( newEntryData, DIR_ENTRY_cluster, dirCluster );
|
u16_to_u8array(newEntryData, DIR_ENTRY_cluster, dirCluster);
|
||||||
u16_to_u8array ( newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16 );
|
u16_to_u8array(newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||||
|
|
||||||
// Write it to the directory, erasing that sector in the process
|
// Write it to the directory, erasing that sector in the process
|
||||||
_FAT_cache_eraseWritePartialSector ( partition->cache, newEntryData,
|
_FAT_cache_eraseWritePartialSector(partition->cache, newEntryData, _FAT_fat_clusterToSector(partition, dirCluster),
|
||||||
_FAT_fat_clusterToSector ( partition, dirCluster ), 0, DIR_ENTRY_DATA_SIZE );
|
0, DIR_ENTRY_DATA_SIZE);
|
||||||
|
|
||||||
|
|
||||||
// Create the double dot entry within the directory
|
// Create the double dot entry within the directory
|
||||||
|
|
||||||
// if ParentDir == Rootdir then ".."" always link to Cluster 0
|
// if ParentDir == Rootdir then ".."" always link to Cluster 0
|
||||||
if ( parentCluster == partition->rootDirCluster )
|
if (parentCluster == partition->rootDirCluster) parentCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||||
parentCluster = FAT16_ROOT_DIR_CLUSTER;
|
|
||||||
|
|
||||||
newEntryData[DIR_ENTRY_name + 1] = '.';
|
newEntryData[DIR_ENTRY_name + 1] = '.';
|
||||||
u16_to_u8array ( newEntryData, DIR_ENTRY_cluster, parentCluster );
|
u16_to_u8array(newEntryData, DIR_ENTRY_cluster, parentCluster);
|
||||||
u16_to_u8array ( newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16 );
|
u16_to_u8array(newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16);
|
||||||
|
|
||||||
// Write it to the directory
|
// Write it to the directory
|
||||||
_FAT_cache_writePartialSector ( partition->cache, newEntryData,
|
_FAT_cache_writePartialSector(partition->cache, newEntryData, _FAT_fat_clusterToSector(partition, dirCluster),
|
||||||
_FAT_fat_clusterToSector ( partition, dirCluster ), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||||
|
|
||||||
// Flush any sectors in the disc cache
|
// Flush any sectors in the disc cache
|
||||||
if ( !_FAT_cache_flush( partition->cache ) )
|
if (!_FAT_cache_flush(partition->cache))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
r->_errno = EIO;
|
r->_errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
return 0;
|
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;
|
PARTITION* partition = NULL;
|
||||||
unsigned int freeClusterCount;
|
unsigned int freeClusterCount;
|
||||||
|
|
||||||
// Get the partition of the requested path
|
// Get the partition of the requested path
|
||||||
partition = _FAT_partition_getPartitionFromPath ( path );
|
partition = _FAT_partition_getPartitionFromPath(path);
|
||||||
if ( partition == NULL )
|
if (partition == NULL)
|
||||||
{
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
freeClusterCount = _FAT_fat_freeClusterCount ( partition );
|
freeClusterCount = _FAT_fat_freeClusterCount(partition);
|
||||||
|
|
||||||
// FAT clusters = POSIX blocks
|
// FAT clusters = POSIX blocks
|
||||||
buf->f_bsize = partition->bytesPerCluster; // File system block size.
|
buf->f_bsize = partition->bytesPerCluster; // File system block size.
|
||||||
@ -541,143 +537,140 @@ 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.
|
buf->f_favail = freeClusterCount; // Number of file serial numbers available to non-privileged process.
|
||||||
|
|
||||||
// File system ID. 32bit ioType value
|
// 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.
|
// Bit mask of f_flag values.
|
||||||
buf->f_flag = ST_NOSUID /* No support for ST_ISUID and ST_ISGID file mode bits */
|
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.
|
// Maximum filename length.
|
||||||
buf->f_namemax = MAX_FILENAME_LENGTH;
|
buf->f_namemax = MAX_FILENAME_LENGTH;
|
||||||
|
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
return 0;
|
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_ENTRY dirEntry;
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||||
bool fileExists;
|
bool fileExists;
|
||||||
|
|
||||||
state->partition = _FAT_partition_getPartitionFromPath ( path );
|
state->partition = _FAT_partition_getPartitionFromPath(path);
|
||||||
if ( state->partition == NULL )
|
if (state->partition == NULL)
|
||||||
{
|
{
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the path pointer to the start of the actual path
|
// Move the path pointer to the start of the actual path
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
path = strchr ( path, ':' ) + 1;
|
path = strchr(path, ':') + 1;
|
||||||
}
|
}
|
||||||
if ( strchr ( path, ':' ) != NULL )
|
if (strchr(path, ':') != NULL)
|
||||||
{
|
{
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_lock( &state->partition->lock );
|
_FAT_lock(&state->partition->lock);
|
||||||
|
|
||||||
// Get the start cluster of the directory
|
// 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 )
|
if (!fileExists)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock(&state->partition->lock);
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure it is a directory
|
// Make sure it is a directory
|
||||||
if ( ! _FAT_directory_isDirectory ( &dirEntry ) )
|
if (!_FAT_directory_isDirectory(&dirEntry))
|
||||||
{
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock(&state->partition->lock);
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the start cluster for use when resetting the directory data
|
// 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
|
// Get the first entry for use with a call to dirnext
|
||||||
state->validEntry =
|
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
|
// We are now using this entry
|
||||||
state->inUse = true;
|
state->inUse = true;
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock(&state->partition->lock);
|
||||||
return ( DIR_ITER* ) state;
|
return (DIR_ITER*) state;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_dirreset_r ( struct _reent *r, DIR_ITER *dirState )
|
int _FAT_dirreset_r(struct _reent *r, DIR_ITER *dirState)
|
||||||
{
|
{
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
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
|
// Make sure we are still using this entry
|
||||||
if ( !state->inUse )
|
if (!state->inUse)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock(&state->partition->lock);
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the first entry for use with a call to dirnext
|
// Get the first entry for use with a call to dirnext
|
||||||
state->validEntry =
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat )
|
int _FAT_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
|
||||||
{
|
{
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
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
|
// Make sure we are still using this entry
|
||||||
if ( !state->inUse )
|
if (!state->inUse)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock(&state->partition->lock);
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there is another file to report on
|
// Make sure there is another file to report on
|
||||||
if ( ! state->validEntry )
|
if (!state->validEntry)
|
||||||
{
|
{
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock(&state->partition->lock);
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the filename
|
// Get the filename
|
||||||
strncpy ( filename, state->currentEntry.filename, MAX_FILENAME_LENGTH );
|
strncpy(filename, state->currentEntry.filename, MAX_FILENAME_LENGTH);
|
||||||
// Get the stats, if requested
|
// Get the stats, if requested
|
||||||
if ( filestat != NULL )
|
if (filestat != NULL)
|
||||||
{
|
{
|
||||||
_FAT_directory_entryStat ( state->partition, &( state->currentEntry ), filestat );
|
_FAT_directory_entryStat(state->partition, &(state->currentEntry), filestat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for the next entry for use next time
|
// Look for the next entry for use next time
|
||||||
state->validEntry =
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _FAT_dirclose_r ( struct _reent *r, DIR_ITER *dirState )
|
int _FAT_dirclose_r(struct _reent *r, DIR_ITER *dirState)
|
||||||
{
|
{
|
||||||
DIR_STATE_STRUCT* state = ( DIR_STATE_STRUCT* ) ( dirState->dirStruct );
|
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||||
|
|
||||||
// We are no longer using this entry
|
// We are no longer using this entry
|
||||||
_FAT_lock( &state->partition->lock );
|
_FAT_lock(&state->partition->lock);
|
||||||
state->inUse = false;
|
state->inUse = false;
|
||||||
_FAT_unlock( &state->partition->lock );
|
_FAT_unlock(&state->partition->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef __FATDIR_H
|
#ifndef __FATDIR_H
|
||||||
#define __FATDIR_H
|
#define __FATDIR_H
|
||||||
@ -48,27 +47,26 @@ typedef struct
|
|||||||
bool validEntry;
|
bool validEntry;
|
||||||
} DIR_STATE_STRUCT;
|
} 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
|
Directory iterator functions
|
||||||
*/
|
*/
|
||||||
extern DIR_ITER* _FAT_diropen_r( struct _reent *r, DIR_ITER *dirState, const char *path );
|
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_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_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 int _FAT_dirclose_r(struct _reent *r, DIR_ITER *dirState);
|
||||||
|
|
||||||
|
|
||||||
#endif // _FATDIR_H
|
#endif // _FATDIR_H
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -26,8 +26,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FATFILE_H
|
#ifndef _FATFILE_H
|
||||||
#define _FATFILE_H
|
#define _FATFILE_H
|
||||||
@ -40,7 +39,6 @@
|
|||||||
#include "directory.h"
|
#include "directory.h"
|
||||||
|
|
||||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
u32 cluster;
|
u32 cluster;
|
||||||
@ -71,37 +69,37 @@ struct _FILE_STRUCT
|
|||||||
|
|
||||||
typedef struct _FILE_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.
|
Synchronizes the file data to disc.
|
||||||
Does no locking of its own -- lock the partition before calling.
|
Does no locking of its own -- lock the partition before calling.
|
||||||
Returns 0 on success, an error code on failure.
|
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
|
#endif // _FATFILE_H
|
||||||
|
@ -25,28 +25,27 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "file_allocation_table.h"
|
#include "file_allocation_table.h"
|
||||||
#include "partition.h"
|
#include "partition.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Gets the cluster linked from input cluster
|
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;
|
uint32_t nextCluster = CLUSTER_FREE;
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
if ( cluster == CLUSTER_FREE )
|
if (cluster == CLUSTER_FREE)
|
||||||
{
|
{
|
||||||
return CLUSTER_FREE;
|
return CLUSTER_FREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( partition->filesysType )
|
switch (partition->filesysType)
|
||||||
{
|
{
|
||||||
case FS_UNKNOWN:
|
case FS_UNKNOWN:
|
||||||
return CLUSTER_ERROR;
|
return CLUSTER_ERROR;
|
||||||
@ -55,25 +54,24 @@ uint32_t _FAT_fat_nextCluster( PARTITION* partition, uint32_t cluster )
|
|||||||
case FS_FAT12:
|
case FS_FAT12:
|
||||||
{
|
{
|
||||||
u32 nextCluster_h;
|
u32 nextCluster_h;
|
||||||
sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ );
|
sector = partition->fat.fatStart + (((cluster * 3) / 2) / BYTES_PER_READ);
|
||||||
offset = ( ( cluster * 3 ) / 2 ) % BYTES_PER_READ;
|
offset = ((cluster * 3) / 2) % BYTES_PER_READ;
|
||||||
|
|
||||||
|
_FAT_cache_readLittleEndianValue(partition->cache, &nextCluster, sector, offset, sizeof(u8));
|
||||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster, sector, offset, sizeof( u8 ) );
|
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
|
|
||||||
if ( offset >= BYTES_PER_READ )
|
if (offset >= BYTES_PER_READ)
|
||||||
{
|
{
|
||||||
offset = 0;
|
offset = 0;
|
||||||
sector++;
|
sector++;
|
||||||
}
|
}
|
||||||
nextCluster_h = 0;
|
nextCluster_h = 0;
|
||||||
|
|
||||||
_FAT_cache_readLittleEndianValue ( partition->cache, &nextCluster_h, sector, offset, sizeof( u8 ) );
|
_FAT_cache_readLittleEndianValue(partition->cache, &nextCluster_h, sector, offset, sizeof(u8));
|
||||||
nextCluster |= ( nextCluster_h << 8 );
|
nextCluster |= (nextCluster_h << 8);
|
||||||
|
|
||||||
if ( cluster & 0x01 )
|
if (cluster & 0x01)
|
||||||
{
|
{
|
||||||
nextCluster = nextCluster >> 4;
|
nextCluster = nextCluster >> 4;
|
||||||
}
|
}
|
||||||
@ -82,7 +80,7 @@ uint32_t _FAT_fat_nextCluster( PARTITION* partition, uint32_t cluster )
|
|||||||
nextCluster &= 0x0FFF;
|
nextCluster &= 0x0FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( nextCluster >= 0x0FF7 )
|
if (nextCluster >= 0x0FF7)
|
||||||
{
|
{
|
||||||
nextCluster = CLUSTER_EOF;
|
nextCluster = CLUSTER_EOF;
|
||||||
}
|
}
|
||||||
@ -90,24 +88,24 @@ uint32_t _FAT_fat_nextCluster( PARTITION* partition, uint32_t cluster )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FS_FAT16:
|
case FS_FAT16:
|
||||||
sector = partition->fat.fatStart + ( ( cluster << 1 ) / BYTES_PER_READ );
|
sector = partition->fat.fatStart + ((cluster << 1) / BYTES_PER_READ);
|
||||||
offset = ( cluster % ( BYTES_PER_READ >> 1 ) ) << 1;
|
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;
|
nextCluster = CLUSTER_EOF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FS_FAT32:
|
case FS_FAT32:
|
||||||
sector = partition->fat.fatStart + ( ( cluster << 2 ) / BYTES_PER_READ );
|
sector = partition->fat.fatStart + ((cluster << 2) / BYTES_PER_READ);
|
||||||
offset = ( cluster % ( BYTES_PER_READ >> 2 ) ) << 2;
|
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;
|
nextCluster = CLUSTER_EOF;
|
||||||
}
|
}
|
||||||
@ -122,83 +120,83 @@ uint32_t _FAT_fat_nextCluster( PARTITION* partition, uint32_t cluster )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
writes value into the correct offset within a partition's FAT, based
|
writes value into the correct offset within a partition's FAT, based
|
||||||
on the cluster number.
|
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;
|
sec_t sector;
|
||||||
int offset;
|
int offset;
|
||||||
uint32_t oldValue;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( partition->filesysType )
|
switch (partition->filesysType)
|
||||||
{
|
{
|
||||||
case FS_UNKNOWN:
|
case FS_UNKNOWN:
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FS_FAT12:
|
case FS_FAT12:
|
||||||
sector = partition->fat.fatStart + ( ( ( cluster * 3 ) / 2 ) / BYTES_PER_READ );
|
sector = partition->fat.fatStart + (((cluster * 3) / 2) / BYTES_PER_READ);
|
||||||
offset = ( ( 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++;
|
offset++;
|
||||||
if ( offset >= BYTES_PER_READ )
|
if (offset >= BYTES_PER_READ)
|
||||||
{
|
{
|
||||||
offset = 0;
|
offset = 0;
|
||||||
sector++;
|
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++;
|
offset++;
|
||||||
if ( offset >= BYTES_PER_READ )
|
if (offset >= BYTES_PER_READ)
|
||||||
{
|
{
|
||||||
offset = 0;
|
offset = 0;
|
||||||
sector++;
|
sector++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FAT_cache_readLittleEndianValue ( partition->cache, &oldValue, sector, offset, sizeof( u8 ) );
|
_FAT_cache_readLittleEndianValue(partition->cache, &oldValue, sector, offset, sizeof(u8));
|
||||||
|
|
||||||
value = ( ( value >> 8 ) & 0x0F ) | ( oldValue & 0xF0 );
|
value = ((value >> 8) & 0x0F) | (oldValue & 0xF0);
|
||||||
|
|
||||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u8 ) );
|
_FAT_cache_writeLittleEndianValue(partition->cache, value, sector, offset, sizeof(u8));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FS_FAT16:
|
case FS_FAT16:
|
||||||
sector = partition->fat.fatStart + ( ( cluster << 1 ) / BYTES_PER_READ );
|
sector = partition->fat.fatStart + ((cluster << 1) / BYTES_PER_READ);
|
||||||
offset = ( cluster % ( BYTES_PER_READ >> 1 ) ) << 1;
|
offset = (cluster % (BYTES_PER_READ >> 1)) << 1;
|
||||||
|
|
||||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u16 ) );
|
_FAT_cache_writeLittleEndianValue(partition->cache, value, sector, offset, sizeof(u16));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FS_FAT32:
|
case FS_FAT32:
|
||||||
sector = partition->fat.fatStart + ( ( cluster << 2 ) / BYTES_PER_READ );
|
sector = partition->fat.fatStart + ((cluster << 2) / BYTES_PER_READ);
|
||||||
offset = ( cluster % ( BYTES_PER_READ >> 2 ) ) << 2;
|
offset = (cluster % (BYTES_PER_READ >> 2)) << 2;
|
||||||
|
|
||||||
_FAT_cache_writeLittleEndianValue ( partition->cache, value, sector, offset, sizeof( u32 ) );
|
_FAT_cache_writeLittleEndianValue(partition->cache, value, sector, offset, sizeof(u32));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -211,12 +209,12 @@ static bool _FAT_fat_writeFatEntry ( PARTITION* partition, uint32_t cluster, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
gets the first available free cluster, sets it
|
gets the first available free cluster, sets it
|
||||||
to end of file, links the input cluster to it then returns the
|
to end of file, links the input cluster to it then returns the
|
||||||
cluster number
|
cluster number
|
||||||
If an error occurs, return CLUSTER_ERROR
|
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 firstFree;
|
||||||
uint32_t curLink;
|
uint32_t curLink;
|
||||||
@ -225,14 +223,14 @@ uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
|
|||||||
|
|
||||||
lastCluster = partition->fat.lastCluster;
|
lastCluster = partition->fat.lastCluster;
|
||||||
|
|
||||||
if ( cluster > lastCluster )
|
if (cluster > lastCluster)
|
||||||
{
|
{
|
||||||
return CLUSTER_ERROR;
|
return CLUSTER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the cluster already has a link, and return it if so
|
// Check if the cluster already has a link, and return it if so
|
||||||
curLink = _FAT_fat_nextCluster( partition, cluster );
|
curLink = _FAT_fat_nextCluster(partition, cluster);
|
||||||
if ( ( curLink >= CLUSTER_FIRST ) && ( curLink <= lastCluster ) )
|
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster))
|
||||||
{
|
{
|
||||||
return curLink; // Return the current link - don't allocate a new one
|
return curLink; // Return the current link - don't allocate a new one
|
||||||
}
|
}
|
||||||
@ -240,18 +238,18 @@ uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
|
|||||||
// Get a free cluster
|
// Get a free cluster
|
||||||
firstFree = partition->fat.firstFree;
|
firstFree = partition->fat.firstFree;
|
||||||
// Start at first valid cluster
|
// Start at first valid cluster
|
||||||
if ( firstFree < CLUSTER_FIRST )
|
if (firstFree < CLUSTER_FIRST)
|
||||||
{
|
{
|
||||||
firstFree = CLUSTER_FIRST;
|
firstFree = CLUSTER_FIRST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search until a free cluster is found
|
// Search until a free cluster is found
|
||||||
while ( _FAT_fat_nextCluster( partition, firstFree ) != CLUSTER_FREE )
|
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE)
|
||||||
{
|
{
|
||||||
firstFree++;
|
firstFree++;
|
||||||
if ( firstFree > lastCluster )
|
if (firstFree > lastCluster)
|
||||||
{
|
{
|
||||||
if ( loopedAroundFAT )
|
if (loopedAroundFAT)
|
||||||
{
|
{
|
||||||
// If couldn't get a free cluster then return an error
|
// If couldn't get a free cluster then return an error
|
||||||
partition->fat.firstFree = firstFree;
|
partition->fat.firstFree = firstFree;
|
||||||
@ -268,74 +266,70 @@ uint32_t _FAT_fat_linkFreeCluster( PARTITION* partition, uint32_t cluster )
|
|||||||
}
|
}
|
||||||
partition->fat.firstFree = firstFree;
|
partition->fat.firstFree = firstFree;
|
||||||
|
|
||||||
if ( ( cluster >= CLUSTER_FIRST ) && ( cluster < lastCluster ) )
|
if ((cluster >= CLUSTER_FIRST) && (cluster < lastCluster))
|
||||||
{
|
{
|
||||||
// Update the linked from FAT entry
|
// Update the linked from FAT entry
|
||||||
_FAT_fat_writeFatEntry ( partition, cluster, firstFree );
|
_FAT_fat_writeFatEntry(partition, cluster, firstFree);
|
||||||
}
|
}
|
||||||
// Create the linked to FAT entry
|
// Create the linked to FAT entry
|
||||||
_FAT_fat_writeFatEntry ( partition, firstFree, CLUSTER_EOF );
|
_FAT_fat_writeFatEntry(partition, firstFree, CLUSTER_EOF);
|
||||||
|
|
||||||
return firstFree;
|
return firstFree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
gets the first available free cluster, sets it
|
gets the first available free cluster, sets it
|
||||||
to end of file, links the input cluster to it, clears the new
|
to end of file, links the input cluster to it, clears the new
|
||||||
cluster to 0 valued bytes, then returns the cluster number
|
cluster to 0 valued bytes, then returns the cluster number
|
||||||
If an error occurs, return CLUSTER_ERROR
|
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 newCluster;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t emptySector[BYTES_PER_READ];
|
uint8_t emptySector[BYTES_PER_READ];
|
||||||
|
|
||||||
// Link the cluster
|
// 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;
|
return CLUSTER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all the sectors within the cluster
|
// Clear all the sectors within the cluster
|
||||||
memset ( emptySector, 0, BYTES_PER_READ );
|
memset(emptySector, 0, BYTES_PER_READ);
|
||||||
for ( i = 0; i < partition->sectorsPerCluster; i++ )
|
for (i = 0; i < partition->sectorsPerCluster; i++)
|
||||||
{
|
{
|
||||||
_FAT_cache_writeSectors ( partition->cache,
|
_FAT_cache_writeSectors(partition->cache, _FAT_fat_clusterToSector(partition, newCluster) + i, 1, emptySector);
|
||||||
_FAT_fat_clusterToSector ( partition, newCluster ) + i,
|
|
||||||
1, emptySector );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newCluster;
|
return newCluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
_FAT_fat_clearLinks
|
_FAT_fat_clearLinks
|
||||||
frees any cluster used by a file
|
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;
|
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;
|
||||||
return false;
|
|
||||||
|
|
||||||
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
// 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;
|
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
|
// Store next cluster before erasing the link
|
||||||
nextCluster = _FAT_fat_nextCluster ( partition, cluster );
|
nextCluster = _FAT_fat_nextCluster(partition, cluster);
|
||||||
|
|
||||||
// Erase the link
|
// Erase the link
|
||||||
_FAT_fat_writeFatEntry ( partition, cluster, CLUSTER_FREE );
|
_FAT_fat_writeFatEntry(partition, cluster, CLUSTER_FREE);
|
||||||
|
|
||||||
// Move onto next cluster
|
// Move onto next cluster
|
||||||
cluster = nextCluster;
|
cluster = nextCluster;
|
||||||
@ -345,73 +339,74 @@ bool _FAT_fat_clearLinks ( PARTITION* partition, uint32_t cluster )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
_FAT_fat_trimChain
|
_FAT_fat_trimChain
|
||||||
Drop all clusters past the chainLength.
|
Drop all clusters past the chainLength.
|
||||||
If chainLength is 0, all clusters are dropped.
|
If chainLength is 0, all clusters are dropped.
|
||||||
If chainLength is 1, the first cluster is kept and the rest are
|
If chainLength is 1, the first cluster is kept and the rest are
|
||||||
dropped, and so on.
|
dropped, and so on.
|
||||||
Return the last cluster left in the chain.
|
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;
|
uint32_t nextCluster;
|
||||||
|
|
||||||
if ( chainLength == 0 )
|
if (chainLength == 0)
|
||||||
{
|
{
|
||||||
// Drop the entire chain
|
// Drop the entire chain
|
||||||
_FAT_fat_clearLinks ( partition, startCluster );
|
_FAT_fat_clearLinks(partition, startCluster);
|
||||||
return CLUSTER_FREE;
|
return CLUSTER_FREE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Find the last cluster in the chain, and the one after it
|
// Find the last cluster in the chain, and the one after it
|
||||||
chainLength--;
|
chainLength--;
|
||||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
nextCluster = _FAT_fat_nextCluster(partition, startCluster);
|
||||||
while ( ( chainLength > 0 ) && ( nextCluster != CLUSTER_FREE ) && ( nextCluster != CLUSTER_EOF ) )
|
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF))
|
||||||
{
|
{
|
||||||
chainLength--;
|
chainLength--;
|
||||||
startCluster = nextCluster;
|
startCluster = nextCluster;
|
||||||
nextCluster = _FAT_fat_nextCluster ( partition, startCluster );
|
nextCluster = _FAT_fat_nextCluster(partition, startCluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop all clusters after the last in the chain
|
// Drop all clusters after the last in the chain
|
||||||
if ( nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF )
|
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF)
|
||||||
{
|
{
|
||||||
_FAT_fat_clearLinks ( partition, nextCluster );
|
_FAT_fat_clearLinks(partition, nextCluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the last cluster in the chain as the end of the file
|
// 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;
|
return startCluster;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
_FAT_fat_lastCluster
|
_FAT_fat_lastCluster
|
||||||
Trace the cluster links until the last one is found
|
Trace the cluster links until the last one is found
|
||||||
-----------------------------------------------------------------*/
|
-----------------------------------------------------------------*/
|
||||||
uint32_t _FAT_fat_lastCluster ( PARTITION* partition, uint32_t 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 ) )
|
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster)
|
||||||
|
!= CLUSTER_EOF))
|
||||||
{
|
{
|
||||||
cluster = _FAT_fat_nextCluster( partition, cluster );
|
cluster = _FAT_fat_nextCluster(partition, cluster);
|
||||||
}
|
}
|
||||||
return cluster;
|
return cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
_FAT_fat_freeClusterCount
|
_FAT_fat_freeClusterCount
|
||||||
Return the number of free clusters available
|
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;
|
unsigned int count = 0;
|
||||||
uint32_t curCluster;
|
uint32_t curCluster;
|
||||||
|
|
||||||
for ( curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++ )
|
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++)
|
||||||
{
|
{
|
||||||
if ( _FAT_fat_nextCluster( partition, curCluster ) == CLUSTER_FREE )
|
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FAT_H
|
#ifndef __FAT_H
|
||||||
#define __FAT_H
|
#define __FAT_H
|
||||||
@ -43,30 +43,28 @@
|
|||||||
#define CLUSTERS_PER_FAT12 4085
|
#define CLUSTERS_PER_FAT12 4085
|
||||||
#define CLUSTERS_PER_FAT16 65525
|
#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 );
|
bool _FAT_fat_clearLinks(PARTITION* partition, uint32_t cluster);
|
||||||
uint32_t _FAT_fat_linkFreeClusterCleared ( 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)
|
||||||
|
|
||||||
static inline sec_t _FAT_fat_clusterToSector ( PARTITION* partition, uint32_t cluster )
|
|
||||||
{
|
{
|
||||||
return ( cluster >= CLUSTER_FIRST ) ?
|
return (cluster >= CLUSTER_FIRST) ? ((cluster - CLUSTER_FIRST) * (sec_t) partition->sectorsPerCluster)
|
||||||
( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart :
|
+ partition->dataStart : partition->rootDirStart;
|
||||||
partition->rootDirStart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _FAT_fat_isValidCluster ( PARTITION* partition, uint32_t cluster )
|
static inline bool _FAT_fat_isValidCluster(PARTITION* partition, uint32_t cluster)
|
||||||
{
|
{
|
||||||
return ( cluster >= CLUSTER_FIRST ) && ( cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ );
|
return (cluster >= CLUSTER_FIRST) && (cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _FAT_H
|
#endif // _FAT_H
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "filetime.h"
|
#include "filetime.h"
|
||||||
@ -40,73 +39,65 @@
|
|||||||
#define MAX_DAY 31
|
#define MAX_DAY 31
|
||||||
#define MIN_DAY 1
|
#define MIN_DAY 1
|
||||||
|
|
||||||
uint16_t _FAT_filetime_getTimeFromRTC ( void )
|
uint16_t _FAT_filetime_getTimeFromRTC(void)
|
||||||
{
|
{
|
||||||
#ifdef USE_RTC_TIME
|
#ifdef USE_RTC_TIME
|
||||||
struct tm timeParts;
|
struct tm timeParts;
|
||||||
time_t epochTime;
|
time_t epochTime;
|
||||||
|
|
||||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
if (time(&epochTime) == (time_t) -1)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
localtime_r( &epochTime, &timeParts );
|
localtime_r(&epochTime, &timeParts);
|
||||||
|
|
||||||
// Check that the values are all in range.
|
// Check that the values are all in range.
|
||||||
// If they are not, return 0 (no timestamp)
|
// If they are not, return 0 (no timestamp)
|
||||||
if ( ( timeParts.tm_hour < 0 ) || ( timeParts.tm_hour > MAX_HOUR ) ) 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_min < 0) || (timeParts.tm_min > MAX_MINUTE)) return 0;
|
||||||
if ( ( timeParts.tm_sec < 0 ) || ( timeParts.tm_sec > MAX_SECOND ) ) return 0;
|
if ((timeParts.tm_sec < 0) || (timeParts.tm_sec > MAX_SECOND)) return 0;
|
||||||
|
|
||||||
return (
|
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
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t _FAT_filetime_getDateFromRTC(void)
|
||||||
uint16_t _FAT_filetime_getDateFromRTC ( void )
|
|
||||||
{
|
{
|
||||||
#ifdef USE_RTC_TIME
|
#ifdef USE_RTC_TIME
|
||||||
struct tm timeParts;
|
struct tm timeParts;
|
||||||
time_t epochTime;
|
time_t epochTime;
|
||||||
|
|
||||||
if ( time( &epochTime ) == ( time_t ) - 1 )
|
if (time(&epochTime) == (time_t) -1)
|
||||||
{
|
{
|
||||||
return 0;
|
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_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_mday < MIN_DAY) || (timeParts.tm_mday > MAX_DAY)) return 0;
|
||||||
|
|
||||||
return (
|
return ((((timeParts.tm_year - 80) & 0x7F) << 9) | // Adjust for MS-FAT base year (1980 vs 1900 for tm_year)
|
||||||
( ( ( 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_mon + 1 ) & 0xF ) << 5 ) |
|
|
||||||
( timeParts.tm_mday & 0x1F )
|
|
||||||
);
|
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#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;
|
struct tm timeParts;
|
||||||
|
|
||||||
timeParts.tm_hour = t >> 11;
|
timeParts.tm_hour = t >> 11;
|
||||||
timeParts.tm_min = ( t >> 5 ) & 0x3F;
|
timeParts.tm_min = (t >> 5) & 0x3F;
|
||||||
timeParts.tm_sec = ( t & 0x1F ) << 1;
|
timeParts.tm_sec = (t & 0x1F) << 1;
|
||||||
|
|
||||||
timeParts.tm_mday = d & 0x1F;
|
timeParts.tm_mday = d & 0x1F;
|
||||||
timeParts.tm_mon = ( ( d >> 5 ) & 0x0F ) - 1;
|
timeParts.tm_mon = ((d >> 5) & 0x0F) - 1;
|
||||||
timeParts.tm_year = ( d >> 9 ) + 80;
|
timeParts.tm_year = (d >> 9) + 80;
|
||||||
|
|
||||||
timeParts.tm_isdst = 0;
|
timeParts.tm_isdst = 0;
|
||||||
|
|
||||||
return mktime( &timeParts );
|
return mktime(&timeParts);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FILETIME_H
|
#ifndef __FILETIME_H
|
||||||
#define __FILETIME_H
|
#define __FILETIME_H
|
||||||
@ -32,10 +32,9 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
uint16_t _FAT_filetime_getTimeFromRTC ( void );
|
uint16_t _FAT_filetime_getTimeFromRTC(void);
|
||||||
uint16_t _FAT_filetime_getDateFromRTC ( 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
|
#endif // _FILETIME_H
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/iosupport.h>
|
#include <sys/iosupport.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -38,178 +38,153 @@
|
|||||||
#include "mem_allocate.h"
|
#include "mem_allocate.h"
|
||||||
#include "disc_fat.h"
|
#include "disc_fat.h"
|
||||||
|
|
||||||
static const devoptab_t dotab_fat =
|
static const devoptab_t dotab_fat = { "fat", sizeof(FILE_STRUCT), _FAT_open_r, _FAT_close_r, _FAT_write_r, _FAT_read_r,
|
||||||
{
|
_FAT_seek_r, _FAT_fstat_r, _FAT_stat_r, _FAT_link_r, _FAT_unlink_r, _FAT_chdir_r, _FAT_rename_r, _FAT_mkdir_r,
|
||||||
"fat",
|
sizeof(DIR_STATE_STRUCT), _FAT_diropen_r, _FAT_dirreset_r, _FAT_dirnext_r, _FAT_dirclose_r, _FAT_statvfs_r,
|
||||||
sizeof ( FILE_STRUCT ),
|
_FAT_ftruncate_r, _FAT_fsync_r, NULL /* Device data */
|
||||||
_FAT_open_r,
|
|
||||||
_FAT_close_r,
|
|
||||||
_FAT_write_r,
|
|
||||||
_FAT_read_r,
|
|
||||||
_FAT_seek_r,
|
|
||||||
_FAT_fstat_r,
|
|
||||||
_FAT_stat_r,
|
|
||||||
_FAT_link_r,
|
|
||||||
_FAT_unlink_r,
|
|
||||||
_FAT_chdir_r,
|
|
||||||
_FAT_rename_r,
|
|
||||||
_FAT_mkdir_r,
|
|
||||||
sizeof ( DIR_STATE_STRUCT ),
|
|
||||||
_FAT_diropen_r,
|
|
||||||
_FAT_dirreset_r,
|
|
||||||
_FAT_dirnext_r,
|
|
||||||
_FAT_dirclose_r,
|
|
||||||
_FAT_statvfs_r,
|
|
||||||
_FAT_ftruncate_r,
|
|
||||||
_FAT_fsync_r,
|
|
||||||
NULL /* Device data */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage )
|
bool fatMount(const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize,
|
||||||
|
uint32_t SectorsPerPage)
|
||||||
{
|
{
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
devoptab_t* devops;
|
devoptab_t* devops;
|
||||||
char* nameCopy;
|
char* nameCopy;
|
||||||
|
|
||||||
if ( !interface->startup() )
|
if (!interface->startup()) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( !interface->isInserted() )
|
if (!interface->isInserted())
|
||||||
{
|
{
|
||||||
interface->shutdown();
|
interface->shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
devops = _FAT_mem_allocate ( sizeof( devoptab_t ) + strlen( name ) + 1 );
|
devops = _FAT_mem_allocate(sizeof(devoptab_t) + strlen(name) + 1);
|
||||||
if ( !devops )
|
if (!devops)
|
||||||
{
|
{
|
||||||
interface->shutdown();
|
interface->shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Use the space allocated at the end of the devoptab struct for storing the name
|
// 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
|
// Initialize the file system
|
||||||
partition = _FAT_partition_constructor ( interface, cacheSize, SectorsPerPage, startSector );
|
partition = _FAT_partition_constructor(interface, cacheSize, SectorsPerPage, startSector);
|
||||||
if ( !partition )
|
if (!partition)
|
||||||
{
|
{
|
||||||
_FAT_mem_free ( devops );
|
_FAT_mem_free(devops);
|
||||||
interface->shutdown();
|
interface->shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an entry for this device to the devoptab table
|
// Add an entry for this device to the devoptab table
|
||||||
memcpy ( devops, &dotab_fat, sizeof( dotab_fat ) );
|
memcpy(devops, &dotab_fat, sizeof(dotab_fat));
|
||||||
strcpy ( nameCopy, name );
|
strcpy(nameCopy, name);
|
||||||
devops->name = nameCopy;
|
devops->name = nameCopy;
|
||||||
devops->deviceData = partition;
|
devops->deviceData = partition;
|
||||||
|
|
||||||
AddDevice ( devops );
|
AddDevice(devops);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fatMountSimple ( const char* name, const DISC_INTERFACE* interface )
|
bool fatMountSimple(const char* name, const DISC_INTERFACE* interface)
|
||||||
{
|
{
|
||||||
return fatMount ( name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE );
|
return fatMount(name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fatUnmount ( const char* name )
|
void fatUnmount(const char* name)
|
||||||
{
|
{
|
||||||
devoptab_t *devops;
|
devoptab_t *devops;
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
const DISC_INTERFACE *disc;
|
const DISC_INTERFACE *disc;
|
||||||
|
|
||||||
devops = ( devoptab_t* )GetDeviceOpTab ( name );
|
devops = (devoptab_t*) GetDeviceOpTab(name);
|
||||||
if ( !devops )
|
if (!devops)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a quick check to make sure we're dealing with a libfat controlled device
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( RemoveDevice ( name ) == -1 )
|
if (RemoveDevice(name) == -1)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
partition = ( PARTITION* )devops->deviceData;
|
partition = (PARTITION*) devops->deviceData;
|
||||||
disc = partition->disc;
|
disc = partition->disc;
|
||||||
_FAT_partition_destructor ( partition );
|
_FAT_partition_destructor(partition);
|
||||||
_FAT_mem_free ( devops );
|
_FAT_mem_free(devops);
|
||||||
disc->shutdown();
|
disc->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
|
bool fatInit(uint32_t cacheSize, bool setAsDefaultDevice)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int defaultDevice = -1;
|
int defaultDevice = -1;
|
||||||
const DISC_INTERFACE *disc;
|
const DISC_INTERFACE *disc;
|
||||||
|
|
||||||
for ( i = 0;
|
for (i = 0; _FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL; i++)
|
||||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
|
||||||
i++ )
|
|
||||||
{
|
{
|
||||||
disc = _FAT_disc_interfaces[i].getInterface();
|
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
|
// The first device to successfully mount is set as the default
|
||||||
if ( defaultDevice < 0 )
|
if (defaultDevice < 0)
|
||||||
{
|
{
|
||||||
defaultDevice = i;
|
defaultDevice = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( defaultDevice < 0 )
|
if (defaultDevice < 0)
|
||||||
{
|
{
|
||||||
// None of our devices mounted
|
// None of our devices mounted
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( setAsDefaultDevice )
|
if (setAsDefaultDevice)
|
||||||
{
|
{
|
||||||
char filePath[MAXPATHLEN * 2];
|
char filePath[MAXPATHLEN * 2];
|
||||||
strcpy ( filePath, _FAT_disc_interfaces[defaultDevice].name );
|
strcpy(filePath, _FAT_disc_interfaces[defaultDevice].name);
|
||||||
strcat ( filePath, ":/" );
|
strcat(filePath, ":/");
|
||||||
#ifdef ARGV_MAGIC
|
#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
|
// Check the app's path against each of our mounted devices, to see
|
||||||
// if we can support it. If so, change to that path.
|
// 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++)
|
||||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
|
||||||
i++ )
|
|
||||||
{
|
{
|
||||||
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
if (!strncasecmp(__system_argv->argv[0], _FAT_disc_interfaces[i].name, strlen(
|
||||||
strlen( _FAT_disc_interfaces[i].name ) ) )
|
_FAT_disc_interfaces[i].name)))
|
||||||
{
|
{
|
||||||
char *lastSlash;
|
char *lastSlash;
|
||||||
strcpy( filePath, __system_argv->argv[0] );
|
strcpy(filePath, __system_argv->argv[0]);
|
||||||
lastSlash = strrchr( filePath, '/' );
|
lastSlash = strrchr(filePath, '/');
|
||||||
|
|
||||||
if ( NULL != lastSlash )
|
if (NULL != lastSlash)
|
||||||
{
|
{
|
||||||
if ( *( lastSlash - 1 ) == ':' ) lastSlash++;
|
if (*(lastSlash - 1) == ':') lastSlash++;
|
||||||
*lastSlash = 0;
|
*lastSlash = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
chdir ( filePath );
|
chdir(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fatInitDefault ( void )
|
bool fatInitDefault(void)
|
||||||
{
|
{
|
||||||
return fatInit ( DEFAULT_CACHE_PAGES, true );
|
return fatInit(DEFAULT_CACHE_PAGES, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __LOCK_H
|
#ifndef __LOCK_H
|
||||||
#define __LOCK_H
|
#define __LOCK_H
|
||||||
@ -60,28 +60,26 @@ static inline void _FAT_unlock( mutex_t *mutex )
|
|||||||
typedef int mutex_t;
|
typedef int mutex_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void _FAT_lock_init( mutex_t *mutex )
|
static inline void _FAT_lock_init(mutex_t *mutex)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _FAT_lock_deinit( mutex_t *mutex )
|
static inline void _FAT_lock_deinit(mutex_t *mutex)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _FAT_lock( mutex_t *mutex )
|
static inline void _FAT_lock(mutex_t *mutex)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _FAT_unlock( mutex_t *mutex )
|
static inline void _FAT_unlock(mutex_t *mutex)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // USE_LWP_LOCK
|
#endif // USE_LWP_LOCK
|
||||||
|
|
||||||
|
|
||||||
#endif // _LOCK_H
|
#endif // _LOCK_H
|
||||||
|
|
||||||
|
@ -26,27 +26,27 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MEM_ALLOCATE_H_
|
#ifndef __MEM_ALLOCATE_H_
|
||||||
#define __MEM_ALLOCATE_H_
|
#define __MEM_ALLOCATE_H_
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
static inline void* _FAT_mem_allocate ( size_t size )
|
static inline void* _FAT_mem_allocate(size_t size)
|
||||||
{
|
{
|
||||||
return malloc ( 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 )
|
static inline void _FAT_mem_free(void* mem)
|
||||||
{
|
{
|
||||||
free ( mem );
|
free(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _MEM_ALLOCATE_H
|
#endif // _MEM_ALLOCATE_H
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "partition.h"
|
#include "partition.h"
|
||||||
#include "bit_ops.h"
|
#include "bit_ops.h"
|
||||||
@ -41,19 +41,18 @@
|
|||||||
sec_t _FAT_startSector;
|
sec_t _FAT_startSector;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This device name, as known by devkitPro toolchains
|
This device name, as known by devkitPro toolchains
|
||||||
*/
|
*/
|
||||||
const char* DEVICE_NAME = "fat";
|
const char* DEVICE_NAME = "fat";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Data offsets
|
Data offsets
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// BIOS Parameter Block offsets
|
// BIOS Parameter Block offsets
|
||||||
enum BPB
|
enum BPB
|
||||||
{
|
{
|
||||||
BPB_jmpBoot = 0x00,
|
BPB_jmpBoot = 0x00, BPB_OEMName = 0x03,
|
||||||
BPB_OEMName = 0x03,
|
|
||||||
// BIOS Parameter Block
|
// BIOS Parameter Block
|
||||||
BPB_bytesPerSector = 0x0B,
|
BPB_bytesPerSector = 0x0B,
|
||||||
BPB_sectorsPerCluster = 0x0D,
|
BPB_sectorsPerCluster = 0x0D,
|
||||||
@ -96,67 +95,66 @@ enum BPB
|
|||||||
BPB_bootSig_AA = 0x1FF
|
BPB_bootSig_AA = 0x1FF
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char FAT_SIG[3] = {'F', 'A', 'T'};
|
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 part_table[16 * 4];
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
uint8_t sectorBuffer[BYTES_PER_READ] = { 0 };
|
||||||
|
|
||||||
// Read first sector of disc
|
// Read first sector of disc
|
||||||
if ( !_FAT_disc_readSectors ( disc, 0, 1, sectorBuffer ) )
|
if (!_FAT_disc_readSectors(disc, 0, 1, sectorBuffer))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy( part_table, sectorBuffer + 0x1BE, 16*4 );
|
memcpy(part_table, sectorBuffer + 0x1BE, 16 * 4);
|
||||||
ptr = part_table;
|
ptr = part_table;
|
||||||
|
|
||||||
for ( i = 0; i < 4; i++, ptr += 16 )
|
for (i = 0; i < 4; i++, ptr += 16)
|
||||||
{
|
{
|
||||||
sec_t part_lba = u8array_to_u32( ptr, 0x8 );
|
sec_t part_lba = u8array_to_u32(ptr, 0x8);
|
||||||
|
|
||||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer
|
||||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
{
|
{
|
||||||
return part_lba;
|
return part_lba;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ptr[4] == 0 ) continue;
|
if (ptr[4] == 0) continue;
|
||||||
|
|
||||||
if ( ptr[4] == 0x0F )
|
if (ptr[4] == 0x0F)
|
||||||
{
|
{
|
||||||
sec_t part_lba2 = part_lba;
|
sec_t part_lba2 = part_lba;
|
||||||
sec_t next_lba2 = 0;
|
sec_t next_lba2 = 0;
|
||||||
int n;
|
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 ) ;
|
part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6);
|
||||||
next_lba2 = u8array_to_u32( sectorBuffer, 0x1D6 );
|
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 ) ) ||
|
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer
|
||||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
{
|
{
|
||||||
return part_lba2;
|
return part_lba2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( next_lba2 == 0 ) break;
|
if (next_lba2 == 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( !_FAT_disc_readSectors ( disc, part_lba, 1, sectorBuffer ) ) return 0;
|
if (!_FAT_disc_readSectors(disc, part_lba, 1, sectorBuffer)) return 0;
|
||||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer
|
||||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
{
|
{
|
||||||
return part_lba;
|
return part_lba;
|
||||||
}
|
}
|
||||||
@ -165,62 +163,64 @@ sec_t FindFirstValidPartition( const DISC_INTERFACE* disc )
|
|||||||
return 0;
|
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;
|
PARTITION* partition;
|
||||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
uint8_t sectorBuffer[BYTES_PER_READ] = { 0 };
|
||||||
|
|
||||||
// Read first sector of disc
|
// Read first sector of disc
|
||||||
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
if (!_FAT_disc_readSectors(disc, startSector, 1, sectorBuffer))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure it is a valid MBR or boot sector
|
// 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( startSector != 0 )
|
if (startSector != 0)
|
||||||
{
|
{
|
||||||
// We're told where to start the partition, so just accept it
|
// 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
|
// Check if there is a FAT string, which indicates this is a boot sector
|
||||||
startSector = 0;
|
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
|
// Check for FAT32
|
||||||
startSector = 0;
|
startSector = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
startSector = FindFirstValidPartition( disc );
|
startSector = FindFirstValidPartition(disc);
|
||||||
if ( !_FAT_disc_readSectors ( disc, startSector, 1, sectorBuffer ) )
|
if (!_FAT_disc_readSectors(disc, startSector, 1, sectorBuffer))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now verify that this is indeed a FAT partition
|
// Now verify that this is indeed a FAT partition
|
||||||
if ( memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) &&
|
if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) && memcmp(sectorBuffer
|
||||||
memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check again for the last two cases to make sure that we really have a FAT filesystem here
|
// check again for the last two cases to make sure that we really have a FAT filesystem here
|
||||||
// and won't corrupt any data
|
// 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
partition = ( PARTITION* ) _FAT_mem_allocate ( sizeof( PARTITION ) );
|
partition = (PARTITION*) _FAT_mem_allocate(sizeof(PARTITION));
|
||||||
if ( partition == NULL )
|
if (partition == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -228,45 +228,48 @@ PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cac
|
|||||||
_FAT_startSector = startSector;
|
_FAT_startSector = startSector;
|
||||||
|
|
||||||
// Init the partition lock
|
// Init the partition lock
|
||||||
_FAT_lock_init( &partition->lock );
|
_FAT_lock_init(&partition->lock);
|
||||||
|
|
||||||
// Set partition's disc interface
|
// Set partition's disc interface
|
||||||
partition->disc = disc;
|
partition->disc = disc;
|
||||||
|
|
||||||
// Store required information about the file system
|
// Store required information about the file system
|
||||||
partition->fat.sectorsPerFat = u8array_to_u16( sectorBuffer, BPB_sectorsPerFAT );
|
partition->fat.sectorsPerFat = u8array_to_u16(sectorBuffer, BPB_sectorsPerFAT);
|
||||||
if ( partition->fat.sectorsPerFat == 0 )
|
if (partition->fat.sectorsPerFat == 0)
|
||||||
{
|
{
|
||||||
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32 );
|
partition->fat.sectorsPerFat = u8array_to_u32(sectorBuffer, BPB_FAT32_sectorsPerFAT32);
|
||||||
}
|
}
|
||||||
|
|
||||||
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall );
|
partition->numberOfSectors = u8array_to_u16(sectorBuffer, BPB_numSectorsSmall);
|
||||||
if ( partition->numberOfSectors == 0 )
|
if (partition->numberOfSectors == 0)
|
||||||
{
|
{
|
||||||
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors );
|
partition->numberOfSectors = u8array_to_u32(sectorBuffer, BPB_numSectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
partition->bytesPerSector = BYTES_PER_READ; // Sector size is redefined to be 512 bytes
|
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->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 +
|
partition->dataStart = partition->rootDirStart + ((u8array_to_u16(sectorBuffer, BPB_rootEntries)
|
||||||
( ( u8array_to_u16( sectorBuffer, BPB_rootEntries ) * DIR_ENTRY_DATA_SIZE ) / partition->bytesPerSector );
|
* 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
|
// 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.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
||||||
partition->fat.firstFree = CLUSTER_FIRST;
|
partition->fat.firstFree = CLUSTER_FIRST;
|
||||||
|
|
||||||
if ( clusterCount < CLUSTERS_PER_FAT12 )
|
if (clusterCount < CLUSTERS_PER_FAT12)
|
||||||
{
|
{
|
||||||
partition->filesysType = FS_FAT12; // FAT12 volume
|
partition->filesysType = FS_FAT12; // FAT12 volume
|
||||||
}
|
}
|
||||||
else if ( clusterCount < CLUSTERS_PER_FAT16 )
|
else if (clusterCount < CLUSTERS_PER_FAT16)
|
||||||
{
|
{
|
||||||
partition->filesysType = FS_FAT16; // FAT16 volume
|
partition->filesysType = FS_FAT16; // FAT16 volume
|
||||||
}
|
}
|
||||||
@ -275,30 +278,32 @@ PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cac
|
|||||||
partition->filesysType = FS_FAT32; // FAT32 volume
|
partition->filesysType = FS_FAT32; // FAT32 volume
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( partition->filesysType != FS_FAT32 )
|
if (partition->filesysType != FS_FAT32)
|
||||||
{
|
{
|
||||||
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set up for the FAT32 way
|
// 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
|
// Check if FAT mirroring is enabled
|
||||||
if ( !( sectorBuffer[BPB_FAT32_extFlags] & 0x80 ) )
|
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80))
|
||||||
{
|
{
|
||||||
// Use the active FAT
|
// 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
|
// 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
|
// Set current directory to the root
|
||||||
partition->cwdCluster = partition->rootDirCluster;
|
partition->cwdCluster = partition->rootDirCluster;
|
||||||
|
|
||||||
// Check if this disc is writable, and set the readOnly property appropriately
|
// 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
|
// There are currently no open files on this partition
|
||||||
partition->openFileCount = 0;
|
partition->openFileCount = 0;
|
||||||
@ -307,41 +312,41 @@ PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cac
|
|||||||
return partition;
|
return partition;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _FAT_partition_destructor ( PARTITION* partition )
|
void _FAT_partition_destructor(PARTITION* partition)
|
||||||
{
|
{
|
||||||
FILE_STRUCT* nextFile;
|
FILE_STRUCT* nextFile;
|
||||||
|
|
||||||
_FAT_lock( &partition->lock );
|
_FAT_lock(&partition->lock);
|
||||||
|
|
||||||
// Synchronize open files
|
// Synchronize open files
|
||||||
nextFile = partition->firstOpenFile;
|
nextFile = partition->firstOpenFile;
|
||||||
while ( nextFile )
|
while (nextFile)
|
||||||
{
|
{
|
||||||
_FAT_syncToDisc ( nextFile );
|
_FAT_syncToDisc(nextFile);
|
||||||
nextFile = nextFile->nextOpenFile;
|
nextFile = nextFile->nextOpenFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free memory used by the cache, writing it to disc at the same time
|
// 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
|
// Unlock the partition and destroy the lock
|
||||||
_FAT_unlock( &partition->lock );
|
_FAT_unlock(&partition->lock);
|
||||||
_FAT_lock_deinit( &partition->lock );
|
_FAT_lock_deinit(&partition->lock);
|
||||||
|
|
||||||
// Free memory used by the partition
|
// 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;
|
const devoptab_t *devops;
|
||||||
|
|
||||||
devops = GetDeviceOpTab ( path );
|
devops = GetDeviceOpTab(path);
|
||||||
|
|
||||||
if ( !devops )
|
if (!devops)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ( PARTITION* )devops->deviceData;
|
return (PARTITION*) devops->deviceData;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PARTITION_H
|
#ifndef __PARTITION_H
|
||||||
#define __PARTITION_H
|
#define __PARTITION_H
|
||||||
@ -38,7 +38,10 @@
|
|||||||
extern const char* DEVICE_NAME;
|
extern const char* DEVICE_NAME;
|
||||||
|
|
||||||
// Filesystem type
|
// Filesystem type
|
||||||
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
typedef enum
|
||||||
|
{
|
||||||
|
FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32
|
||||||
|
} FS_TYPE;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -72,19 +75,20 @@ typedef struct
|
|||||||
} PARTITION;
|
} PARTITION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Mount the supplied device and return a pointer to the struct necessary to use it
|
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.
|
Dismount the device and free all structures used.
|
||||||
Will also attempt to synchronise all open files to disc.
|
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.
|
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
|
#endif // _PARTITION_H
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,6 @@
|
|||||||
#define NTFS_FIND_USER(map,usid) ntfs_find_user(map,usid)
|
#define NTFS_FIND_USER(map,usid) ntfs_find_user(map,usid)
|
||||||
#define NTFS_FIND_GROUP(map,gsid) ntfs_find_group(map,gsid)
|
#define NTFS_FIND_GROUP(map,gsid) ntfs_find_group(map,gsid)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Matching of ntfs permissions to Linux permissions
|
* Matching of ntfs permissions to Linux permissions
|
||||||
* these constants are adapted to endianness
|
* these constants are adapted to endianness
|
||||||
@ -64,7 +63,7 @@
|
|||||||
* when checking, check one is present
|
* 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_READ (FILE_READ_DATA)
|
||||||
#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
||||||
@ -75,8 +74,8 @@
|
|||||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||||
#define DIR_EXEC (FILE_TRAVERSE)
|
#define DIR_EXEC (FILE_TRAVERSE)
|
||||||
|
|
||||||
/* flags tested for meaning exec, write or read */
|
/* flags tested for meaning exec, write or read */
|
||||||
/* tests for write allow for interpretation of a sticky bit */
|
/* tests for write allow for interpretation of a sticky bit */
|
||||||
|
|
||||||
#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ)
|
#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ)
|
||||||
#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)
|
#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)
|
||||||
@ -85,19 +84,19 @@
|
|||||||
#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE)
|
#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE)
|
||||||
#define DIR_GEXEC (FILE_TRAVERSE | GENERIC_EXECUTE)
|
#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 \
|
#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \
|
||||||
| SYNCHRONIZE \
|
| SYNCHRONIZE \
|
||||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
||||||
| FILE_READ_EA | FILE_WRITE_EA)
|
| FILE_READ_EA | FILE_WRITE_EA)
|
||||||
|
|
||||||
/* standard world rights */
|
/* standard world rights */
|
||||||
|
|
||||||
#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \
|
#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \
|
||||||
| SYNCHRONIZE)
|
| SYNCHRONIZE)
|
||||||
|
|
||||||
/* inheritance flags for files and directories */
|
/* inheritance flags for files and directories */
|
||||||
|
|
||||||
#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE
|
#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE
|
||||||
#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
|
#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
|
||||||
@ -122,7 +121,8 @@ typedef char BIGSID[40];
|
|||||||
* (private to this module)
|
* (private to this module)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct MAPLIST {
|
struct MAPLIST
|
||||||
|
{
|
||||||
struct MAPLIST *next;
|
struct MAPLIST *next;
|
||||||
char *uidstr; /* uid text from the same record */
|
char *uidstr; /* uid text from the same record */
|
||||||
char *gidstr; /* gid text from the same record */
|
char *gidstr; /* gid text from the same record */
|
||||||
@ -150,14 +150,11 @@ 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);
|
int ntfs_sid_size(const SID * sid);
|
||||||
unsigned int ntfs_attr_size(const char *attr);
|
unsigned int ntfs_attr_size(const char *attr);
|
||||||
|
|
||||||
const SID *ntfs_find_usid(const struct MAPPING *usermapping,
|
const SID *ntfs_find_usid(const struct MAPPING *usermapping, uid_t uid, SID *pdefsid);
|
||||||
uid_t uid, SID *pdefsid);
|
const SID *ntfs_find_gsid(const struct MAPPING *groupmapping, gid_t gid, 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);
|
uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid);
|
||||||
gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
||||||
const SID *ntfs_acl_owner(const char *secattr);
|
const SID *ntfs_acl_owner(const char *secattr);
|
||||||
@ -184,12 +181,9 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
|||||||
|
|
||||||
#endif /* POSIXACLS */
|
#endif /* POSIXACLS */
|
||||||
|
|
||||||
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl, const SID *usid, const SID *gsid, BOOL fordir);
|
||||||
const SID *usid, const SID *gsid, BOOL fordir);
|
int ntfs_build_permissions(const char *securattr, const SID *usid, const SID *gsid, BOOL isdir);
|
||||||
int ntfs_build_permissions(const char *securattr,
|
char *ntfs_build_descr(mode_t mode, int isdir, const SID * usid, const SID * gsid);
|
||||||
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 MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid);
|
||||||
struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem);
|
struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem);
|
||||||
struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem);
|
struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -49,12 +49,10 @@ extern ntfschar TXF_DATA[10];
|
|||||||
*
|
*
|
||||||
* TODO: Describe them.
|
* TODO: Describe them.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||||
LCN_RL_NOT_MAPPED = -2,
|
LCN_RL_NOT_MAPPED = -2, LCN_ENOENT = -3, LCN_EINVAL = -4, LCN_EIO = -5,
|
||||||
LCN_ENOENT = -3,
|
|
||||||
LCN_EINVAL = -4,
|
|
||||||
LCN_EIO = -5,
|
|
||||||
} ntfs_lcn_special_values;
|
} ntfs_lcn_special_values;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,7 +73,8 @@ typedef enum {
|
|||||||
* any modification of the search context, to automagically get the next
|
* any modification of the search context, to automagically get the next
|
||||||
* matching attribute.
|
* matching attribute.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_attr_search_ctx {
|
struct _ntfs_attr_search_ctx
|
||||||
|
{
|
||||||
MFT_RECORD *mrec;
|
MFT_RECORD *mrec;
|
||||||
ATTR_RECORD *attr;
|
ATTR_RECORD *attr;
|
||||||
BOOL is_first;
|
BOOL is_first;
|
||||||
@ -87,19 +86,15 @@ struct _ntfs_attr_search_ctx {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern void ntfs_attr_reinit_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,
|
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec);
|
||||||
MFT_RECORD *mrec);
|
|
||||||
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
|
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 u32 name_len, const IGNORE_CASE_BOOL ic,
|
const VCN lowest_vcn, const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx);
|
||||||
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
|
||||||
ntfs_attr_search_ctx *ctx);
|
|
||||||
|
|
||||||
extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
|
extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
|
||||||
|
|
||||||
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, const ATTR_TYPES type);
|
||||||
const ATTR_TYPES type);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
||||||
@ -128,8 +123,7 @@ extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
|||||||
*/
|
*/
|
||||||
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,
|
return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx);
|
||||||
NULL, 0, ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,7 +168,8 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
|
|||||||
* @state contains NTFS attribute specific flags describing this attribute
|
* @state contains NTFS attribute specific flags describing this attribute
|
||||||
* structure. See ntfs_attr_state_bits above.
|
* structure. See ntfs_attr_state_bits above.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_attr {
|
struct _ntfs_attr
|
||||||
|
{
|
||||||
runlist_element *rl;
|
runlist_element *rl;
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
ATTR_TYPES type;
|
ATTR_TYPES type;
|
||||||
@ -196,12 +191,14 @@ struct _ntfs_attr {
|
|||||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
||||||
* structure
|
* structure
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NA_Initialized, /* 1: structure is initialized. */
|
NA_Initialized, /* 1: structure is initialized. */
|
||||||
NA_NonResident, /* 1: Attribute is not resident. */
|
NA_NonResident, /* 1: Attribute is not resident. */
|
||||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||||
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
||||||
NA_ComprClosing, /* 1: Compressed attribute is being closed */
|
NA_ComprClosing,
|
||||||
|
/* 1: Compressed attribute is being closed */
|
||||||
} ntfs_attr_state_bits;
|
} ntfs_attr_state_bits;
|
||||||
|
|
||||||
#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
|
#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
|
||||||
@ -243,7 +240,8 @@ GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
|||||||
*
|
*
|
||||||
* For convenience. Used in the attr structure.
|
* For convenience. Used in the attr structure.
|
||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union
|
||||||
|
{
|
||||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||||
a_val without specifying any of the below. */
|
a_val without specifying any of the below. */
|
||||||
STANDARD_INFORMATION std_inf;
|
STANDARD_INFORMATION std_inf;
|
||||||
@ -265,32 +263,23 @@ typedef union {
|
|||||||
EFS_ATTR_HEADER efs;
|
EFS_ATTR_HEADER efs;
|
||||||
} attr_val;
|
} 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 ATTR_FLAGS data_flags, const BOOL encrypted,
|
const BOOL sparse, const s64 allocated_size, const s64 data_size, const s64 initialized_size,
|
||||||
const BOOL sparse,
|
const s64 compressed_size, const u8 compression_unit);
|
||||||
const s64 allocated_size, const s64 data_size,
|
|
||||||
const s64 initialized_size, const s64 compressed_size,
|
|
||||||
const u8 compression_unit);
|
|
||||||
|
|
||||||
/* warning : in the following "name" has to be freeable */
|
/* warning : in the following "name" has to be freeable */
|
||||||
/* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */
|
/* 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,
|
extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len);
|
||||||
ntfschar *name, u32 name_len);
|
|
||||||
extern void ntfs_attr_close(ntfs_attr *na);
|
extern void ntfs_attr_close(ntfs_attr *na);
|
||||||
|
|
||||||
extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
|
extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b);
|
||||||
void *b);
|
extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const 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 int ntfs_attr_pclose(ntfs_attr *na);
|
||||||
|
|
||||||
extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
|
extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len, s64 *data_size);
|
||||||
ntfschar *name, u32 name_len, s64 *data_size);
|
|
||||||
|
|
||||||
extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos,
|
extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, const u32 bk_size, void *dst);
|
||||||
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_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_runlist(ntfs_attr *na, VCN vcn);
|
||||||
extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
||||||
@ -298,33 +287,26 @@ extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
|||||||
extern LCN ntfs_attr_vcn_to_lcn(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 runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
|
||||||
|
|
||||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, const s64 size);
|
||||||
const ATTR_TYPES type, const s64 size);
|
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type);
|
||||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
int ntfs_attr_make_non_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx);
|
||||||
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);
|
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_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,
|
||||||
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
u32 size, ATTR_FLAGS flags);
|
||||||
ATTR_FLAGS flags);
|
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, ntfschar *name, u8 name_len,
|
||||||
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
VCN lowest_vcn, int dataruns_size, ATTR_FLAGS flags);
|
||||||
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
|
||||||
ATTR_FLAGS flags);
|
|
||||||
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
|
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
|
||||||
|
|
||||||
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, ntfschar *name, u8 name_len, u8 *val, s64 size);
|
||||||
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,
|
||||||
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
|
ATTR_FLAGS mask);
|
||||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask);
|
|
||||||
extern int ntfs_attr_rm(ntfs_attr *na);
|
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,
|
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, const u32 new_size);
|
||||||
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_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_away(ntfs_attr_search_ctx *ctx, int extra);
|
||||||
@ -360,15 +342,12 @@ extern s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a);
|
|||||||
* then nothing was read due to a zero-length attribute value, otherwise
|
* then nothing was read due to a zero-length attribute value, otherwise
|
||||||
* errno describes the error.
|
* errno describes the error.
|
||||||
*/
|
*/
|
||||||
extern s64 ntfs_get_attribute_value(const ntfs_volume *vol,
|
extern s64 ntfs_get_attribute_value(const ntfs_volume *vol, const ATTR_RECORD *a, u8 *b);
|
||||||
const ATTR_RECORD *a, u8 *b);
|
|
||||||
|
|
||||||
extern void ntfs_attr_name_free(char **name);
|
extern void ntfs_attr_name_free(char **name);
|
||||||
extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len);
|
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,
|
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len);
|
||||||
ntfschar *name, u32 name_len);
|
extern int ntfs_attr_remove(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 s64 ntfs_attr_get_free_bits(ntfs_attr *na);
|
||||||
|
|
||||||
#endif /* defined _NTFS_ATTRIB_H */
|
#endif /* defined _NTFS_ATTRIB_H */
|
||||||
|
@ -65,13 +65,15 @@
|
|||||||
|
|
||||||
#define STANDARD_COMPRESSION_UNIT 4
|
#define STANDARD_COMPRESSION_UNIT 4
|
||||||
|
|
||||||
ntfschar AT_UNNAMED[] = { const_cpu_to_le16( '\0' ) };
|
ntfschar AT_UNNAMED[] =
|
||||||
ntfschar STREAM_SDS[] = { const_cpu_to_le16( '$' ),
|
{ const_cpu_to_le16( '\0' )};
|
||||||
|
ntfschar STREAM_SDS[] =
|
||||||
|
{ const_cpu_to_le16( '$' ),
|
||||||
const_cpu_to_le16( 'S' ),
|
const_cpu_to_le16( 'S' ),
|
||||||
const_cpu_to_le16( 'D' ),
|
const_cpu_to_le16( 'D' ),
|
||||||
const_cpu_to_le16( 'S' ),
|
const_cpu_to_le16( 'S' ),
|
||||||
const_cpu_to_le16( '\0' )
|
const_cpu_to_le16( '\0' )
|
||||||
};
|
};
|
||||||
|
|
||||||
static int NAttrFlag( ntfs_attr *na, FILE_ATTR_FLAGS flag )
|
static int NAttrFlag( ntfs_attr *na, FILE_ATTR_FLAGS flag )
|
||||||
{
|
{
|
||||||
@ -527,13 +529,13 @@ ntfs_attr *ntfs_attr_open( ntfs_inode *ni, const ATTR_TYPES type,
|
|||||||
cs ? ( l + 7 ) & ~7 : 0, 0 );
|
cs ? ( l + 7 ) & ~7 : 0, 0 );
|
||||||
}
|
}
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
out:
|
out:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave( "\n" );
|
||||||
return na;
|
return na;
|
||||||
|
|
||||||
put_err_out:
|
put_err_out:
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
err_out:
|
err_out:
|
||||||
free( newname );
|
free( newname );
|
||||||
free( na );
|
free( na );
|
||||||
na = NULL;
|
na = NULL;
|
||||||
@ -712,9 +714,9 @@ int ntfs_attr_map_whole_runlist( ntfs_attr *na )
|
|||||||
}
|
}
|
||||||
if ( errno == ENOENT )
|
if ( errno == ENOENT )
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err_out:
|
err_out:
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
out:
|
out:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave( "\n" );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -750,7 +752,7 @@ LCN ntfs_attr_vcn_to_lcn( ntfs_attr *na, const VCN vcn )
|
|||||||
|
|
||||||
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x.\n", ( unsigned long
|
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x.\n", ( unsigned long
|
||||||
long )na->ni->mft_no, na->type );
|
long )na->ni->mft_no, na->type );
|
||||||
retry:
|
retry:
|
||||||
/* Convert vcn to lcn. If that fails map the runlist and retry once. */
|
/* Convert vcn to lcn. If that fails map the runlist and retry once. */
|
||||||
lcn = ntfs_rl_vcn_to_lcn( na->rl, vcn );
|
lcn = ntfs_rl_vcn_to_lcn( na->rl, vcn );
|
||||||
if ( lcn >= 0 )
|
if ( lcn >= 0 )
|
||||||
@ -805,7 +807,7 @@ runlist_element *ntfs_attr_find_vcn( ntfs_attr *na, const VCN vcn )
|
|||||||
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x, vcn %llx\n",
|
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x, vcn %llx\n",
|
||||||
( unsigned long long )na->ni->mft_no, na->type,
|
( unsigned long long )na->ni->mft_no, na->type,
|
||||||
( long long )vcn );
|
( long long )vcn );
|
||||||
retry:
|
retry:
|
||||||
rl = na->rl;
|
rl = na->rl;
|
||||||
if ( !rl )
|
if ( !rl )
|
||||||
goto map_rl;
|
goto map_rl;
|
||||||
@ -836,7 +838,7 @@ retry:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
map_rl:
|
map_rl:
|
||||||
/* The @vcn is in an unmapped region, map the runlist and retry. */
|
/* The @vcn is in an unmapped region, map the runlist and retry. */
|
||||||
if ( !is_retry && !ntfs_attr_map_runlist( na, vcn ) )
|
if ( !is_retry && !ntfs_attr_map_runlist( na, vcn ) )
|
||||||
{
|
{
|
||||||
@ -854,14 +856,13 @@ map_rl:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_attr_pread_i - see description at ntfs_attr_pread()
|
* ntfs_attr_pread_i - see description at ntfs_attr_pread()
|
||||||
*/
|
*/
|
||||||
static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
static s64 ntfs_attr_getfragments_i(ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
||||||
_ntfs_frag_append_t append_fragment, void *callback_data )
|
_ntfs_frag_append_t append_fragment, void *callback_data)
|
||||||
{
|
{
|
||||||
u64 b = offset;
|
u64 b = offset;
|
||||||
s64 br, to_read, ofs, total, total2, max_read, max_init;
|
s64 br, to_read, ofs, total, total2, max_read, max_init;
|
||||||
@ -871,7 +872,7 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
|
|
||||||
/* Sanity checking arguments is done in ntfs_attr_pread(). */
|
/* Sanity checking arguments is done in ntfs_attr_pread(). */
|
||||||
|
|
||||||
if ( ( na->data_flags & ATTR_COMPRESSION_MASK ) && NAttrNonResident( na ) )
|
if ((na->data_flags & ATTR_COMPRESSION_MASK) && NAttrNonResident( na ))
|
||||||
{
|
{
|
||||||
//return -1; // no compressed files
|
//return -1; // no compressed files
|
||||||
return -31;
|
return -31;
|
||||||
@ -892,15 +893,14 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
* However, allow if mounted with efs_raw option
|
* However, allow if mounted with efs_raw option
|
||||||
*/
|
*/
|
||||||
vol = na->ni->vol;
|
vol = na->ni->vol;
|
||||||
if ( !vol->efs_raw && NAttrEncrypted( na ) && NAttrNonResident( na ) )
|
if (!vol->efs_raw && NAttrEncrypted(na) && NAttrNonResident( na ))
|
||||||
{
|
{
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
//return -1;
|
//return -1;
|
||||||
return -32;
|
return -32;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !count )
|
if (!count) return 0;
|
||||||
return 0;
|
|
||||||
/*
|
/*
|
||||||
* Truncate reads beyond end of attribute,
|
* Truncate reads beyond end of attribute,
|
||||||
* but round to next 512 byte boundary for encrypted
|
* but round to next 512 byte boundary for encrypted
|
||||||
@ -908,27 +908,24 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
*/
|
*/
|
||||||
max_read = na->data_size;
|
max_read = na->data_size;
|
||||||
max_init = na->initialized_size;
|
max_init = na->initialized_size;
|
||||||
if ( na->ni->vol->efs_raw
|
if (na->ni->vol->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) && NAttrNonResident( na ))
|
||||||
&& ( na->data_flags & ATTR_IS_ENCRYPTED )
|
|
||||||
&& NAttrNonResident( na ) )
|
|
||||||
{
|
{
|
||||||
if ( na->data_size != na->initialized_size )
|
if (na->data_size != na->initialized_size)
|
||||||
{
|
{
|
||||||
ntfs_log_error( "uninitialized encrypted file not supported\n" );
|
ntfs_log_error( "uninitialized encrypted file not supported\n" );
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
//return -1;
|
//return -1;
|
||||||
return -33;
|
return -33;
|
||||||
}
|
}
|
||||||
max_init = max_read = ( ( na->data_size + 511 ) & ~511 ) + 2;
|
max_init = max_read = ((na->data_size + 511) & ~511) + 2;
|
||||||
}
|
}
|
||||||
if ( pos + count > max_read )
|
if (pos + count > max_read)
|
||||||
{
|
{
|
||||||
if ( pos >= max_read )
|
if (pos >= max_read) return 0;
|
||||||
return 0;
|
|
||||||
count = max_read - pos;
|
count = max_read - pos;
|
||||||
}
|
}
|
||||||
/* If it is a resident attribute, get the value from the mft record. */
|
/* If it is a resident attribute, get the value from the mft record. */
|
||||||
if ( !NAttrNonResident( na ) )
|
if (!NAttrNonResident( na ))
|
||||||
{
|
{
|
||||||
return -34; // No resident files
|
return -34; // No resident files
|
||||||
/*
|
/*
|
||||||
@ -959,9 +956,9 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
}
|
}
|
||||||
total = total2 = 0;
|
total = total2 = 0;
|
||||||
/* Zero out reads beyond initialized size. */
|
/* Zero out reads beyond initialized size. */
|
||||||
if ( pos + count > max_init )
|
if (pos + count > max_init)
|
||||||
{
|
{
|
||||||
if ( pos >= max_init )
|
if (pos >= max_init)
|
||||||
{
|
{
|
||||||
//memset(b, 0, count);
|
//memset(b, 0, count);
|
||||||
return count;
|
return count;
|
||||||
@ -976,9 +973,7 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
* the number of padding bytes so original size can be
|
* the number of padding bytes so original size can be
|
||||||
* restored
|
* restored
|
||||||
*/
|
*/
|
||||||
if ( na->ni->vol->efs_raw &&
|
if (na->ni->vol->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) && ((pos + count) > max_init - 2))
|
||||||
( na->data_flags & ATTR_IS_ENCRYPTED ) &&
|
|
||||||
( ( pos + count ) > max_init - 2 ) )
|
|
||||||
{
|
{
|
||||||
return -35; //No encrypted files
|
return -35; //No encrypted files
|
||||||
/*
|
/*
|
||||||
@ -1002,15 +997,15 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find the runlist element containing the vcn. */
|
/* Find the runlist element containing the vcn. */
|
||||||
rl = ntfs_attr_find_vcn( na, pos >> vol->cluster_size_bits );
|
rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
|
||||||
if ( !rl )
|
if (!rl)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If the vcn is not present it is an out of bounds read.
|
* If the vcn is not present it is an out of bounds read.
|
||||||
* However, we already truncated the read to the data_size,
|
* However, we already truncated the read to the data_size,
|
||||||
* so getting this here is an error.
|
* so getting this here is an error.
|
||||||
*/
|
*/
|
||||||
if ( errno == ENOENT )
|
if (errno == ENOENT)
|
||||||
{
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: Failed to find VCN #1", __FUNCTION__ );
|
ntfs_log_perror( "%s: Failed to find VCN #1", __FUNCTION__ );
|
||||||
@ -1023,15 +1018,15 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
* a partial final vcn is taken care of by the @count capping of read
|
* a partial final vcn is taken care of by the @count capping of read
|
||||||
* length.
|
* length.
|
||||||
*/
|
*/
|
||||||
ofs = pos - ( rl->vcn << vol->cluster_size_bits );
|
ofs = pos - (rl->vcn << vol->cluster_size_bits);
|
||||||
for ( ; count; rl++, ofs = 0 )
|
for (; count; rl++, ofs = 0)
|
||||||
{
|
{
|
||||||
if ( rl->lcn == LCN_RL_NOT_MAPPED )
|
if (rl->lcn == LCN_RL_NOT_MAPPED)
|
||||||
{
|
{
|
||||||
rl = ntfs_attr_find_vcn( na, rl->vcn );
|
rl = ntfs_attr_find_vcn(na, rl->vcn);
|
||||||
if ( !rl )
|
if (!rl)
|
||||||
{
|
{
|
||||||
if ( errno == ENOENT )
|
if (errno == ENOENT)
|
||||||
{
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: Failed to find VCN #2",
|
ntfs_log_perror( "%s: Failed to find VCN #2",
|
||||||
@ -1040,17 +1035,17 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
goto rl_err_out;
|
goto rl_err_out;
|
||||||
}
|
}
|
||||||
/* Needed for case when runs merged. */
|
/* Needed for case when runs merged. */
|
||||||
ofs = pos + total - ( rl->vcn << vol->cluster_size_bits );
|
ofs = pos + total - (rl->vcn << vol->cluster_size_bits);
|
||||||
}
|
}
|
||||||
if ( !rl->length )
|
if (!rl->length)
|
||||||
{
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: Zero run length", __FUNCTION__ );
|
ntfs_log_perror( "%s: Zero run length", __FUNCTION__ );
|
||||||
goto rl_err_out;
|
goto rl_err_out;
|
||||||
}
|
}
|
||||||
if ( rl->lcn < ( LCN )0 )
|
if (rl->lcn < (LCN) 0)
|
||||||
{
|
{
|
||||||
if ( rl->lcn != ( LCN )LCN_HOLE )
|
if (rl->lcn != (LCN) LCN_HOLE)
|
||||||
{
|
{
|
||||||
ntfs_log_perror( "%s: Bad run (%lld)",
|
ntfs_log_perror( "%s: Bad run (%lld)",
|
||||||
__FUNCTION__,
|
__FUNCTION__,
|
||||||
@ -1070,7 +1065,7 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
|||||||
/* It is a real lcn, read it into @dst. */
|
/* It is a real lcn, read it into @dst. */
|
||||||
to_read = min( count, ( rl->length << vol->cluster_size_bits ) -
|
to_read = min( count, ( rl->length << vol->cluster_size_bits ) -
|
||||||
ofs );
|
ofs );
|
||||||
retry:
|
retry:
|
||||||
ntfs_log_trace( "Reading %lld bytes from vcn %lld, lcn %lld, ofs"
|
ntfs_log_trace( "Reading %lld bytes from vcn %lld, lcn %lld, ofs"
|
||||||
" %lld.\n", ( long long )to_read, ( long long )rl->vcn,
|
" %lld.\n", ( long long )to_read, ( long long )rl->vcn,
|
||||||
( long long )rl->lcn, ( long long )ofs );
|
( long long )rl->lcn, ( long long )ofs );
|
||||||
@ -1081,46 +1076,39 @@ retry:
|
|||||||
br = to_read;
|
br = to_read;
|
||||||
// convert to sectors unit
|
// convert to sectors unit
|
||||||
u32 off_sec = b >> 9;
|
u32 off_sec = b >> 9;
|
||||||
u32 sector = ( ( rl->lcn << vol->cluster_size_bits ) + ofs ) >> 9;
|
u32 sector = ((rl->lcn << vol->cluster_size_bits) + ofs) >> 9;
|
||||||
u32 count_sec = to_read >> 9;
|
u32 count_sec = to_read >> 9;
|
||||||
int ret;
|
int ret;
|
||||||
ret = append_fragment( callback_data, off_sec, sector, count_sec );
|
ret = append_fragment(callback_data, off_sec, sector, count_sec);
|
||||||
if ( ret )
|
if (ret)
|
||||||
{
|
{
|
||||||
if ( ret < 0 ) return ret;
|
if (ret < 0) return ret;
|
||||||
return -50;
|
return -50;
|
||||||
}
|
}
|
||||||
/* If everything ok, update progress counters and continue. */
|
/* If everything ok, update progress counters and continue. */
|
||||||
if ( br > 0 )
|
if (br > 0)
|
||||||
{
|
{
|
||||||
total += br;
|
total += br;
|
||||||
count -= br;
|
count -= br;
|
||||||
b = b + br;
|
b = b + br;
|
||||||
}
|
}
|
||||||
if ( br == to_read )
|
if (br == to_read) continue;
|
||||||
continue;
|
|
||||||
/* If the syscall was interrupted, try again. */
|
/* If the syscall was interrupted, try again. */
|
||||||
if ( br == ( s64 ) - 1 && errno == EINTR )
|
if (br == (s64) -1 && errno == EINTR) goto retry;
|
||||||
goto retry;
|
if (total) return total;
|
||||||
if ( total )
|
if (!br) errno = EIO;
|
||||||
return total;
|
|
||||||
if ( !br )
|
|
||||||
errno = EIO;
|
|
||||||
ntfs_log_perror( "%s: ntfs_pread failed", __FUNCTION__ );
|
ntfs_log_perror( "%s: ntfs_pread failed", __FUNCTION__ );
|
||||||
//return -1;
|
//return -1;
|
||||||
return -38;
|
return -38;
|
||||||
}
|
}
|
||||||
/* Finally, return the number of bytes read. */
|
/* Finally, return the number of bytes read. */
|
||||||
return total + total2;
|
return total + total2;
|
||||||
rl_err_out:
|
rl_err_out: if (total) return total;
|
||||||
if ( total )
|
|
||||||
return total;
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
//return -1;
|
//return -1;
|
||||||
return -39;
|
return -39;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure
|
* ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure
|
||||||
* @na: ntfs attribute to read from
|
* @na: ntfs attribute to read from
|
||||||
@ -1140,12 +1128,12 @@ rl_err_out:
|
|||||||
* to the return code of ntfs_pread(), or to EINVAL in case of invalid
|
* to the return code of ntfs_pread(), or to EINVAL in case of invalid
|
||||||
* arguments.
|
* arguments.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_attr_getfragments( ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
s64 ntfs_attr_getfragments(ntfs_attr *na, const s64 pos, s64 count, u64 offset, _ntfs_frag_append_t append_fragment,
|
||||||
_ntfs_frag_append_t append_fragment, void *callback_data )
|
void *callback_data)
|
||||||
{
|
{
|
||||||
s64 ret;
|
s64 ret;
|
||||||
|
|
||||||
if ( !na || !na->ni || !na->ni->vol || !callback_data || pos < 0 || count < 0 )
|
if (!na || !na->ni || !na->ni->vol || !callback_data || pos < 0 || count < 0)
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: na=%p b=%p pos=%lld count=%lld",
|
ntfs_log_perror( "%s: na=%p b=%p pos=%lld count=%lld",
|
||||||
@ -1161,8 +1149,7 @@ s64 ntfs_attr_getfragments( ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
|||||||
na->type, (long long)pos, (long long)count);
|
na->type, (long long)pos, (long long)count);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = ntfs_attr_getfragments_i( na, pos, count, offset,
|
ret = ntfs_attr_getfragments_i(na, pos, count, offset, append_fragment, callback_data);
|
||||||
append_fragment, callback_data );
|
|
||||||
|
|
||||||
//ntfs_log_leave("\n");
|
//ntfs_log_leave("\n");
|
||||||
return ret;
|
return ret;
|
||||||
@ -1214,9 +1201,9 @@ static int ntfs_attr_fill_zero( ntfs_attr *na, s64 pos, s64 count )
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err_free:
|
err_free:
|
||||||
free( buf );
|
free( buf );
|
||||||
err_out:
|
err_out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1378,7 +1365,7 @@ static int ntfs_attr_fill_hole( ntfs_attr *na, s64 count, s64 *ofs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err_out:
|
err_out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1419,7 +1406,8 @@ s64 ntfs_attr_pwrite( ntfs_attr *na, const s64 pos, s64 count, const void *b )
|
|||||||
{
|
{
|
||||||
unsigned int undo_initialized_size : 1;
|
unsigned int undo_initialized_size : 1;
|
||||||
unsigned int undo_data_size : 1;
|
unsigned int undo_data_size : 1;
|
||||||
} need_to = { 0, 0 };
|
}need_to =
|
||||||
|
{ 0, 0};
|
||||||
BOOL makingnonresident = FALSE;
|
BOOL makingnonresident = FALSE;
|
||||||
BOOL wasnonresident = FALSE;
|
BOOL wasnonresident = FALSE;
|
||||||
BOOL compressed;
|
BOOL compressed;
|
||||||
@ -1751,7 +1739,7 @@ s64 ntfs_attr_pwrite( ntfs_attr *na, const s64 pos, s64 count, const void *b )
|
|||||||
|
|
||||||
/* It is a real lcn, write it to the volume. */
|
/* It is a real lcn, write it to the volume. */
|
||||||
to_write = min( count, ( rl->length << vol->cluster_size_bits ) - ofs );
|
to_write = min( count, ( rl->length << vol->cluster_size_bits ) - ofs );
|
||||||
retry:
|
retry:
|
||||||
ntfs_log_trace( "Writing %lld bytes to vcn %lld, lcn %lld, ofs "
|
ntfs_log_trace( "Writing %lld bytes to vcn %lld, lcn %lld, ofs "
|
||||||
"%lld.\n", ( long long )to_write, ( long long )rl->vcn,
|
"%lld.\n", ( long long )to_write, ( long long )rl->vcn,
|
||||||
( long long )rl->lcn, ( long long )ofs );
|
( long long )rl->lcn, ( long long )ofs );
|
||||||
@ -1839,13 +1827,13 @@ retry:
|
|||||||
}
|
}
|
||||||
compressed_part = 0;
|
compressed_part = 0;
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
if ( ctx )
|
if ( ctx )
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
/* Update mapping pairs if needed. */
|
/* Update mapping pairs if needed. */
|
||||||
if ( ( update_from != -1 )
|
if ( ( update_from != -1 )
|
||||||
|| ( compressed && !makingnonresident ) )
|
|| ( compressed && !makingnonresident ) )
|
||||||
if ( ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/ ) )
|
if ( ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/) )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* FIXME: trying to recover by goto rl_err_out;
|
* FIXME: trying to recover by goto rl_err_out;
|
||||||
@ -1854,10 +1842,10 @@ done:
|
|||||||
total = -1;
|
total = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave( "\n" );
|
||||||
return total;
|
return total;
|
||||||
rl_err_out:
|
rl_err_out:
|
||||||
eo = errno;
|
eo = errno;
|
||||||
if ( total )
|
if ( total )
|
||||||
{
|
{
|
||||||
@ -1874,7 +1862,7 @@ rl_err_out:
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
errno = eo;
|
errno = eo;
|
||||||
err_out:
|
err_out:
|
||||||
eo = errno;
|
eo = errno;
|
||||||
if ( need_to.undo_initialized_size )
|
if ( need_to.undo_initialized_size )
|
||||||
{
|
{
|
||||||
@ -1919,12 +1907,12 @@ err_out:
|
|||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
/* Update mapping pairs if needed. */
|
/* Update mapping pairs if needed. */
|
||||||
if ( update_from != -1 )
|
if ( update_from != -1 )
|
||||||
ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/ );
|
ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/);
|
||||||
/* Restore original data_size if needed. */
|
/* Restore original data_size if needed. */
|
||||||
if ( need_to.undo_data_size && ntfs_attr_truncate( na, old_data_size ) )
|
if ( need_to.undo_data_size && ntfs_attr_truncate( na, old_data_size ) )
|
||||||
ntfs_log_perror( "Failed to restore data_size" );
|
ntfs_log_perror( "Failed to restore data_size" );
|
||||||
errno = eo;
|
errno = eo;
|
||||||
errno_set:
|
errno_set:
|
||||||
total = -1;
|
total = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2062,7 +2050,7 @@ int ntfs_attr_pclose( ntfs_attr *na )
|
|||||||
rl++;
|
rl++;
|
||||||
}
|
}
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
if ( !NVolReadOnly( vol ) )
|
if ( !NVolReadOnly( vol ) )
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -2078,11 +2066,11 @@ retry:
|
|||||||
errno = EIO;
|
errno = EIO;
|
||||||
goto rl_err_out;
|
goto rl_err_out;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if ( ctx )
|
if ( ctx )
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
/* Update mapping pairs if needed. */
|
/* Update mapping pairs if needed. */
|
||||||
if ( ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/ ) )
|
if ( ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/) )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* FIXME: trying to recover by goto rl_err_out;
|
* FIXME: trying to recover by goto rl_err_out;
|
||||||
@ -2091,24 +2079,24 @@ done:
|
|||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave( "\n" );
|
||||||
return ( !ok );
|
return ( !ok );
|
||||||
rl_err_out:
|
rl_err_out:
|
||||||
/*
|
/*
|
||||||
* need not restore old sizes, only compressed_size
|
* need not restore old sizes, only compressed_size
|
||||||
* can have changed. It has been set according to
|
* can have changed. It has been set according to
|
||||||
* the current runlist while updating the mapping pairs,
|
* the current runlist while updating the mapping pairs,
|
||||||
* and must be kept consistent with the runlists.
|
* and must be kept consistent with the runlists.
|
||||||
*/
|
*/
|
||||||
err_out:
|
err_out:
|
||||||
eo = errno;
|
eo = errno;
|
||||||
if ( ctx )
|
if ( ctx )
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
/* Update mapping pairs if needed. */
|
/* Update mapping pairs if needed. */
|
||||||
ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/ );
|
ntfs_attr_update_mapping_pairs( na, 0 /*update_from*/);
|
||||||
errno = eo;
|
errno = eo;
|
||||||
errno_set:
|
errno_set:
|
||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2358,7 +2346,7 @@ static int ntfs_attr_find( const ATTR_TYPES type, const ntfschar *name,
|
|||||||
else
|
else
|
||||||
a = ( ATTR_RECORD* )( ( char* )ctx->attr +
|
a = ( ATTR_RECORD* )( ( char* )ctx->attr +
|
||||||
le32_to_cpu( ctx->attr->length ) );
|
le32_to_cpu( ctx->attr->length ) );
|
||||||
for ( ;; a = ( ATTR_RECORD* )( ( char* )a + le32_to_cpu( a->length ) ) )
|
for (;; a = ( ATTR_RECORD* )( ( char* )a + le32_to_cpu( a->length ) ) )
|
||||||
{
|
{
|
||||||
if ( p2n( a ) < p2n( ctx->mrec ) || ( char* )a > ( char* )ctx->mrec +
|
if ( p2n( a ) < p2n( ctx->mrec ) || ( char* )a > ( char* )ctx->mrec +
|
||||||
le32_to_cpu( ctx->mrec->bytes_allocated ) )
|
le32_to_cpu( ctx->mrec->bytes_allocated ) )
|
||||||
@ -2640,7 +2628,7 @@ static int ntfs_external_attr_find( ATTR_TYPES type, const ntfschar *name,
|
|||||||
le32_to_cpu( AT_ATTRIBUTE_LIST ) )
|
le32_to_cpu( AT_ATTRIBUTE_LIST ) )
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
find_attr_list_attr:
|
find_attr_list_attr:
|
||||||
|
|
||||||
/* Check for bogus calls. */
|
/* Check for bogus calls. */
|
||||||
if ( name || name_len || val || val_len || lowest_vcn )
|
if ( name || name_len || val || val_len || lowest_vcn )
|
||||||
@ -2683,7 +2671,7 @@ find_attr_list_attr:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ( ;; al_entry = next_al_entry )
|
for (;; al_entry = next_al_entry )
|
||||||
{
|
{
|
||||||
/* Out of bounds check. */
|
/* Out of bounds check. */
|
||||||
if ( ( u8* )al_entry < base_ni->attr_list ||
|
if ( ( u8* )al_entry < base_ni->attr_list ||
|
||||||
@ -2780,7 +2768,7 @@ find_attr_list_attr:
|
|||||||
al_name, al_name_len, CASE_SENSITIVE,
|
al_name, al_name_len, CASE_SENSITIVE,
|
||||||
vol->upcase, vol->upcase_len ) )
|
vol->upcase, vol->upcase_len ) )
|
||||||
continue;
|
continue;
|
||||||
is_enumeration:
|
is_enumeration:
|
||||||
if ( MREF_LE( al_entry->mft_reference ) == ni->mft_no )
|
if ( MREF_LE( al_entry->mft_reference ) == ni->mft_no )
|
||||||
{
|
{
|
||||||
if ( MSEQNO_LE( al_entry->mft_reference ) !=
|
if ( MSEQNO_LE( al_entry->mft_reference ) !=
|
||||||
@ -2831,7 +2819,7 @@ is_enumeration:
|
|||||||
* Use a manual loop so we can still use break and continue
|
* Use a manual loop so we can still use break and continue
|
||||||
* with the same meanings as above.
|
* with the same meanings as above.
|
||||||
*/
|
*/
|
||||||
do_next_attr_loop:
|
do_next_attr_loop:
|
||||||
if ( ( char* )a < ( char* )ctx->mrec || ( char* )a > ( char* )ctx->mrec +
|
if ( ( char* )a < ( char* )ctx->mrec || ( char* )a > ( char* )ctx->mrec +
|
||||||
le32_to_cpu( ctx->mrec->bytes_allocated ) )
|
le32_to_cpu( ctx->mrec->bytes_allocated ) )
|
||||||
break;
|
break;
|
||||||
@ -2867,7 +2855,7 @@ do_next_attr_loop:
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
do_next_attr:
|
do_next_attr:
|
||||||
/* Proceed to the next attribute in the current mft record. */
|
/* Proceed to the next attribute in the current mft record. */
|
||||||
a = ( ATTR_RECORD* )( ( char* )a + le32_to_cpu( a->length ) );
|
a = ( ATTR_RECORD* )( ( char* )a + le32_to_cpu( a->length ) );
|
||||||
goto do_next_attr_loop;
|
goto do_next_attr_loop;
|
||||||
@ -2881,7 +2869,7 @@ do_next_attr:
|
|||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Inode is corrupt (%lld)", ( long long )base_ni->mft_no );
|
ntfs_log_perror( "Inode is corrupt (%lld)", ( long long )base_ni->mft_no );
|
||||||
return -1;
|
return -1;
|
||||||
not_found:
|
not_found:
|
||||||
/*
|
/*
|
||||||
* If we were looking for AT_END or we were enumerating and reached the
|
* If we were looking for AT_END or we were enumerating and reached the
|
||||||
* end, we reset the search context @ctx and use ntfs_attr_find() to
|
* end, we reset the search context @ctx and use ntfs_attr_find() to
|
||||||
@ -3030,7 +3018,7 @@ int ntfs_attr_lookup( const ATTR_TYPES type, const ntfschar *name,
|
|||||||
else
|
else
|
||||||
ret = ntfs_external_attr_find( type, name, name_len, ic,
|
ret = ntfs_external_attr_find( type, name, name_len, ic,
|
||||||
lowest_vcn, val, val_len, ctx );
|
lowest_vcn, val, val_len, ctx );
|
||||||
out:
|
out:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave( "\n" );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -3520,7 +3508,7 @@ int ntfs_resident_attr_record_add( ntfs_inode *ni, ATTR_TYPES type,
|
|||||||
ntfs_inode_mark_dirty( ni );
|
ntfs_inode_mark_dirty( ni );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
return offset;
|
return offset;
|
||||||
put_err_out:
|
put_err_out:
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
@ -3674,7 +3662,7 @@ int ntfs_non_resident_attr_record_add( ntfs_inode *ni, ATTR_TYPES type,
|
|||||||
offset = ( u8* )ctx->attr - ( u8* )ctx->mrec;
|
offset = ( u8* )ctx->attr - ( u8* )ctx->mrec;
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
return offset;
|
return offset;
|
||||||
put_err_out:
|
put_err_out:
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
@ -3985,7 +3973,7 @@ int ntfs_attr_add( ntfs_inode *ni, ATTR_TYPES type,
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_attr_record:
|
add_attr_record:
|
||||||
if ( ( ni->flags & FILE_ATTR_COMPRESSED )
|
if ( ( ni->flags & FILE_ATTR_COMPRESSED )
|
||||||
&& ( ( type == AT_DATA )
|
&& ( ( type == AT_DATA )
|
||||||
|| ( ( type == AT_INDEX_ROOT ) && ( name == NTFS_INDEX_I30 ) ) ) )
|
|| ( ( type == AT_INDEX_ROOT ) && ( name == NTFS_INDEX_I30 ) ) ) )
|
||||||
@ -4008,7 +3996,7 @@ add_attr_record:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_non_resident:
|
add_non_resident:
|
||||||
/* Add non resident attribute. */
|
/* Add non resident attribute. */
|
||||||
offset = ntfs_non_resident_attr_record_add( attr_ni, type, name,
|
offset = ntfs_non_resident_attr_record_add( attr_ni, type, name,
|
||||||
name_len, 0, 8, data_flags );
|
name_len, 0, 8, data_flags );
|
||||||
@ -4045,18 +4033,18 @@ add_non_resident:
|
|||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rm_attr_err_out:
|
rm_attr_err_out:
|
||||||
/* Remove just added attribute. */
|
/* Remove just added attribute. */
|
||||||
if ( ntfs_attr_record_resize( attr_ni->mrec,
|
if ( ntfs_attr_record_resize( attr_ni->mrec,
|
||||||
( ATTR_RECORD* )( ( u8* )attr_ni->mrec + offset ), 0 ) )
|
( ATTR_RECORD* )( ( u8* )attr_ni->mrec + offset ), 0 ) )
|
||||||
ntfs_log_perror( "Failed to remove just added attribute #2" );
|
ntfs_log_perror( "Failed to remove just added attribute #2" );
|
||||||
free_err_out:
|
free_err_out:
|
||||||
/* Free MFT record, if it doesn't contain attributes. */
|
/* Free MFT record, if it doesn't contain attributes. */
|
||||||
if ( le32_to_cpu( attr_ni->mrec->bytes_in_use ) -
|
if ( le32_to_cpu( attr_ni->mrec->bytes_in_use ) -
|
||||||
le16_to_cpu( attr_ni->mrec->attrs_offset ) == 8 )
|
le16_to_cpu( attr_ni->mrec->attrs_offset ) == 8 )
|
||||||
if ( ntfs_mft_record_free( attr_ni->vol, attr_ni ) )
|
if ( ntfs_mft_record_free( attr_ni->vol, attr_ni ) )
|
||||||
ntfs_log_perror( "Failed to free MFT record" );
|
ntfs_log_perror( "Failed to free MFT record" );
|
||||||
err_out:
|
err_out:
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -4090,7 +4078,6 @@ int ntfs_attr_set_flags( ntfs_inode *ni, ATTR_TYPES type,
|
|||||||
return ( res );
|
return ( res );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_attr_rm - remove attribute from ntfs inode
|
* ntfs_attr_rm - remove attribute from ntfs inode
|
||||||
* @na: opened ntfs attribute to delete
|
* @na: opened ntfs attribute to delete
|
||||||
@ -4353,7 +4340,7 @@ int ntfs_attr_record_move_to( ntfs_attr_search_ctx *ctx, ntfs_inode *ni )
|
|||||||
|
|
||||||
ntfs_attr_put_search_ctx( nctx );
|
ntfs_attr_put_search_ctx( nctx );
|
||||||
return 0;
|
return 0;
|
||||||
put_err_out:
|
put_err_out:
|
||||||
ntfs_attr_put_search_ctx( nctx );
|
ntfs_attr_put_search_ctx( nctx );
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
@ -4635,7 +4622,7 @@ int ntfs_attr_make_non_resident( ntfs_attr *na,
|
|||||||
/* Done! */
|
/* Done! */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cluster_free_err_out:
|
cluster_free_err_out:
|
||||||
if ( rl && ntfs_cluster_free( vol, na, 0, -1 ) < 0 )
|
if ( rl && ntfs_cluster_free( vol, na, 0, -1 ) < 0 )
|
||||||
ntfs_log_trace( "Eeek! Failed to release allocated clusters in error "
|
ntfs_log_trace( "Eeek! Failed to release allocated clusters in error "
|
||||||
"code path. Leaving inconsistent metadata...\n" );
|
"code path. Leaving inconsistent metadata...\n" );
|
||||||
@ -4647,7 +4634,6 @@ cluster_free_err_out:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ntfs_resident_attr_resize( ntfs_attr *na, const s64 newsize );
|
static int ntfs_resident_attr_resize( ntfs_attr *na, const s64 newsize );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4876,7 +4862,7 @@ static int ntfs_resident_attr_resize_i( ntfs_attr *na, const s64 newsize )
|
|||||||
/* Try to perform resize once again. */
|
/* Try to perform resize once again. */
|
||||||
return ntfs_resident_attr_resize( na, newsize );
|
return ntfs_resident_attr_resize( na, newsize );
|
||||||
|
|
||||||
resize_done:
|
resize_done:
|
||||||
/*
|
/*
|
||||||
* Set the inode (and its base inode if it exists) dirty so it is
|
* Set the inode (and its base inode if it exists) dirty so it is
|
||||||
* written out later.
|
* written out later.
|
||||||
@ -4884,7 +4870,7 @@ resize_done:
|
|||||||
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
ntfs_inode_mark_dirty( ctx->ntfs_ino );
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
return 0;
|
return 0;
|
||||||
put_err_out:
|
put_err_out:
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
errno = err;
|
errno = err;
|
||||||
return ret;
|
return ret;
|
||||||
@ -5207,11 +5193,11 @@ static int ntfs_attr_update_meta( ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
|
|||||||
na->ni->allocated_size = na->allocated_size;
|
na->ni->allocated_size = na->allocated_size;
|
||||||
NInoFileNameSetDirty( na->ni );
|
NInoFileNameSetDirty( na->ni );
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
leave: ret = -1; goto out; /* return -1 */
|
leave: ret = -1; goto out; /* return -1 */
|
||||||
retry: ret = -2; goto out;
|
retry: ret = -2; goto out;
|
||||||
error: ret = -3; goto out;
|
error: ret = -3; goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NTFS_VCN_DELETE_MARK -2
|
#define NTFS_VCN_DELETE_MARK -2
|
||||||
@ -5229,7 +5215,7 @@ static int ntfs_attr_update_mapping_pairs_i( ntfs_attr *na, VCN from_vcn )
|
|||||||
int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1;
|
int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1;
|
||||||
BOOL finished_build;
|
BOOL finished_build;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
if ( !na || !na->rl || from_vcn )
|
if ( !na || !na->rl || from_vcn )
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@ -5530,11 +5516,11 @@ retry:
|
|||||||
if ( !err )
|
if ( !err )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ok:
|
ok:
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
put_err_out:
|
put_err_out:
|
||||||
if ( ctx )
|
if ( ctx )
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
goto out;
|
goto out;
|
||||||
@ -5658,7 +5644,7 @@ static int ntfs_non_resident_attr_shrink( ntfs_attr *na, const s64 newsize )
|
|||||||
/* Prepare to mapping pairs update. */
|
/* Prepare to mapping pairs update. */
|
||||||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||||
/* Write mapping pairs for new runlist. */
|
/* Write mapping pairs for new runlist. */
|
||||||
if ( ntfs_attr_update_mapping_pairs( na, 0 /*first_free_vcn*/ ) )
|
if ( ntfs_attr_update_mapping_pairs( na, 0 /*first_free_vcn*/) )
|
||||||
{
|
{
|
||||||
ntfs_log_trace( "Eeek! Mapping pairs update failed. "
|
ntfs_log_trace( "Eeek! Mapping pairs update failed. "
|
||||||
"Leaving inconstant metadata. "
|
"Leaving inconstant metadata. "
|
||||||
@ -5715,7 +5701,7 @@ static int ntfs_non_resident_attr_shrink( ntfs_attr *na, const s64 newsize )
|
|||||||
/* Done! */
|
/* Done! */
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
return 0;
|
return 0;
|
||||||
put_err_out:
|
put_err_out:
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
@ -5861,7 +5847,7 @@ static int ntfs_non_resident_attr_expand_i( ntfs_attr *na, const s64 newsize )
|
|||||||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||||
/* Write mapping pairs for new runlist. */
|
/* Write mapping pairs for new runlist. */
|
||||||
if ( ntfs_attr_update_mapping_pairs( na, 0 /*na->allocated_size >>
|
if ( ntfs_attr_update_mapping_pairs( na, 0 /*na->allocated_size >>
|
||||||
vol->cluster_size_bits*/ ) )
|
vol->cluster_size_bits*/) )
|
||||||
{
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Mapping pairs update failed" );
|
ntfs_log_perror( "Mapping pairs update failed" );
|
||||||
@ -5912,7 +5898,7 @@ static int ntfs_non_resident_attr_expand_i( ntfs_attr *na, const s64 newsize )
|
|||||||
/* Done! */
|
/* Done! */
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
return 0;
|
return 0;
|
||||||
rollback:
|
rollback:
|
||||||
/* Free allocated clusters. */
|
/* Free allocated clusters. */
|
||||||
if ( ntfs_cluster_free( vol, na, org_alloc_size >>
|
if ( ntfs_cluster_free( vol, na, org_alloc_size >>
|
||||||
vol->cluster_size_bits, -1 ) < 0 )
|
vol->cluster_size_bits, -1 ) < 0 )
|
||||||
@ -5938,20 +5924,19 @@ rollback:
|
|||||||
na->allocated_size = org_alloc_size;
|
na->allocated_size = org_alloc_size;
|
||||||
/* Restore mapping pairs. */
|
/* Restore mapping pairs. */
|
||||||
if ( ntfs_attr_update_mapping_pairs( na, 0 /*na->allocated_size >>
|
if ( ntfs_attr_update_mapping_pairs( na, 0 /*na->allocated_size >>
|
||||||
vol->cluster_size_bits*/ ) )
|
vol->cluster_size_bits*/) )
|
||||||
{
|
{
|
||||||
ntfs_log_perror( "Failed to restore old mapping pairs" );
|
ntfs_log_perror( "Failed to restore old mapping pairs" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
put_err_out:
|
put_err_out:
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx( ctx );
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ntfs_non_resident_attr_expand( ntfs_attr *na, const s64 newsize )
|
static int ntfs_non_resident_attr_expand( ntfs_attr *na, const s64 newsize )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -6059,7 +6044,7 @@ int ntfs_attr_truncate( ntfs_attr *na, const s64 newsize )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = ntfs_resident_attr_resize( na, newsize );
|
ret = ntfs_resident_attr_resize( na, newsize );
|
||||||
out:
|
out:
|
||||||
ntfs_log_leave( "Return status %d\n", ret );
|
ntfs_log_leave( "Return status %d\n", ret );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -6207,15 +6192,13 @@ void *ntfs_attr_readall( ntfs_inode *ni, const ATTR_TYPES type,
|
|||||||
ret = data;
|
ret = data;
|
||||||
if ( data_size )
|
if ( data_size )
|
||||||
*data_size = size;
|
*data_size = size;
|
||||||
out:
|
out:
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close( na );
|
||||||
err_exit:
|
err_exit:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave( "\n" );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int ntfs_attr_exist( ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
|
int ntfs_attr_exist( ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
|
||||||
u32 name_len )
|
u32 name_len )
|
||||||
{
|
{
|
||||||
@ -6313,7 +6296,7 @@ s64 ntfs_attr_get_free_bits( ntfs_attr *na )
|
|||||||
break;
|
break;
|
||||||
total += br;
|
total += br;
|
||||||
p = ( u32 * )buf + br / 4 - 1;
|
p = ( u32 * )buf + br / 4 - 1;
|
||||||
for ( ; ( u8 * )p >= buf; p-- )
|
for (; ( u8 * )p >= buf; p-- )
|
||||||
{
|
{
|
||||||
nr_free += lut[ *p & 255] +
|
nr_free += lut[ *p & 255] +
|
||||||
lut[( *p >> 8 ) & 255] +
|
lut[( *p >> 8 ) & 255] +
|
||||||
@ -6328,7 +6311,7 @@ s64 ntfs_attr_get_free_bits( ntfs_attr *na )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
free( buf );
|
free( buf );
|
||||||
out:
|
out:
|
||||||
free( lut );
|
free( lut );
|
||||||
if ( !total || br < 0 )
|
if ( !total || br < 0 )
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -62,7 +62,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
|||||||
{
|
{
|
||||||
ATTR_LIST_ENTRY *ale;
|
ATTR_LIST_ENTRY *ale;
|
||||||
|
|
||||||
if (!ni) {
|
if (!ni)
|
||||||
|
{
|
||||||
ntfs_log_trace("Invalid arguments.\n");
|
ntfs_log_trace("Invalid arguments.\n");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -70,24 +71,26 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
|||||||
|
|
||||||
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)) {
|
if (!NInoAttrList(ni))
|
||||||
|
{
|
||||||
ntfs_log_trace("Inode haven't got attribute list.\n");
|
ntfs_log_trace("Inode haven't got attribute list.\n");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ni->attr_list) {
|
if (!ni->attr_list)
|
||||||
|
{
|
||||||
ntfs_log_trace("Corrupt in-memory struct.\n");
|
ntfs_log_trace("Corrupt in-memory struct.\n");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ale = (ATTR_LIST_ENTRY *)ni->attr_list;
|
ale = (ATTR_LIST_ENTRY *) ni->attr_list;
|
||||||
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
while ((u8*) ale < ni->attr_list + ni->attr_list_size)
|
||||||
if (MREF_LE(ale->mft_reference) != ni->mft_no)
|
{
|
||||||
return 1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -117,7 +120,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
(long long) ni->mft_no,
|
(long long) ni->mft_no,
|
||||||
(unsigned) le32_to_cpu(attr->type));
|
(unsigned) le32_to_cpu(attr->type));
|
||||||
|
|
||||||
if (!ni || !attr) {
|
if (!ni || !attr)
|
||||||
|
{
|
||||||
ntfs_log_trace("Invalid arguments.\n");
|
ntfs_log_trace("Invalid arguments.\n");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -125,37 +129,36 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
|
|
||||||
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;
|
||||||
ni = ni->base_ni;
|
|
||||||
|
|
||||||
if (!NInoAttrList(ni)) {
|
if (!NInoAttrList(ni))
|
||||||
|
{
|
||||||
ntfs_log_trace("Attribute list isn't present.\n");
|
ntfs_log_trace("Attribute list isn't present.\n");
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine size and allocate memory for new attribute list. */
|
/* Determine size and allocate memory for new attribute list. */
|
||||||
entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
|
entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * attr->name_length + 7) & ~7;
|
||||||
attr->name_length + 7) & ~7;
|
|
||||||
new_al = ntfs_calloc(ni->attr_list_size + entry_len);
|
new_al = ntfs_calloc(ni->attr_list_size + entry_len);
|
||||||
if (!new_al)
|
if (!new_al) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Find place for the new entry. */
|
/* Find place for the new entry. */
|
||||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||||
if (!ctx) {
|
if (!ctx)
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
|
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*) ((u8*) attr + le16_to_cpu(attr->name_offset))
|
||||||
((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,
|
||||||
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
|
(attr->non_resident) ? NULL : ((u8*) attr + le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
|
||||||
(attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) :
|
0
|
||||||
0, (attr->non_resident) ? NULL : ((u8*)attr +
|
: le32_to_cpu(attr->value_length), ctx))
|
||||||
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. */
|
/* 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;
|
err = EEXIST;
|
||||||
ntfs_log_trace("Such attribute already present in the "
|
ntfs_log_trace("Such attribute already present in the "
|
||||||
"attribute list.\n");
|
"attribute list.\n");
|
||||||
@ -163,11 +166,13 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* Add new entry after this extent. */
|
/* Add new entry after this extent. */
|
||||||
ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
|
ale = (ATTR_LIST_ENTRY*) ((u8*) ctx->al_entry + le16_to_cpu(ctx->al_entry->length));
|
||||||
le16_to_cpu(ctx->al_entry->length));
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
/* Check for real errors. */
|
/* Check for real errors. */
|
||||||
if (errno != ENOENT) {
|
if (errno != ENOENT)
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace("Attribute lookup failed.\n");
|
ntfs_log_trace("Attribute lookup failed.\n");
|
||||||
ntfs_attr_put_search_ctx(ctx);
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
@ -180,9 +185,9 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
ntfs_attr_put_search_ctx(ctx);
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
|
|
||||||
/* Determine new entry offset. */
|
/* Determine new entry offset. */
|
||||||
entry_offset = ((u8 *)ale - ni->attr_list);
|
entry_offset = ((u8 *) ale - ni->attr_list);
|
||||||
/* Set pointer to new entry. */
|
/* 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. */
|
/* Zero it to fix valgrind warning. */
|
||||||
memset(ale, 0, entry_len);
|
memset(ale, 0, entry_len);
|
||||||
/* Form new entry. */
|
/* Form new entry. */
|
||||||
@ -192,21 +197,21 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
|
ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
|
||||||
if (attr->non_resident)
|
if (attr->non_resident)
|
||||||
ale->lowest_vcn = attr->lowest_vcn;
|
ale->lowest_vcn = attr->lowest_vcn;
|
||||||
else
|
else ale->lowest_vcn = 0;
|
||||||
ale->lowest_vcn = 0;
|
|
||||||
ale->mft_reference = mref;
|
ale->mft_reference = mref;
|
||||||
ale->instance = attr->instance;
|
ale->instance = attr->instance;
|
||||||
memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
|
memcpy(ale->name, (u8 *) attr + le16_to_cpu(attr->name_offset), attr->name_length * sizeof(ntfschar));
|
||||||
attr->name_length * sizeof(ntfschar));
|
|
||||||
|
|
||||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||||
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||||
if (!na) {
|
if (!na)
|
||||||
|
{
|
||||||
err = errno;
|
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;
|
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;
|
err = errno;
|
||||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -214,8 +219,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
|
|
||||||
/* Copy entries from old attribute list to new. */
|
/* Copy entries from old attribute list to new. */
|
||||||
memcpy(new_al, ni->attr_list, entry_offset);
|
memcpy(new_al, ni->attr_list, entry_offset);
|
||||||
memcpy(new_al + entry_offset + entry_len, ni->attr_list +
|
memcpy(new_al + entry_offset + entry_len, ni->attr_list + entry_offset, ni->attr_list_size - entry_offset);
|
||||||
entry_offset, ni->attr_list_size - entry_offset);
|
|
||||||
|
|
||||||
/* Set new runlist. */
|
/* Set new runlist. */
|
||||||
free(ni->attr_list);
|
free(ni->attr_list);
|
||||||
@ -225,9 +229,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
|||||||
/* Done! */
|
/* Done! */
|
||||||
ntfs_attr_close(na);
|
ntfs_attr_close(na);
|
||||||
return 0;
|
return 0;
|
||||||
err_out:
|
err_out: if (na) ntfs_attr_close(na);
|
||||||
if (na)
|
|
||||||
ntfs_attr_close(na);
|
|
||||||
free(new_al);
|
free(new_al);
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
@ -250,7 +252,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
ATTR_LIST_ENTRY *ale;
|
ATTR_LIST_ENTRY *ale;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry)
|
||||||
|
{
|
||||||
ntfs_log_trace("Invalid arguments.\n");
|
ntfs_log_trace("Invalid arguments.\n");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@ -258,8 +261,7 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
|
|
||||||
if (ctx->base_ntfs_ino)
|
if (ctx->base_ntfs_ino)
|
||||||
base_ni = ctx->base_ntfs_ino;
|
base_ni = ctx->base_ntfs_ino;
|
||||||
else
|
else base_ni = ctx->ntfs_ino;
|
||||||
base_ni = ctx->ntfs_ino;
|
|
||||||
ale = ctx->al_entry;
|
ale = ctx->al_entry;
|
||||||
|
|
||||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
||||||
@ -267,7 +269,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
(unsigned) le32_to_cpu(ctx->al_entry->type),
|
(unsigned) le32_to_cpu(ctx->al_entry->type),
|
||||||
(long long) le64_to_cpu(ctx->al_entry->lowest_vcn));
|
(long long) le64_to_cpu(ctx->al_entry->lowest_vcn));
|
||||||
|
|
||||||
if (!NInoAttrList(base_ni)) {
|
if (!NInoAttrList(base_ni))
|
||||||
|
{
|
||||||
ntfs_log_trace("Attribute list isn't present.\n");
|
ntfs_log_trace("Attribute list isn't present.\n");
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -276,26 +279,27 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
/* Allocate memory for new attribute list. */
|
/* Allocate memory for new attribute list. */
|
||||||
new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
|
new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
|
||||||
new_al = ntfs_calloc(new_al_len);
|
new_al = ntfs_calloc(new_al_len);
|
||||||
if (!new_al)
|
if (!new_al) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||||
na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||||
if (!na) {
|
if (!na)
|
||||||
|
{
|
||||||
err = errno;
|
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;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (ntfs_attr_truncate(na, new_al_len)) {
|
if (ntfs_attr_truncate(na, new_al_len))
|
||||||
|
{
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy entries from old attribute list to new. */
|
/* Copy entries from old attribute list to new. */
|
||||||
memcpy(new_al, base_ni->attr_list, (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(
|
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));
|
ale->length), new_al_len - ((u8*) ale - base_ni->attr_list));
|
||||||
|
|
||||||
/* Set new runlist. */
|
/* Set new runlist. */
|
||||||
free(base_ni->attr_list);
|
free(base_ni->attr_list);
|
||||||
@ -305,9 +309,7 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
|||||||
/* Done! */
|
/* Done! */
|
||||||
ntfs_attr_close(na);
|
ntfs_attr_close(na);
|
||||||
return 0;
|
return 0;
|
||||||
err_out:
|
err_out: if (na) ntfs_attr_close(na);
|
||||||
if (na)
|
|
||||||
ntfs_attr_close(na);
|
|
||||||
free(new_al);
|
free(new_al);
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -44,8 +44,7 @@ static __inline__ void ntfs_attrlist_mark_dirty(ntfs_inode *ni)
|
|||||||
{
|
{
|
||||||
if (ni->nr_extents == -1)
|
if (ni->nr_extents == -1)
|
||||||
NInoAttrListSetDirty(ni->base_ni);
|
NInoAttrListSetDirty(ni->base_ni);
|
||||||
else
|
else NInoAttrListSetDirty(ni);
|
||||||
NInoAttrListSetDirty(ni);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined _NTFS_ATTRLIST_H */
|
#endif /* defined _NTFS_ATTRLIST_H */
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _BIT_OPS_H
|
#ifndef _BIT_OPS_H
|
||||||
#define _BIT_OPS_H
|
#define _BIT_OPS_H
|
||||||
@ -32,26 +32,30 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
Functions to deal with little endian values stored in uint8_t arrays
|
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) {
|
static inline uint16_t u8array_to_u16(const uint8_t* item, int offset)
|
||||||
return ( item[offset] | (item[offset + 1] << 8));
|
{
|
||||||
|
return (item[offset] | (item[offset + 1] << 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
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));
|
{
|
||||||
|
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) {
|
static inline void u16_to_u8array(uint8_t* item, int offset, uint16_t value)
|
||||||
|
{
|
||||||
item[offset] = (uint8_t) value;
|
item[offset] = (uint8_t) value;
|
||||||
item[offset + 1] = (uint8_t)(value >> 8);
|
item[offset + 1] = (uint8_t) (value >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
static inline void u32_to_u8array(uint8_t* item, int offset, uint32_t value)
|
||||||
|
{
|
||||||
item[offset] = (uint8_t) value;
|
item[offset] = (uint8_t) value;
|
||||||
item[offset + 1] = (uint8_t)(value >> 8);
|
item[offset + 1] = (uint8_t) (value >> 8);
|
||||||
item[offset + 2] = (uint8_t)(value >> 16);
|
item[offset + 2] = (uint8_t) (value >> 16);
|
||||||
item[offset + 3] = (uint8_t)(value >> 24);
|
item[offset + 3] = (uint8_t) (value >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _BIT_OPS_H
|
#endif // _BIT_OPS_H
|
||||||
|
@ -55,12 +55,10 @@
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
return;
|
|
||||||
if (!new_value)
|
if (!new_value)
|
||||||
bitmap[bit >> 3] &= ~(1 << (bit & 7));
|
bitmap[bit >> 3] &= ~(1 << (bit & 7));
|
||||||
else
|
else bitmap[bit >> 3] |= (1 << (bit & 7));
|
||||||
bitmap[bit >> 3] |= (1 << (bit & 7));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,8 +71,7 @@ void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
|||||||
*/
|
*/
|
||||||
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 -1;
|
|
||||||
return (bitmap[bit >> 3] >> (bit & 7)) & 1;
|
return (bitmap[bit >> 3] >> (bit & 7)) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +88,10 @@ char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
|||||||
{
|
{
|
||||||
register u8 old_bit, shift;
|
register u8 old_bit, shift;
|
||||||
|
|
||||||
if (!bitmap || new_value > 1)
|
if (!bitmap || new_value > 1) return -1;
|
||||||
return -1;
|
|
||||||
shift = bit & 7;
|
shift = bit & 7;
|
||||||
old_bit = (bitmap[bit >> 3] >> shift) & 1;
|
old_bit = (bitmap[bit >> 3] >> shift) & 1;
|
||||||
if (new_value != old_bit)
|
if (new_value != old_bit) bitmap[bit >> 3] ^= 1 << shift;
|
||||||
bitmap[bit >> 3] ^= 1 << shift;
|
|
||||||
return old_bit;
|
return old_bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,14 +107,14 @@ 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.
|
* 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,
|
static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, s64 count, int value)
|
||||||
s64 count, int value)
|
|
||||||
{
|
{
|
||||||
s64 bufsize, br;
|
s64 bufsize, br;
|
||||||
u8 *buf, *lastbyte_buf;
|
u8 *buf, *lastbyte_buf;
|
||||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
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;
|
errno = EINVAL;
|
||||||
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
|
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
|
||||||
__FUNCTION__, na, (long long)start_bit, (long long)count);
|
__FUNCTION__, na, (long long)start_bit, (long long)count);
|
||||||
@ -129,36 +124,34 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
bit = start_bit & 7;
|
bit = start_bit & 7;
|
||||||
if (bit)
|
if (bit)
|
||||||
firstbyte = 1;
|
firstbyte = 1;
|
||||||
else
|
else firstbyte = 0;
|
||||||
firstbyte = 0;
|
|
||||||
|
|
||||||
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
||||||
bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
|
bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
|
||||||
if (bufsize > 8192)
|
if (bufsize > 8192) bufsize = 8192;
|
||||||
bufsize = 8192;
|
|
||||||
|
|
||||||
buf = ntfs_malloc(bufsize);
|
buf = ntfs_malloc(bufsize);
|
||||||
if (!buf)
|
if (!buf) return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
/* 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 there is a first partial byte... */
|
||||||
if (bit) {
|
if (bit)
|
||||||
|
{
|
||||||
/* read it in... */
|
/* read it in... */
|
||||||
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
||||||
if (br != 1) {
|
if (br != 1)
|
||||||
if (br >= 0)
|
{
|
||||||
errno = EIO;
|
if (br >= 0) errno = EIO;
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and set or clear the appropriate bits in it. */
|
/* and set or clear the appropriate bits in it. */
|
||||||
while ((bit & 7) && count--) {
|
while ((bit & 7) && count--)
|
||||||
|
{
|
||||||
if (value)
|
if (value)
|
||||||
*buf |= 1 << bit++;
|
*buf |= 1 << bit++;
|
||||||
else
|
else *buf &= ~(1 << bit++);
|
||||||
*buf &= ~(1 << bit++);
|
|
||||||
}
|
}
|
||||||
/* Update @start_bit to the new position. */
|
/* Update @start_bit to the new position. */
|
||||||
start_bit = (start_bit + 7) & ~7;
|
start_bit = (start_bit + 7) & ~7;
|
||||||
@ -168,11 +161,14 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
lastbyte = 0;
|
lastbyte = 0;
|
||||||
lastbyte_buf = NULL;
|
lastbyte_buf = NULL;
|
||||||
bit = count & 7;
|
bit = count & 7;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
/* If there is a last partial byte... */
|
/* If there is a last partial byte... */
|
||||||
if (count > 0 && bit) {
|
if (count > 0 && bit)
|
||||||
|
{
|
||||||
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||||
if (!lastbyte_pos) {
|
if (!lastbyte_pos)
|
||||||
|
{
|
||||||
// FIXME: Eeek! BUG!
|
// FIXME: Eeek! BUG!
|
||||||
ntfs_log_error("Lastbyte is zero. Leaving "
|
ntfs_log_error("Lastbyte is zero. Leaving "
|
||||||
"inconsistent metadata.\n");
|
"inconsistent metadata.\n");
|
||||||
@ -180,27 +176,27 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and it is in the currently loaded bitmap window... */
|
/* and it is in the currently loaded bitmap window... */
|
||||||
if (lastbyte_pos <= bufsize) {
|
if (lastbyte_pos <= bufsize)
|
||||||
|
{
|
||||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||||
|
|
||||||
/* read the byte in... */
|
/* read the byte in... */
|
||||||
br = ntfs_attr_pread(na, (start_bit + count) >>
|
br = ntfs_attr_pread(na, (start_bit + count) >> 3, 1, lastbyte_buf);
|
||||||
3, 1, lastbyte_buf);
|
if (br != 1)
|
||||||
if (br != 1) {
|
{
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
if (br >= 0)
|
if (br >= 0) errno = EIO;
|
||||||
errno = EIO;
|
|
||||||
ntfs_log_perror("Reading of last byte "
|
ntfs_log_perror("Reading of last byte "
|
||||||
"failed (%lld). Leaving inconsistent "
|
"failed (%lld). Leaving inconsistent "
|
||||||
"metadata", (long long)br);
|
"metadata", (long long)br);
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and set/clear the appropriate bits in it. */
|
/* and set/clear the appropriate bits in it. */
|
||||||
while (bit && count--) {
|
while (bit && count--)
|
||||||
|
{
|
||||||
if (value)
|
if (value)
|
||||||
*lastbyte_buf |= 1 << --bit;
|
*lastbyte_buf |= 1 << --bit;
|
||||||
else
|
else *lastbyte_buf &= ~(1 << --bit);
|
||||||
*lastbyte_buf &= ~(1 << --bit);
|
|
||||||
}
|
}
|
||||||
/* We don't want to come back here... */
|
/* We don't want to come back here... */
|
||||||
bit = 0;
|
bit = 0;
|
||||||
@ -212,10 +208,10 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
/* Write the prepared buffer to disk. */
|
/* Write the prepared buffer to disk. */
|
||||||
tmp = (start_bit >> 3) - firstbyte;
|
tmp = (start_bit >> 3) - firstbyte;
|
||||||
br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
|
br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
|
||||||
if (br != bufsize) {
|
if (br != bufsize)
|
||||||
|
{
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
if (br >= 0)
|
if (br >= 0) errno = EIO;
|
||||||
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",
|
"(%lld != %lld). Leaving inconsistent metadata",
|
||||||
(long long)br, (long long)bufsize);
|
(long long)br, (long long)bufsize);
|
||||||
@ -224,7 +220,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
|
|
||||||
/* Update counters. */
|
/* Update counters. */
|
||||||
tmp = (bufsize - firstbyte - lastbyte) << 3;
|
tmp = (bufsize - firstbyte - lastbyte) << 3;
|
||||||
if (firstbyte) {
|
if (firstbyte)
|
||||||
|
{
|
||||||
firstbyte = 0;
|
firstbyte = 0;
|
||||||
/*
|
/*
|
||||||
* Re-set the partial first byte so a subsequent write
|
* Re-set the partial first byte so a subsequent write
|
||||||
@ -234,10 +231,10 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
}
|
}
|
||||||
start_bit += tmp;
|
start_bit += tmp;
|
||||||
count -= tmp;
|
count -= tmp;
|
||||||
if (bufsize > (tmp = (count + 7) >> 3))
|
if (bufsize > (tmp = (count + 7) >> 3)) bufsize = tmp;
|
||||||
bufsize = tmp;
|
|
||||||
|
|
||||||
if (lastbyte && count != 0) {
|
if (lastbyte && count != 0)
|
||||||
|
{
|
||||||
// FIXME: Eeek! BUG!
|
// 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",
|
"(%lld). Leaving inconsistent metadata.\n",
|
||||||
@ -249,8 +246,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
free_err_out:
|
free_err_out: free(buf);
|
||||||
free(buf);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,22 +65,31 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
ntfs_log_debug("Beginning bootsector check.\n");
|
ntfs_log_debug("Beginning bootsector check.\n");
|
||||||
|
|
||||||
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
|
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
|
||||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
if (b->oem_id != cpu_to_le64(0x202020205346544eULL))
|
||||||
|
{ /* "NTFS " */
|
||||||
ntfs_log_error("NTFS signature is missing.\n");
|
ntfs_log_error("NTFS signature is missing.\n");
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug("Checking bytes per sector.\n");
|
ntfs_log_debug("Checking bytes per sector.\n");
|
||||||
if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 ||
|
if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 || le16_to_cpu(b->bpb.bytes_per_sector) > 4096)
|
||||||
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
|
{
|
||||||
ntfs_log_error("Unexpected bytes per sector value (%d).\n",
|
ntfs_log_error("Unexpected bytes per sector value (%d).\n",
|
||||||
le16_to_cpu(b->bpb.bytes_per_sector));
|
le16_to_cpu(b->bpb.bytes_per_sector));
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug("Checking sectors per cluster.\n");
|
ntfs_log_debug("Checking sectors per cluster.\n");
|
||||||
switch (b->bpb.sectors_per_cluster) {
|
switch (b->bpb.sectors_per_cluster)
|
||||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
case 16:
|
||||||
|
case 32:
|
||||||
|
case 64:
|
||||||
|
case 128:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
|
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
|
||||||
@ -89,20 +98,17 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug("Checking cluster size.\n");
|
ntfs_log_debug("Checking cluster size.\n");
|
||||||
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) *
|
i = (u32) le16_to_cpu(b->bpb.bytes_per_sector) * b->bpb.sectors_per_cluster;
|
||||||
b->bpb.sectors_per_cluster;
|
if (i > 65536)
|
||||||
if (i > 65536) {
|
{
|
||||||
ntfs_log_error("Unexpected cluster size (%d).\n", i);
|
ntfs_log_error("Unexpected cluster size (%d).\n", i);
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug("Checking reserved fields are zero.\n");
|
ntfs_log_debug("Checking reserved fields are zero.\n");
|
||||||
if (le16_to_cpu(b->bpb.reserved_sectors) ||
|
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.root_entries) ||
|
|| le16_to_cpu(b->bpb.sectors_per_fat) || le32_to_cpu(b->bpb.large_sectors) || b->bpb.fats)
|
||||||
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_error("Reserved fields aren't zero "
|
||||||
"(%d, %d, %d, %d, %d, %d).\n",
|
"(%d, %d, %d, %d, %d, %d).\n",
|
||||||
le16_to_cpu(b->bpb.reserved_sectors),
|
le16_to_cpu(b->bpb.reserved_sectors),
|
||||||
@ -115,10 +121,17 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug("Checking clusters per mft record.\n");
|
ntfs_log_debug("Checking clusters per mft record.\n");
|
||||||
if ((u8)b->clusters_per_mft_record < 0xe1 ||
|
if ((u8) b->clusters_per_mft_record < 0xe1 || (u8) b->clusters_per_mft_record > 0xf7)
|
||||||
(u8)b->clusters_per_mft_record > 0xf7) {
|
{
|
||||||
switch (b->clusters_per_mft_record) {
|
switch (b->clusters_per_mft_record)
|
||||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
case 0x10:
|
||||||
|
case 0x20:
|
||||||
|
case 0x40:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ntfs_log_error("Unexpected clusters per mft record "
|
ntfs_log_error("Unexpected clusters per mft record "
|
||||||
@ -128,10 +141,17 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug("Checking clusters per index block.\n");
|
ntfs_log_debug("Checking clusters per index block.\n");
|
||||||
if ((u8)b->clusters_per_index_record < 0xe1 ||
|
if ((u8) b->clusters_per_index_record < 0xe1 || (u8) b->clusters_per_index_record > 0xf7)
|
||||||
(u8)b->clusters_per_index_record > 0xf7) {
|
{
|
||||||
switch (b->clusters_per_index_record) {
|
switch (b->clusters_per_index_record)
|
||||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
case 0x10:
|
||||||
|
case 0x20:
|
||||||
|
case 0x40:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ntfs_log_error("Unexpected clusters per index record "
|
ntfs_log_error("Unexpected clusters per index record "
|
||||||
@ -147,16 +167,14 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
|||||||
ntfs_log_debug("Bootsector check completed successfully.\n");
|
ntfs_log_debug("Bootsector check completed successfully.\n");
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
not_ntfs:
|
not_ntfs: return ret;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *last_sector_error =
|
static const char *last_sector_error = "HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\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 it was not setup correctly (e.g. by not using mdadm --build ...),\n"
|
" or a wrong device is tried to be mounted,\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 partition table is corrupt (partition is smaller than NTFS),\n"
|
" or the NTFS boot sector is corrupt (NTFS size is not valid).\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
|
* ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
|
||||||
@ -188,7 +206,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
*/
|
*/
|
||||||
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
||||||
ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
|
ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
|
||||||
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
|
if (sectors_per_cluster & (sectors_per_cluster - 1))
|
||||||
|
{
|
||||||
ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
|
ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
|
||||||
"\n", sectors_per_cluster);
|
"\n", sectors_per_cluster);
|
||||||
return -1;
|
return -1;
|
||||||
@ -196,13 +215,13 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
|
|
||||||
sectors = sle64_to_cpu(bs->number_of_sectors);
|
sectors = sle64_to_cpu(bs->number_of_sectors);
|
||||||
ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
|
ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
|
||||||
if (!sectors) {
|
if (!sectors)
|
||||||
|
{
|
||||||
ntfs_log_error("Volume size is set to zero.\n");
|
ntfs_log_error("Volume size is set to zero.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (vol->dev->d_ops->seek(vol->dev,
|
if (vol->dev->d_ops->seek(vol->dev, (sectors - 1) << vol->sector_size_bits, SEEK_SET) == -1)
|
||||||
(sectors - 1) << vol->sector_size_bits,
|
{
|
||||||
SEEK_SET) == -1) {
|
|
||||||
ntfs_log_perror("Failed to read last sector (%lld)",
|
ntfs_log_perror("Failed to read last sector (%lld)",
|
||||||
(long long)sectors);
|
(long long)sectors);
|
||||||
ntfs_log_error("%s", last_sector_error);
|
ntfs_log_error("%s", last_sector_error);
|
||||||
@ -215,8 +234,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_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("MFT LCN = %lld\n", (long long)vol->mft_lcn);
|
||||||
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
||||||
if (vol->mft_lcn > vol->nr_clusters ||
|
if (vol->mft_lcn > vol->nr_clusters || vol->mftmirr_lcn > vol->nr_clusters)
|
||||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
{
|
||||||
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||||
"greater than the number of clusters (%lld).\n",
|
"greater than the number of clusters (%lld).\n",
|
||||||
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
|
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
|
||||||
@ -225,7 +244,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||||
if (vol->cluster_size & (vol->cluster_size - 1)) {
|
if (vol->cluster_size & (vol->cluster_size - 1))
|
||||||
|
{
|
||||||
ntfs_log_error("cluster_size (%d) is not a power of 2.\n",
|
ntfs_log_error("cluster_size (%d) is not a power of 2.\n",
|
||||||
vol->cluster_size);
|
vol->cluster_size);
|
||||||
return -1;
|
return -1;
|
||||||
@ -248,9 +268,9 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
*/
|
*/
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
vol->mft_record_size = 1 << -c;
|
vol->mft_record_size = 1 << -c;
|
||||||
else
|
else vol->mft_record_size = c << vol->cluster_size_bits;
|
||||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
if (vol->mft_record_size & (vol->mft_record_size - 1))
|
||||||
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
|
{
|
||||||
ntfs_log_error("mft_record_size (%d) is not a power of 2.\n",
|
ntfs_log_error("mft_record_size (%d) is not a power of 2.\n",
|
||||||
vol->mft_record_size);
|
vol->mft_record_size);
|
||||||
return -1;
|
return -1;
|
||||||
@ -263,8 +283,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
|
ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
vol->indx_record_size = 1 << -c;
|
vol->indx_record_size = 1 << -c;
|
||||||
else
|
else vol->indx_record_size = c << vol->cluster_size_bits;
|
||||||
vol->indx_record_size = c << vol->cluster_size_bits;
|
|
||||||
vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
|
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("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
|
||||||
ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
|
ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
|
||||||
@ -278,8 +297,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
|||||||
*/
|
*/
|
||||||
if (vol->cluster_size <= 4 * vol->mft_record_size)
|
if (vol->cluster_size <= 4 * vol->mft_record_size)
|
||||||
vol->mftmirr_size = 4;
|
vol->mftmirr_size = 4;
|
||||||
else
|
else vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,38 +60,43 @@
|
|||||||
* Do not call when a record has been modified (with no key change)
|
* Do not call when a record has been modified (with no key change)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void inserthashindex(struct CACHE_HEADER *cache,
|
static void inserthashindex(struct CACHE_HEADER *cache, struct CACHED_GENERIC *current)
|
||||||
struct CACHED_GENERIC *current)
|
|
||||||
{
|
{
|
||||||
int h;
|
int h;
|
||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
struct HASH_ENTRY *first;
|
struct HASH_ENTRY *first;
|
||||||
|
|
||||||
if (cache->dohash) {
|
if (cache->dohash)
|
||||||
|
{
|
||||||
h = cache->dohash(current);
|
h = cache->dohash(current);
|
||||||
if ((h >= 0) && (h < cache->max_hash)) {
|
if ((h >= 0) && (h < cache->max_hash))
|
||||||
|
{
|
||||||
/* get a free link and insert at top of hash list */
|
/* get a free link and insert at top of hash list */
|
||||||
link = cache->free_hash;
|
link = cache->free_hash;
|
||||||
if (link) {
|
if (link)
|
||||||
|
{
|
||||||
cache->free_hash = link->next;
|
cache->free_hash = link->next;
|
||||||
first = cache->first_hash[h];
|
first = cache->first_hash[h];
|
||||||
if (first)
|
if (first)
|
||||||
link->next = first;
|
link->next = first;
|
||||||
else
|
else link->next = NULL;
|
||||||
link->next = NULL;
|
|
||||||
link->entry = current;
|
link->entry = current;
|
||||||
cache->first_hash[h] = link;
|
cache->first_hash[h] = link;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error("No more hash entries,"
|
ntfs_log_error("No more hash entries,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name);
|
cache->name);
|
||||||
cache->dohash = (cache_hash)NULL;
|
cache->dohash = (cache_hash) NULL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error("Illegal hash value,"
|
ntfs_log_error("Illegal hash value,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name);
|
cache->name);
|
||||||
cache->dohash = (cache_hash)NULL;
|
cache->dohash = (cache_hash) NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,39 +105,45 @@ static void inserthashindex(struct CACHE_HEADER *cache,
|
|||||||
* Drop a hash index when a record is about to be deleted
|
* Drop a hash index when a record is about to be deleted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void drophashindex(struct CACHE_HEADER *cache,
|
static void drophashindex(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *current, int hash)
|
||||||
const struct CACHED_GENERIC *current, int hash)
|
|
||||||
{
|
{
|
||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
struct HASH_ENTRY *previous;
|
struct HASH_ENTRY *previous;
|
||||||
|
|
||||||
if (cache->dohash) {
|
if (cache->dohash)
|
||||||
if ((hash >= 0) && (hash < cache->max_hash)) {
|
{
|
||||||
|
if ((hash >= 0) && (hash < cache->max_hash))
|
||||||
|
{
|
||||||
/* find the link and unlink */
|
/* find the link and unlink */
|
||||||
link = cache->first_hash[hash];
|
link = cache->first_hash[hash];
|
||||||
previous = (struct HASH_ENTRY*)NULL;
|
previous = (struct HASH_ENTRY*) NULL;
|
||||||
while (link && (link->entry != current)) {
|
while (link && (link->entry != current))
|
||||||
|
{
|
||||||
previous = link;
|
previous = link;
|
||||||
link = link->next;
|
link = link->next;
|
||||||
}
|
}
|
||||||
if (link) {
|
if (link)
|
||||||
|
{
|
||||||
if (previous)
|
if (previous)
|
||||||
previous->next = link->next;
|
previous->next = link->next;
|
||||||
else
|
else cache->first_hash[hash] = link->next;
|
||||||
cache->first_hash[hash] = link->next;
|
|
||||||
link->next = cache->free_hash;
|
link->next = cache->free_hash;
|
||||||
cache->free_hash = link;
|
cache->free_hash = link;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error("Bad hash list,"
|
ntfs_log_error("Bad hash list,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name);
|
cache->name);
|
||||||
cache->dohash = (cache_hash)NULL;
|
cache->dohash = (cache_hash) NULL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error("Illegal hash value,"
|
ntfs_log_error("Illegal hash value,"
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name);
|
cache->name);
|
||||||
cache->dohash = (cache_hash)NULL;
|
cache->dohash = (cache_hash) NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,17 +155,19 @@ static void drophashindex(struct CACHE_HEADER *cache,
|
|||||||
* The returned entry may be modified, but not freed
|
* The returned entry may be modified, but not freed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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,
|
||||||
const struct CACHED_GENERIC *wanted, cache_compare compare)
|
cache_compare compare)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *current;
|
struct CACHED_GENERIC *current;
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = (struct CACHED_GENERIC*)NULL;
|
current = (struct CACHED_GENERIC*) NULL;
|
||||||
if (cache) {
|
if (cache)
|
||||||
if (cache->dohash) {
|
{
|
||||||
|
if (cache->dohash)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* locate the entry if present
|
* locate the entry if present
|
||||||
@ -163,38 +176,36 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
|||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while (link && compare(link->entry, wanted))
|
while (link && compare(link->entry, wanted))
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if (link)
|
if (link) current = link->entry;
|
||||||
current = link->entry;
|
|
||||||
}
|
}
|
||||||
if (!cache->dohash) {
|
if (!cache->dohash)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list if no hash table
|
* Search sequentially in LRU list if no hash table
|
||||||
* or if hashing has just failed
|
* or if hashing has just failed
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
while (current
|
while (current && compare(current, wanted))
|
||||||
&& compare(current, wanted)) {
|
{
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (current) {
|
if (current)
|
||||||
|
{
|
||||||
previous = current->previous;
|
previous = current->previous;
|
||||||
cache->hits++;
|
cache->hits++;
|
||||||
if (previous) {
|
if (previous)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* found and not at head of list, unlink from current
|
* found and not at head of list, unlink from current
|
||||||
* position and relink as head of list
|
* position and relink as head of list
|
||||||
*/
|
*/
|
||||||
previous->next = current->next;
|
previous->next = current->next;
|
||||||
if (current->next)
|
if (current->next)
|
||||||
current->next->previous
|
current->next->previous = current->previous;
|
||||||
= current->previous;
|
else cache->oldest_entry = current->previous;
|
||||||
else
|
|
||||||
cache->oldest_entry
|
|
||||||
= current->previous;
|
|
||||||
current->next = cache->most_recent_entry;
|
current->next = cache->most_recent_entry;
|
||||||
current->previous
|
current->previous = (struct CACHED_GENERIC*) NULL;
|
||||||
= (struct CACHED_GENERIC*)NULL;
|
|
||||||
cache->most_recent_entry->previous = current;
|
cache->most_recent_entry->previous = current;
|
||||||
cache->most_recent_entry = current;
|
cache->most_recent_entry = current;
|
||||||
}
|
}
|
||||||
@ -209,8 +220,7 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
|||||||
* returns the cache entry or NULL if not possible
|
* 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,
|
||||||
const struct CACHED_GENERIC *item,
|
|
||||||
cache_compare compare)
|
cache_compare compare)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *current;
|
struct CACHED_GENERIC *current;
|
||||||
@ -218,9 +228,11 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = (struct CACHED_GENERIC*)NULL;
|
current = (struct CACHED_GENERIC*) NULL;
|
||||||
if (cache) {
|
if (cache)
|
||||||
if (cache->dohash) {
|
{
|
||||||
|
if (cache->dohash)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* find out whether the entry if present
|
* find out whether the entry if present
|
||||||
@ -229,11 +241,13 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while (link && compare(link->entry, item))
|
while (link && compare(link->entry, item))
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if (link) {
|
if (link)
|
||||||
|
{
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cache->dohash) {
|
if (!cache->dohash)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list to locate the end,
|
* Search sequentially in LRU list to locate the end,
|
||||||
* and find out whether the entry is already in list
|
* and find out whether the entry is already in list
|
||||||
@ -241,13 +255,14 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
* kept.
|
* kept.
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
while (current
|
while (current && compare(current, item))
|
||||||
&& compare(current, item)) {
|
{
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current) {
|
if (!current)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Not in list, get a free entry or reuse the
|
* Not in list, get a free entry or reuse the
|
||||||
* last entry, and relink as head of list
|
* last entry, and relink as head of list
|
||||||
@ -256,54 +271,53 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
* an entry is reused.
|
* an entry is reused.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (cache->free_entry) {
|
if (cache->free_entry)
|
||||||
|
{
|
||||||
current = cache->free_entry;
|
current = cache->free_entry;
|
||||||
cache->free_entry = cache->free_entry->next;
|
cache->free_entry = cache->free_entry->next;
|
||||||
if (item->varsize) {
|
if (item->varsize)
|
||||||
current->variable = ntfs_malloc(
|
{
|
||||||
item->varsize);
|
current->variable = ntfs_malloc(item->varsize);
|
||||||
} else
|
}
|
||||||
current->variable = (void*)NULL;
|
else current->variable = (void*) NULL;
|
||||||
current->varsize = item->varsize;
|
current->varsize = item->varsize;
|
||||||
if (!cache->oldest_entry)
|
if (!cache->oldest_entry) cache->oldest_entry = current;
|
||||||
cache->oldest_entry = current;
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
/* reusing the oldest entry */
|
/* reusing the oldest entry */
|
||||||
current = cache->oldest_entry;
|
current = cache->oldest_entry;
|
||||||
before = current->previous;
|
before = current->previous;
|
||||||
before->next = (struct CACHED_GENERIC*)NULL;
|
before->next = (struct CACHED_GENERIC*) NULL;
|
||||||
if (cache->dohash)
|
if (cache->dohash) drophashindex(cache, current, cache->dohash(current));
|
||||||
drophashindex(cache,current,
|
if (cache->dofree) cache->dofree(current);
|
||||||
cache->dohash(current));
|
|
||||||
if (cache->dofree)
|
|
||||||
cache->dofree(current);
|
|
||||||
cache->oldest_entry = current->previous;
|
cache->oldest_entry = current->previous;
|
||||||
if (item->varsize) {
|
if (item->varsize)
|
||||||
|
{
|
||||||
if (current->varsize)
|
if (current->varsize)
|
||||||
current->variable = realloc(
|
current->variable = realloc(current->variable, item->varsize);
|
||||||
current->variable,
|
else current->variable = ntfs_malloc(item->varsize);
|
||||||
item->varsize);
|
}
|
||||||
else
|
else
|
||||||
current->variable = ntfs_malloc(
|
{
|
||||||
item->varsize);
|
if (current->varsize) free(current->variable);
|
||||||
} else {
|
current->variable = (void*) NULL;
|
||||||
if (current->varsize)
|
|
||||||
free(current->variable);
|
|
||||||
current->variable = (void*)NULL;
|
|
||||||
}
|
}
|
||||||
current->varsize = item->varsize;
|
current->varsize = item->varsize;
|
||||||
}
|
}
|
||||||
current->next = cache->most_recent_entry;
|
current->next = cache->most_recent_entry;
|
||||||
current->previous = (struct CACHED_GENERIC*)NULL;
|
current->previous = (struct CACHED_GENERIC*) NULL;
|
||||||
if (cache->most_recent_entry)
|
if (cache->most_recent_entry) cache->most_recent_entry->previous = current;
|
||||||
cache->most_recent_entry->previous = current;
|
|
||||||
cache->most_recent_entry = current;
|
cache->most_recent_entry = current;
|
||||||
memcpy(current->fixed, item->fixed, cache->fixed_size);
|
memcpy(current->fixed, item->fixed, cache->fixed_size);
|
||||||
if (item->varsize) {
|
if (item->varsize)
|
||||||
if (current->variable) {
|
{
|
||||||
memcpy(current->variable,
|
if (current->variable)
|
||||||
item->variable, item->varsize);
|
{
|
||||||
} else {
|
memcpy(current->variable, item->variable, item->varsize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* no more memory for variable part
|
* no more memory for variable part
|
||||||
* recycle entry in free list
|
* recycle entry in free list
|
||||||
@ -312,14 +326,15 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
cache->most_recent_entry = current->next;
|
cache->most_recent_entry = current->next;
|
||||||
current->next = cache->free_entry;
|
current->next = cache->free_entry;
|
||||||
cache->free_entry = current;
|
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;
|
current->varsize = 0;
|
||||||
}
|
}
|
||||||
if (cache->dohash && current)
|
if (cache->dohash && current) inserthashindex(cache, current);
|
||||||
inserthashindex(cache,current);
|
|
||||||
}
|
}
|
||||||
cache->writes++;
|
cache->writes++;
|
||||||
}
|
}
|
||||||
@ -332,32 +347,26 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
|||||||
* A specific function may be called for entry deletion
|
* A specific function may be called for entry deletion
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void do_invalidate(struct CACHE_HEADER *cache,
|
static void do_invalidate(struct CACHE_HEADER *cache, struct CACHED_GENERIC *current, int flags)
|
||||||
struct CACHED_GENERIC *current, int flags)
|
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
|
|
||||||
previous = current->previous;
|
previous = current->previous;
|
||||||
if ((flags & CACHE_FREE) && cache->dofree)
|
if ((flags & CACHE_FREE) && cache->dofree) cache->dofree(current);
|
||||||
cache->dofree(current);
|
|
||||||
/*
|
/*
|
||||||
* Relink into free list
|
* Relink into free list
|
||||||
*/
|
*/
|
||||||
if (current->next)
|
if (current->next)
|
||||||
current->next->previous = current->previous;
|
current->next->previous = current->previous;
|
||||||
else
|
else cache->oldest_entry = current->previous;
|
||||||
cache->oldest_entry = current->previous;
|
|
||||||
if (previous)
|
if (previous)
|
||||||
previous->next = current->next;
|
previous->next = current->next;
|
||||||
else
|
else cache->most_recent_entry = current->next;
|
||||||
cache->most_recent_entry = current->next;
|
|
||||||
current->next = cache->free_entry;
|
current->next = cache->free_entry;
|
||||||
cache->free_entry = current;
|
cache->free_entry = current;
|
||||||
if (current->variable)
|
if (current->variable) free(current->variable);
|
||||||
free(current->variable);
|
|
||||||
current->varsize = 0;
|
current->varsize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invalidate entries in cache
|
* Invalidate entries in cache
|
||||||
@ -371,8 +380,7 @@ static void do_invalidate(struct CACHE_HEADER *cache,
|
|||||||
* supposed to be found.
|
* 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,
|
||||||
const struct CACHED_GENERIC *item, cache_compare compare,
|
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *current;
|
struct CACHED_GENERIC *current;
|
||||||
@ -382,47 +390,54 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
|||||||
int count;
|
int count;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = (struct CACHED_GENERIC*)NULL;
|
current = (struct CACHED_GENERIC*) NULL;
|
||||||
count = 0;
|
count = 0;
|
||||||
if (cache) {
|
if (cache)
|
||||||
if (!(flags & CACHE_NOHASH) && cache->dohash) {
|
{
|
||||||
|
if (!(flags & CACHE_NOHASH) && cache->dohash)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* find out whether the entry if present
|
* find out whether the entry if present
|
||||||
*/
|
*/
|
||||||
h = cache->dohash(item);
|
h = cache->dohash(item);
|
||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while (link) {
|
while (link)
|
||||||
|
{
|
||||||
if (compare(link->entry, item))
|
if (compare(link->entry, item))
|
||||||
link = link->next;
|
link = link->next;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if (current) {
|
if (current)
|
||||||
drophashindex(cache,current,h);
|
{
|
||||||
do_invalidate(cache,
|
drophashindex(cache, current, h);
|
||||||
current,flags);
|
do_invalidate(cache, current, flags);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((flags & CACHE_NOHASH) || !cache->dohash) {
|
if ((flags & CACHE_NOHASH) || !cache->dohash)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list
|
* Search sequentially in LRU list
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
previous = (struct CACHED_GENERIC*)NULL;
|
previous = (struct CACHED_GENERIC*) NULL;
|
||||||
while (current) {
|
while (current)
|
||||||
if (!compare(current, item)) {
|
{
|
||||||
|
if (!compare(current, item))
|
||||||
|
{
|
||||||
next = current->next;
|
next = current->next;
|
||||||
if (cache->dohash)
|
if (cache->dohash) drophashindex(cache, current, cache->dohash(current));
|
||||||
drophashindex(cache,current,
|
do_invalidate(cache, current, flags);
|
||||||
cache->dohash(current));
|
|
||||||
do_invalidate(cache,current,flags);
|
|
||||||
current = next;
|
current = next;
|
||||||
count++;
|
count++;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
previous = current;
|
previous = current;
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
@ -432,16 +447,15 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
|||||||
return (count);
|
return (count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
int ntfs_remove_cache(struct CACHE_HEADER *cache, struct CACHED_GENERIC *item, int flags)
|
||||||
struct CACHED_GENERIC *item, int flags)
|
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
if (cache) {
|
if (cache)
|
||||||
if (cache->dohash)
|
{
|
||||||
drophashindex(cache,item,cache->dohash(item));
|
if (cache->dohash) drophashindex(cache, item, cache->dohash(item));
|
||||||
do_invalidate(cache,item,flags);
|
do_invalidate(cache, item, flags);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return (count);
|
return (count);
|
||||||
@ -455,12 +469,12 @@ static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
|||||||
{
|
{
|
||||||
struct CACHED_GENERIC *entry;
|
struct CACHED_GENERIC *entry;
|
||||||
|
|
||||||
if (cache) {
|
if (cache)
|
||||||
for (entry=cache->most_recent_entry; entry; entry=entry->next) {
|
{
|
||||||
if (cache->dofree)
|
for (entry = cache->most_recent_entry; entry; entry = entry->next)
|
||||||
cache->dofree(entry);
|
{
|
||||||
if (entry->variable)
|
if (cache->dofree) cache->dofree(entry);
|
||||||
free(entry->variable);
|
if (entry->variable) free(entry->variable);
|
||||||
}
|
}
|
||||||
free(cache);
|
free(cache);
|
||||||
}
|
}
|
||||||
@ -472,10 +486,8 @@ static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
|||||||
* Returns the cache header, or NULL if the cache could not be created
|
* 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,
|
||||||
cache_free dofree, cache_hash dohash,
|
int full_item_size, int item_count, int max_hash)
|
||||||
int full_item_size,
|
|
||||||
int item_count, int max_hash)
|
|
||||||
{
|
{
|
||||||
struct CACHE_HEADER *cache;
|
struct CACHE_HEADER *cache;
|
||||||
struct CACHED_GENERIC *pc;
|
struct CACHED_GENERIC *pc;
|
||||||
@ -486,20 +498,22 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
|||||||
size_t size;
|
size_t size;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
size = sizeof(struct CACHE_HEADER) + item_count*full_item_size;
|
size = sizeof(struct CACHE_HEADER) + item_count * full_item_size;
|
||||||
if (max_hash)
|
if (max_hash) size += item_count * sizeof(struct HASH_ENTRY) + max_hash * sizeof(struct HASH_ENTRY*);
|
||||||
size += item_count*sizeof(struct HASH_ENTRY)
|
cache = (struct CACHE_HEADER*) ntfs_malloc(size);
|
||||||
+ max_hash*sizeof(struct HASH_ENTRY*);
|
if (cache)
|
||||||
cache = (struct CACHE_HEADER*)ntfs_malloc(size);
|
{
|
||||||
if (cache) {
|
|
||||||
/* header */
|
/* header */
|
||||||
cache->name = name;
|
cache->name = name;
|
||||||
cache->dofree = dofree;
|
cache->dofree = dofree;
|
||||||
if (dohash && max_hash) {
|
if (dohash && max_hash)
|
||||||
|
{
|
||||||
cache->dohash = dohash;
|
cache->dohash = dohash;
|
||||||
cache->max_hash = max_hash;
|
cache->max_hash = max_hash;
|
||||||
} else {
|
}
|
||||||
cache->dohash = (cache_hash)NULL;
|
else
|
||||||
|
{
|
||||||
|
cache->dohash = (cache_hash) NULL;
|
||||||
cache->max_hash = 0;
|
cache->max_hash = 0;
|
||||||
}
|
}
|
||||||
cache->fixed_size = full_item_size - sizeof(struct CACHED_GENERIC);
|
cache->fixed_size = full_item_size - sizeof(struct CACHED_GENERIC);
|
||||||
@ -507,44 +521,49 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
|||||||
cache->writes = 0;
|
cache->writes = 0;
|
||||||
cache->hits = 0;
|
cache->hits = 0;
|
||||||
/* chain the data entries, and mark an invalid entry */
|
/* chain the data entries, and mark an invalid entry */
|
||||||
cache->most_recent_entry = (struct CACHED_GENERIC*)NULL;
|
cache->most_recent_entry = (struct CACHED_GENERIC*) NULL;
|
||||||
cache->oldest_entry = (struct CACHED_GENERIC*)NULL;
|
cache->oldest_entry = (struct CACHED_GENERIC*) NULL;
|
||||||
cache->free_entry = &cache->entry[0];
|
cache->free_entry = &cache->entry[0];
|
||||||
pc = &cache->entry[0];
|
pc = &cache->entry[0];
|
||||||
for (i=0; i<(item_count - 1); i++) {
|
for (i = 0; i < (item_count - 1); i++)
|
||||||
qc = (struct CACHED_GENERIC*)((char*)pc
|
{
|
||||||
+ full_item_size);
|
qc = (struct CACHED_GENERIC*) ((char*) pc + full_item_size);
|
||||||
pc->next = qc;
|
pc->next = qc;
|
||||||
pc->variable = (void*)NULL;
|
pc->variable = (void*) NULL;
|
||||||
pc->varsize = 0;
|
pc->varsize = 0;
|
||||||
pc = qc;
|
pc = qc;
|
||||||
}
|
}
|
||||||
/* special for the last entry */
|
/* special for the last entry */
|
||||||
pc->next = (struct CACHED_GENERIC*)NULL;
|
pc->next = (struct CACHED_GENERIC*) NULL;
|
||||||
pc->variable = (void*)NULL;
|
pc->variable = (void*) NULL;
|
||||||
pc->varsize = 0;
|
pc->varsize = 0;
|
||||||
|
|
||||||
if (max_hash) {
|
if (max_hash)
|
||||||
|
{
|
||||||
/* chain the hash entries */
|
/* 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;
|
cache->free_hash = ph;
|
||||||
for (i=0; i<(item_count - 1); i++) {
|
for (i = 0; i < (item_count - 1); i++)
|
||||||
|
{
|
||||||
qh = &ph[1];
|
qh = &ph[1];
|
||||||
ph->next = qh;
|
ph->next = qh;
|
||||||
ph = qh;
|
ph = qh;
|
||||||
}
|
}
|
||||||
/* special for the last entry */
|
/* special for the last entry */
|
||||||
if (item_count) {
|
if (item_count)
|
||||||
ph->next = (struct HASH_ENTRY*)NULL;
|
{
|
||||||
|
ph->next = (struct HASH_ENTRY*) NULL;
|
||||||
}
|
}
|
||||||
/* create and initialize the hash indexes */
|
/* create and initialize the hash indexes */
|
||||||
px = (struct HASH_ENTRY**)&ph[1];
|
px = (struct HASH_ENTRY**) &ph[1];
|
||||||
cache->first_hash = px;
|
cache->first_hash = px;
|
||||||
for (i=0; i<max_hash; i++)
|
for (i = 0; i < max_hash; i++)
|
||||||
px[i] = (struct HASH_ENTRY*)NULL;
|
px[i] = (struct HASH_ENTRY*) NULL;
|
||||||
} else {
|
}
|
||||||
cache->free_hash = (struct HASH_ENTRY*)NULL;
|
else
|
||||||
cache->first_hash = (struct HASH_ENTRY**)NULL;
|
{
|
||||||
|
cache->free_hash = (struct HASH_ENTRY*) NULL;
|
||||||
|
cache->first_hash = (struct HASH_ENTRY**) NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (cache);
|
return (cache);
|
||||||
@ -561,29 +580,24 @@ void ntfs_create_lru_caches(ntfs_volume *vol)
|
|||||||
{
|
{
|
||||||
#if CACHE_INODE_SIZE
|
#if CACHE_INODE_SIZE
|
||||||
/* inode cache */
|
/* inode cache */
|
||||||
vol->xinode_cache = ntfs_create_cache("inode",(cache_free)NULL,
|
vol->xinode_cache = ntfs_create_cache("inode", (cache_free) NULL, ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
|
||||||
ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
|
CACHE_INODE_SIZE, 2 * CACHE_INODE_SIZE);
|
||||||
CACHE_INODE_SIZE, 2*CACHE_INODE_SIZE);
|
|
||||||
#endif
|
#endif
|
||||||
#if CACHE_NIDATA_SIZE
|
#if CACHE_NIDATA_SIZE
|
||||||
/* idata cache */
|
/* idata cache */
|
||||||
vol->nidata_cache = ntfs_create_cache("nidata",
|
vol->nidata_cache = ntfs_create_cache("nidata", ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
|
||||||
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
|
#endif
|
||||||
#if CACHE_LOOKUP_SIZE
|
#if CACHE_LOOKUP_SIZE
|
||||||
/* lookup cache */
|
/* lookup cache */
|
||||||
vol->lookup_cache = ntfs_create_cache("lookup",
|
vol->lookup_cache = ntfs_create_cache("lookup", (cache_free) NULL, ntfs_dir_lookup_hash,
|
||||||
(cache_free)NULL, ntfs_dir_lookup_hash,
|
sizeof(struct CACHED_LOOKUP), CACHE_LOOKUP_SIZE, 2 * CACHE_LOOKUP_SIZE);
|
||||||
sizeof(struct CACHED_LOOKUP),
|
|
||||||
CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE);
|
|
||||||
#endif
|
#endif
|
||||||
vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL,
|
vol->securid_cache = ntfs_create_cache("securid", (cache_free) NULL, (cache_hash) NULL,
|
||||||
(cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
|
sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
|
||||||
#if CACHE_LEGACY_SIZE
|
#if CACHE_LEGACY_SIZE
|
||||||
vol->legacy_cache = ntfs_create_cache("legacy",(cache_free)NULL,
|
vol->legacy_cache = ntfs_create_cache("legacy", (cache_free) NULL, (cache_hash) NULL,
|
||||||
(cache_hash)NULL, sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0);
|
sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,28 +24,32 @@
|
|||||||
|
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
|
|
||||||
struct CACHED_GENERIC {
|
struct CACHED_GENERIC
|
||||||
|
{
|
||||||
struct CACHED_GENERIC *next;
|
struct CACHED_GENERIC *next;
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
void *variable;
|
void *variable;
|
||||||
size_t varsize;
|
size_t varsize;
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
/* force alignment for pointers and u64 */
|
/* force alignment for pointers and u64 */
|
||||||
u64 u64align;
|
u64 u64align;
|
||||||
void *ptralign;
|
void *ptralign;
|
||||||
} fixed[0];
|
} fixed[0];
|
||||||
} ;
|
};
|
||||||
|
|
||||||
struct CACHED_INODE {
|
struct CACHED_INODE
|
||||||
|
{
|
||||||
struct CACHED_INODE *next;
|
struct CACHED_INODE *next;
|
||||||
struct CACHED_INODE *previous;
|
struct CACHED_INODE *previous;
|
||||||
const char *pathname;
|
const char *pathname;
|
||||||
size_t varsize;
|
size_t varsize;
|
||||||
/* above fields must match "struct CACHED_GENERIC" */
|
/* above fields must match "struct CACHED_GENERIC" */
|
||||||
u64 inum;
|
u64 inum;
|
||||||
} ;
|
};
|
||||||
|
|
||||||
struct CACHED_NIDATA {
|
struct CACHED_NIDATA
|
||||||
|
{
|
||||||
struct CACHED_NIDATA *next;
|
struct CACHED_NIDATA *next;
|
||||||
struct CACHED_NIDATA *previous;
|
struct CACHED_NIDATA *previous;
|
||||||
const char *pathname; /* not used */
|
const char *pathname; /* not used */
|
||||||
@ -53,9 +57,10 @@ struct CACHED_NIDATA {
|
|||||||
/* above fields must match "struct CACHED_GENERIC" */
|
/* above fields must match "struct CACHED_GENERIC" */
|
||||||
u64 inum;
|
u64 inum;
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
} ;
|
};
|
||||||
|
|
||||||
struct CACHED_LOOKUP {
|
struct CACHED_LOOKUP
|
||||||
|
{
|
||||||
struct CACHED_LOOKUP *next;
|
struct CACHED_LOOKUP *next;
|
||||||
struct CACHED_LOOKUP *previous;
|
struct CACHED_LOOKUP *previous;
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -63,24 +68,25 @@ struct CACHED_LOOKUP {
|
|||||||
/* above fields must match "struct CACHED_GENERIC" */
|
/* above fields must match "struct CACHED_GENERIC" */
|
||||||
u64 parent;
|
u64 parent;
|
||||||
u64 inum;
|
u64 inum;
|
||||||
} ;
|
};
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
CACHE_FREE = 1,
|
{
|
||||||
CACHE_NOHASH = 2
|
CACHE_FREE = 1, CACHE_NOHASH = 2
|
||||||
} ;
|
};
|
||||||
|
|
||||||
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
|
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached, const struct CACHED_GENERIC *item);
|
||||||
const struct CACHED_GENERIC *item);
|
|
||||||
typedef void (*cache_free)(const struct CACHED_GENERIC *cached);
|
typedef void (*cache_free)(const struct CACHED_GENERIC *cached);
|
||||||
typedef int (*cache_hash)(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 HASH_ENTRY *next;
|
||||||
struct CACHED_GENERIC *entry;
|
struct CACHED_GENERIC *entry;
|
||||||
} ;
|
};
|
||||||
|
|
||||||
struct CACHE_HEADER {
|
struct CACHE_HEADER
|
||||||
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
struct CACHED_GENERIC *most_recent_entry;
|
struct CACHED_GENERIC *most_recent_entry;
|
||||||
struct CACHED_GENERIC *oldest_entry;
|
struct CACHED_GENERIC *oldest_entry;
|
||||||
@ -95,22 +101,18 @@ struct CACHE_HEADER {
|
|||||||
int fixed_size;
|
int fixed_size;
|
||||||
int max_hash;
|
int max_hash;
|
||||||
struct CACHED_GENERIC entry[0];
|
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))
|
#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,
|
||||||
const struct CACHED_GENERIC *wanted,
|
|
||||||
cache_compare compare);
|
cache_compare compare);
|
||||||
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,
|
||||||
const struct CACHED_GENERIC *item,
|
|
||||||
cache_compare compare);
|
cache_compare compare);
|
||||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
int ntfs_invalidate_cache(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *item, cache_compare compare,
|
||||||
const 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);
|
||||||
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
|
||||||
struct CACHED_GENERIC *item, int flags);
|
|
||||||
|
|
||||||
void ntfs_create_lru_caches(ntfs_volume *vol);
|
void ntfs_create_lru_caches(ntfs_volume *vol);
|
||||||
void ntfs_free_lru_caches(ntfs_volume *vol);
|
void ntfs_free_lru_caches(ntfs_volume *vol);
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ogc/lwp_watchdog.h>
|
#include <ogc/lwp_watchdog.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -45,23 +45,28 @@
|
|||||||
|
|
||||||
#define CACHE_FREE UINT_MAX
|
#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;
|
NTFS_CACHE* cache;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries;
|
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;
|
numberOfPages = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sectorsPerPage < 32) {
|
if (sectorsPerPage < 32)
|
||||||
|
{
|
||||||
sectorsPerPage = 32;
|
sectorsPerPage = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = (NTFS_CACHE*) ntfs_alloc (sizeof(NTFS_CACHE));
|
cache = (NTFS_CACHE*) ntfs_alloc(sizeof(NTFS_CACHE));
|
||||||
if (cache == NULL) {
|
if (cache == NULL)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,19 +76,20 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
|||||||
cache->sectorsPerPage = sectorsPerPage;
|
cache->sectorsPerPage = sectorsPerPage;
|
||||||
cache->sectorSize = sectorSize;
|
cache->sectorSize = sectorSize;
|
||||||
|
|
||||||
|
cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc(sizeof(NTFS_CACHE_ENTRY) * numberOfPages);
|
||||||
cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc ( sizeof(NTFS_CACHE_ENTRY) * numberOfPages);
|
if (cacheEntries == NULL)
|
||||||
if (cacheEntries == NULL) {
|
{
|
||||||
ntfs_free (cache);
|
ntfs_free(cache);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < numberOfPages; i++) {
|
for (i = 0; i < numberOfPages; i++)
|
||||||
|
{
|
||||||
cacheEntries[i].sector = CACHE_FREE;
|
cacheEntries[i].sector = CACHE_FREE;
|
||||||
cacheEntries[i].count = 0;
|
cacheEntries[i].count = 0;
|
||||||
cacheEntries[i].last_access = 0;
|
cacheEntries[i].last_access = 0;
|
||||||
cacheEntries[i].dirty = false;
|
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;
|
cache->cacheEntries = cacheEntries;
|
||||||
@ -91,30 +97,33 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
void _NTFS_cache_destructor(NTFS_CACHE* cache)
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if(cache==NULL) return;
|
if (cache == NULL) return;
|
||||||
|
|
||||||
// Clear out cache before destroying it
|
// Clear out cache before destroying it
|
||||||
_NTFS_cache_flush(cache);
|
_NTFS_cache_flush(cache);
|
||||||
|
|
||||||
// Free memory in reverse allocation order
|
// Free memory in reverse allocation order
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
ntfs_free (cache->cacheEntries[i].cache);
|
{
|
||||||
|
ntfs_free(cache->cacheEntries[i].cache);
|
||||||
}
|
}
|
||||||
ntfs_free (cache->cacheEntries);
|
ntfs_free(cache->cacheEntries);
|
||||||
ntfs_free (cache);
|
ntfs_free(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 accessCounter = 0;
|
static u32 accessCounter = 0;
|
||||||
|
|
||||||
static u32 accessTime(){
|
static u32 accessTime()
|
||||||
|
{
|
||||||
accessCounter++;
|
accessCounter++;
|
||||||
return 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;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
@ -125,37 +134,43 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
|||||||
unsigned int oldUsed = 0;
|
unsigned int oldUsed = 0;
|
||||||
unsigned int oldAccess = UINT_MAX;
|
unsigned int oldAccess = UINT_MAX;
|
||||||
|
|
||||||
for(i=0;i<numberOfPages;i++) {
|
for (i = 0; i < numberOfPages; i++)
|
||||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
{
|
||||||
|
if (sector >= cacheEntries[i].sector && sector < (cacheEntries[i].sector + cacheEntries[i].count))
|
||||||
|
{
|
||||||
cacheEntries[i].last_access = accessTime();
|
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 (foundFree == false && (cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess))
|
||||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
{
|
||||||
|
if (cacheEntries[i].sector == CACHE_FREE) foundFree = true;
|
||||||
oldUsed = i;
|
oldUsed = i;
|
||||||
oldAccess = cacheEntries[i].last_access;
|
oldAccess = cacheEntries[i].last_access;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
if (foundFree == false && cacheEntries[oldUsed].dirty == true)
|
||||||
if(!cache->disc->writeSectors(cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
{
|
||||||
|
if (!cache->disc->writeSectors(cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count,
|
||||||
|
cacheEntries[oldUsed].cache)) return NULL;
|
||||||
cacheEntries[oldUsed].dirty = false;
|
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;
|
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].sector = sector;
|
||||||
cacheEntries[oldUsed].count = next_page-sector;
|
cacheEntries[oldUsed].count = next_page - sector;
|
||||||
cacheEntries[oldUsed].last_access = accessTime();
|
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;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
@ -163,16 +178,22 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
|
|||||||
NTFS_CACHE_ENTRY *entry = NULL;
|
NTFS_CACHE_ENTRY *entry = NULL;
|
||||||
sec_t lowest = UINT_MAX;
|
sec_t lowest = UINT_MAX;
|
||||||
|
|
||||||
for(i=0;i<numberOfPages;i++) {
|
for (i = 0; i < numberOfPages; i++)
|
||||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
{
|
||||||
|
if (cacheEntries[i].sector != CACHE_FREE)
|
||||||
|
{
|
||||||
bool intersect;
|
bool intersect;
|
||||||
if (sector > cacheEntries[i].sector) {
|
if (sector > cacheEntries[i].sector)
|
||||||
|
{
|
||||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
intersect = cacheEntries[i].sector - sector < count;
|
intersect = cacheEntries[i].sector - sector < count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
if (intersect && (cacheEntries[i].sector < lowest))
|
||||||
|
{
|
||||||
lowest = cacheEntries[i].sector;
|
lowest = cacheEntries[i].sector;
|
||||||
entry = &cacheEntries[i];
|
entry = &cacheEntries[i];
|
||||||
}
|
}
|
||||||
@ -182,24 +203,25 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
|
|||||||
return entry;
|
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 sec;
|
||||||
sec_t secs_to_read;
|
sec_t secs_to_read;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
uint8_t *dest = buffer;
|
uint8_t *dest = buffer;
|
||||||
|
|
||||||
while(numSectors>0) {
|
while (numSectors > 0)
|
||||||
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;
|
sec = sector - entry->sector;
|
||||||
secs_to_read = entry->count - sec;
|
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;
|
sector += secs_to_read;
|
||||||
numSectors -= secs_to_read;
|
numSectors -= secs_to_read;
|
||||||
}
|
}
|
||||||
@ -208,113 +230,137 @@ 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
|
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;
|
sec_t sec;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
|
|
||||||
if (offset + size > cache->sectorSize) return false;
|
if (offset + size > cache->sectorSize) return false;
|
||||||
|
|
||||||
entry = _NTFS_cache_getPage(cache,sector);
|
entry = _NTFS_cache_getPage(cache, sector);
|
||||||
if(entry==NULL) return false;
|
if (entry == NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
memcpy(buffer,entry->cache + ((sec*cache->sectorSize) + offset),size);
|
memcpy(buffer, entry->cache + ((sec * cache->sectorSize) + offset), size);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
bool _NTFS_cache_readLittleEndianValue(NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset,
|
||||||
|
int num_bytes)
|
||||||
|
{
|
||||||
uint8_t buf[4];
|
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 1:
|
||||||
case 4: *value = u8array_to_u32(buf,0); break;
|
*value = buf[0];
|
||||||
default: return false;
|
break;
|
||||||
|
case 2:
|
||||||
|
*value = u8array_to_u16(buf, 0);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*value = u8array_to_u32(buf, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
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;
|
sec_t sec;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
|
|
||||||
if (offset + size > cache->sectorSize) return false;
|
if (offset + size > cache->sectorSize) return false;
|
||||||
|
|
||||||
entry = _NTFS_cache_getPage(cache,sector);
|
entry = _NTFS_cache_getPage(cache, sector);
|
||||||
if(entry==NULL) return false;
|
if (entry == NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
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;
|
entry->dirty = true;
|
||||||
return 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,
|
||||||
uint8_t buf[4] = {0, 0, 0, 0};
|
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 1:
|
||||||
case 4: u32_to_u8array(buf, 0, value); break;
|
buf[0] = value;
|
||||||
default: return false;
|
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
|
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;
|
sec_t sec;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
|
|
||||||
if (offset + size > cache->sectorSize) return false;
|
if (offset + size > cache->sectorSize) return false;
|
||||||
|
|
||||||
entry = _NTFS_cache_getPage(cache,sector);
|
entry = _NTFS_cache_getPage(cache, sector);
|
||||||
if(entry==NULL) return false;
|
if (entry == NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
memset(entry->cache + (sec*cache->sectorSize),0,cache->sectorSize);
|
memset(entry->cache + (sec * cache->sectorSize), 0, cache->sectorSize);
|
||||||
memcpy(entry->cache + ((sec*cache->sectorSize) + offset),buffer,size);
|
memcpy(entry->cache + ((sec * cache->sectorSize) + offset), buffer, size);
|
||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
return 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 sec;
|
||||||
sec_t secs_to_write;
|
sec_t secs_to_write;
|
||||||
NTFS_CACHE_ENTRY* entry;
|
NTFS_CACHE_ENTRY* entry;
|
||||||
const uint8_t *src = buffer;
|
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;
|
secs_to_write = entry->sector - sector;
|
||||||
|
|
||||||
cache->disc->writeSectors(sector,secs_to_write,src);
|
cache->disc->writeSectors(sector, secs_to_write, src);
|
||||||
src += (secs_to_write*cache->sectorSize);
|
src += (secs_to_write * cache->sectorSize);
|
||||||
sector += secs_to_write;
|
sector += secs_to_write;
|
||||||
numSectors -= secs_to_write;
|
numSectors -= secs_to_write;
|
||||||
}
|
}
|
||||||
@ -322,34 +368,41 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
|||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
secs_to_write = entry->count - sec;
|
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;
|
sector += secs_to_write;
|
||||||
numSectors -= secs_to_write;
|
numSectors -= secs_to_write;
|
||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
|
|
||||||
} else {
|
}
|
||||||
cache->disc->writeSectors(sector,numSectors,src);
|
else
|
||||||
numSectors=0;
|
{
|
||||||
|
cache->disc->writeSectors(sector, numSectors, src);
|
||||||
|
numSectors = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
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;
|
unsigned int i;
|
||||||
if(cache==NULL) return true;
|
if (cache == NULL) return true;
|
||||||
|
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
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)) {
|
if (cache->cacheEntries[i].dirty)
|
||||||
|
{
|
||||||
|
if (!cache->disc->writeSectors(cache->cacheEntries[i].sector, cache->cacheEntries[i].count,
|
||||||
|
cache->cacheEntries[i].cache))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,13 +412,14 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
void _NTFS_cache_invalidate(NTFS_CACHE* cache)
|
||||||
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
if(cache==NULL)
|
if (cache == NULL) return;
|
||||||
return;
|
|
||||||
|
|
||||||
_NTFS_cache_flush(cache);
|
_NTFS_cache_flush(cache);
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for (i = 0; i < cache->numberOfPages; i++)
|
||||||
|
{
|
||||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||||
cache->cacheEntries[i].last_access = 0;
|
cache->cacheEntries[i].last_access = 0;
|
||||||
cache->cacheEntries[i].count = 0;
|
cache->cacheEntries[i].count = 0;
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _CACHE2_H
|
#ifndef _CACHE2_H
|
||||||
#define _CACHE2_H
|
#define _CACHE2_H
|
||||||
@ -46,7 +46,8 @@
|
|||||||
#include <ogc/disc_io.h>
|
#include <ogc/disc_io.h>
|
||||||
#include <gccore.h>
|
#include <gccore.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
u64 last_access;
|
u64 last_access;
|
||||||
@ -54,7 +55,8 @@ typedef struct {
|
|||||||
u8* cache;
|
u8* cache;
|
||||||
} NTFS_CACHE_ENTRY;
|
} NTFS_CACHE_ENTRY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
const DISC_INTERFACE* disc;
|
const DISC_INTERFACE* disc;
|
||||||
sec_t endOfPartition;
|
sec_t endOfPartition;
|
||||||
unsigned int numberOfPages;
|
unsigned int numberOfPages;
|
||||||
@ -64,72 +66,72 @@ typedef struct {
|
|||||||
} NTFS_CACHE;
|
} NTFS_CACHE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read data from a sector in the NTFS_CACHE
|
Read data from a sector in the NTFS_CACHE
|
||||||
If the sector is not in the NTFS_CACHE, it will be swapped in
|
If the sector is not in the NTFS_CACHE, it will be swapped in
|
||||||
offset is the position to start reading from
|
offset is the position to start reading from
|
||||||
size is the amount of data to read
|
size is the amount of data to read
|
||||||
Precondition: offset + size <= BYTES_PER_READ
|
Precondition: offset + size <= BYTES_PER_READ
|
||||||
*/
|
*/
|
||||||
//bool _NTFS_cache_readPartialSector (NTFS_CACHE* NTFS_CACHE, void* buffer, sec_t sector, unsigned int offset, size_t size);
|
//bool _NTFS_cache_readPartialSector (NTFS_CACHE* NTFS_CACHE, void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||||
|
|
||||||
//bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* NTFS_CACHE, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes);
|
//bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* NTFS_CACHE, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write data to a sector in the NTFS_CACHE
|
Write data to a sector in the NTFS_CACHE
|
||||||
If the sector is not in the NTFS_CACHE, it will be swapped in.
|
If the sector is not in the NTFS_CACHE, it will be swapped in.
|
||||||
When the sector is swapped out, the data will be written to the disc
|
When the sector is swapped out, the data will be written to the disc
|
||||||
offset is the position to start writing to
|
offset is the position to start writing to
|
||||||
size is the amount of data to write
|
size is the amount of data to write
|
||||||
Precondition: offset + size <= BYTES_PER_READ
|
Precondition: offset + size <= BYTES_PER_READ
|
||||||
*/
|
*/
|
||||||
//bool _NTFS_cache_writePartialSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
//bool _NTFS_cache_writePartialSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||||
|
|
||||||
//bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* NTFS_CACHE, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes);
|
//bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* NTFS_CACHE, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write data to a sector in the NTFS_CACHE, zeroing the sector first
|
Write data to a sector in the NTFS_CACHE, zeroing the sector first
|
||||||
If the sector is not in the NTFS_CACHE, it will be swapped in.
|
If the sector is not in the NTFS_CACHE, it will be swapped in.
|
||||||
When the sector is swapped out, the data will be written to the disc
|
When the sector is swapped out, the data will be written to the disc
|
||||||
offset is the position to start writing to
|
offset is the position to start writing to
|
||||||
size is the amount of data to write
|
size is the amount of data to write
|
||||||
Precondition: offset + size <= BYTES_PER_READ
|
Precondition: offset + size <= BYTES_PER_READ
|
||||||
*/
|
*/
|
||||||
//bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
//bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read several sectors from the NTFS_CACHE
|
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
|
Read a full sector from the NTFS_CACHE
|
||||||
*/
|
*/
|
||||||
//static inline bool _NTFS_cache_readSector (NTFS_CACHE* NTFS_CACHE, void* buffer, sec_t sector) {
|
//static inline bool _NTFS_cache_readSector (NTFS_CACHE* NTFS_CACHE, void* buffer, sec_t sector) {
|
||||||
// return _NTFS_cache_readPartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
// return _NTFS_cache_readPartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write a full sector to the NTFS_CACHE
|
Write a full sector to the NTFS_CACHE
|
||||||
*/
|
*/
|
||||||
//static inline bool _NTFS_cache_writeSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector) {
|
//static inline bool _NTFS_cache_writeSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector) {
|
||||||
// return _NTFS_cache_writePartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
// return _NTFS_cache_writePartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
bool _NTFS_cache_writeSectors (NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, const void* buffer);
|
bool _NTFS_cache_writeSectors(NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, const void* buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write any dirty sectors back to disc and clear out the contents of the NTFS_CACHE
|
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
|
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
|
#endif // _CACHE_H
|
||||||
|
|
||||||
|
@ -52,19 +52,18 @@
|
|||||||
*
|
*
|
||||||
* Returns:
|
* 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 void *data1, const int data1_len,
|
const int data2_len)
|
||||||
const void *data2, const int data2_len)
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ntfs_log_trace("Entering.\n");
|
ntfs_log_trace("Entering.\n");
|
||||||
rc = memcmp(data1, data2, min(data1_len, data2_len));
|
rc = memcmp(data1, data2, min(data1_len, data2_len));
|
||||||
if (!rc && (data1_len != data2_len)) {
|
if (!rc && (data1_len != data2_len))
|
||||||
|
{
|
||||||
if (data1_len < data2_len)
|
if (data1_len < data2_len)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else rc = 1;
|
||||||
rc = 1;
|
|
||||||
}
|
}
|
||||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
@ -82,15 +81,15 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
|||||||
*
|
*
|
||||||
* Returns:
|
* 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 void *data1, const int data1_len,
|
const int data2_len)
|
||||||
const void *data2, const int data2_len)
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u32 d1, d2;
|
u32 d1, d2;
|
||||||
|
|
||||||
ntfs_log_trace("Entering.\n");
|
ntfs_log_trace("Entering.\n");
|
||||||
if (data1_len != data2_len || data1_len != 4) {
|
if (data1_len != data2_len || data1_len != 4)
|
||||||
|
{
|
||||||
ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
|
ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
@ -98,11 +97,11 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
|||||||
d2 = le32_to_cpup(data2);
|
d2 = le32_to_cpup(data2);
|
||||||
if (d1 < d2)
|
if (d1 < d2)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (d1 == d2)
|
if (d1 == d2)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else
|
else rc = 1;
|
||||||
rc = 1;
|
|
||||||
}
|
}
|
||||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
@ -114,9 +113,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
|||||||
* Returns: -1, 0 or 1 depending of how the arrays compare
|
* 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 void *data1, const int data1_len,
|
const int data2_len)
|
||||||
const void *data2, const int data2_len)
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int len;
|
int len;
|
||||||
@ -124,14 +122,16 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
|||||||
u32 d1, d2;
|
u32 d1, d2;
|
||||||
|
|
||||||
ntfs_log_trace("Entering.\n");
|
ntfs_log_trace("Entering.\n");
|
||||||
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) {
|
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3))
|
||||||
|
{
|
||||||
ntfs_log_error("data1_len or data2_len not valid\n");
|
ntfs_log_error("data1_len or data2_len not valid\n");
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
p1 = (const le32*)data1;
|
p1 = (const le32*) data1;
|
||||||
p2 = (const le32*)data2;
|
p2 = (const le32*) data2;
|
||||||
len = data1_len;
|
len = data1_len;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
d1 = le32_to_cpup(p1);
|
d1 = le32_to_cpup(p1);
|
||||||
p1++;
|
p1++;
|
||||||
d2 = le32_to_cpup(p2);
|
d2 = le32_to_cpup(p2);
|
||||||
@ -139,11 +139,11 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
|||||||
} while ((d1 == d2) && ((len -= 4) > 0));
|
} while ((d1 == d2) && ((len -= 4) > 0));
|
||||||
if (d1 < d2)
|
if (d1 < d2)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (d1 == d2)
|
if (d1 == d2)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else
|
else rc = 1;
|
||||||
rc = 1;
|
|
||||||
}
|
}
|
||||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
@ -162,8 +162,7 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
|||||||
*
|
*
|
||||||
* Returns: -1, 0 or 1 depending of how the keys compare
|
* 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 *data1, const int data1_len,
|
|
||||||
const void *data2, const int data2_len)
|
const void *data2, const int data2_len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@ -171,31 +170,34 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
|||||||
const le32 *p1, *p2;
|
const le32 *p1, *p2;
|
||||||
|
|
||||||
ntfs_log_trace("Entering.\n");
|
ntfs_log_trace("Entering.\n");
|
||||||
if (data1_len != data2_len || data1_len != 8) {
|
if (data1_len != data2_len || data1_len != 8)
|
||||||
|
{
|
||||||
ntfs_log_error("data1_len or/and data2_len not equal to 8.\n");
|
ntfs_log_error("data1_len or/and data2_len not equal to 8.\n");
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
p1 = (const le32*)data1;
|
p1 = (const le32*) data1;
|
||||||
p2 = (const le32*)data2;
|
p2 = (const le32*) data2;
|
||||||
d1 = le32_to_cpup(p1);
|
d1 = le32_to_cpup(p1);
|
||||||
d2 = le32_to_cpup(p2);
|
d2 = le32_to_cpup(p2);
|
||||||
if (d1 < d2)
|
if (d1 < d2)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (d1 > d2)
|
if (d1 > d2)
|
||||||
rc = 1;
|
rc = 1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
p1++;
|
p1++;
|
||||||
p2++;
|
p2++;
|
||||||
d1 = le32_to_cpup(p1);
|
d1 = le32_to_cpup(p1);
|
||||||
d2 = le32_to_cpup(p2);
|
d2 = le32_to_cpup(p2);
|
||||||
if (d1 < d2)
|
if (d1 < d2)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (d1 > d2)
|
if (d1 > d2)
|
||||||
rc = 1;
|
rc = 1;
|
||||||
else
|
else rc = 0;
|
||||||
rc = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,23 +217,19 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
|||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
*/
|
*/
|
||||||
static int ntfs_collate_file_name(ntfs_volume *vol,
|
static int ntfs_collate_file_name(ntfs_volume *vol, const void *data1, const int data1_len __attribute__((unused)), const void *data2,
|
||||||
const void *data1, const int data1_len __attribute__((unused)),
|
const int data2_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_attr1;
|
||||||
const FILE_NAME_ATTR *file_name_attr2;
|
const FILE_NAME_ATTR *file_name_attr2;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ntfs_log_trace("Entering.\n");
|
ntfs_log_trace("Entering.\n");
|
||||||
file_name_attr1 = (const FILE_NAME_ATTR*)data1;
|
file_name_attr1 = (const FILE_NAME_ATTR*) data1;
|
||||||
file_name_attr2 = (const FILE_NAME_ATTR*)data2;
|
file_name_attr2 = (const FILE_NAME_ATTR*) data2;
|
||||||
rc = ntfs_names_full_collate(
|
rc = ntfs_names_full_collate((ntfschar*) &file_name_attr1->file_name, file_name_attr1->file_name_length,
|
||||||
(ntfschar*)&file_name_attr1->file_name,
|
(ntfschar*) &file_name_attr2->file_name, file_name_attr2->file_name_length, CASE_SENSITIVE, vol->upcase,
|
||||||
file_name_attr1->file_name_length,
|
vol->upcase_len);
|
||||||
(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);
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -246,25 +244,26 @@ COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
|
|||||||
{
|
{
|
||||||
COLLATE collate;
|
COLLATE collate;
|
||||||
|
|
||||||
switch (cr) {
|
switch (cr)
|
||||||
case COLLATION_BINARY :
|
{
|
||||||
|
case COLLATION_BINARY:
|
||||||
collate = ntfs_collate_binary;
|
collate = ntfs_collate_binary;
|
||||||
break;
|
break;
|
||||||
case COLLATION_FILE_NAME :
|
case COLLATION_FILE_NAME:
|
||||||
collate = ntfs_collate_file_name;
|
collate = ntfs_collate_file_name;
|
||||||
break;
|
break;
|
||||||
case COLLATION_NTOFS_SECURITY_HASH :
|
case COLLATION_NTOFS_SECURITY_HASH:
|
||||||
collate = ntfs_collate_ntofs_security_hash;
|
collate = ntfs_collate_ntofs_security_hash;
|
||||||
break;
|
break;
|
||||||
case COLLATION_NTOFS_ULONG :
|
case COLLATION_NTOFS_ULONG:
|
||||||
collate = ntfs_collate_ntofs_ulong;
|
collate = ntfs_collate_ntofs_ulong;
|
||||||
break;
|
break;
|
||||||
case COLLATION_NTOFS_ULONGS :
|
case COLLATION_NTOFS_ULONGS:
|
||||||
collate = ntfs_collate_ntofs_ulongs;
|
collate = ntfs_collate_ntofs_ulongs;
|
||||||
break;
|
break;
|
||||||
default :
|
default:
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
collate = (COLLATE)NULL;
|
collate = (COLLATE) NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (collate);
|
return (collate);
|
||||||
|
@ -39,25 +39,29 @@ int ffs(int x)
|
|||||||
{
|
{
|
||||||
int r = 1;
|
int r = 1;
|
||||||
|
|
||||||
if (!x)
|
if (!x) return 0;
|
||||||
return 0;
|
if (!(x & 0xffff))
|
||||||
if (!(x & 0xffff)) {
|
{
|
||||||
x >>= 16;
|
x >>= 16;
|
||||||
r += 16;
|
r += 16;
|
||||||
}
|
}
|
||||||
if (!(x & 0xff)) {
|
if (!(x & 0xff))
|
||||||
|
{
|
||||||
x >>= 8;
|
x >>= 8;
|
||||||
r += 8;
|
r += 8;
|
||||||
}
|
}
|
||||||
if (!(x & 0xf)) {
|
if (!(x & 0xf))
|
||||||
|
{
|
||||||
x >>= 4;
|
x >>= 4;
|
||||||
r += 4;
|
r += 4;
|
||||||
}
|
}
|
||||||
if (!(x & 3)) {
|
if (!(x & 3))
|
||||||
|
{
|
||||||
x >>= 2;
|
x >>= 2;
|
||||||
r += 2;
|
r += 2;
|
||||||
}
|
}
|
||||||
if (!(x & 1)) {
|
if (!(x & 1))
|
||||||
|
{
|
||||||
x >>= 1;
|
x >>= 1;
|
||||||
r += 1;
|
r += 1;
|
||||||
}
|
}
|
||||||
@ -120,10 +124,12 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int daemon(int nochdir, int noclose) {
|
int daemon(int nochdir, int noclose)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
switch (fork()) {
|
switch (fork())
|
||||||
|
{
|
||||||
case -1:
|
case -1:
|
||||||
return (-1);
|
return (-1);
|
||||||
case 0:
|
case 0:
|
||||||
@ -132,18 +138,16 @@ int daemon(int nochdir, int noclose) {
|
|||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsid() == -1)
|
if (setsid() == -1) return (-1);
|
||||||
return (-1);
|
|
||||||
|
|
||||||
if (!nochdir)
|
if (!nochdir) (void) chdir("/");
|
||||||
(void)chdir("/");
|
|
||||||
|
|
||||||
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1)
|
||||||
(void)dup2(fd, 0);
|
{
|
||||||
(void)dup2(fd, 1);
|
(void) dup2(fd, 0);
|
||||||
(void)dup2(fd, 2);
|
(void) dup2(fd, 1);
|
||||||
if (fd > 2)
|
(void) dup2(fd, 2);
|
||||||
(void)close (fd);
|
if (fd > 2) (void) close(fd);
|
||||||
}
|
}
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -218,23 +222,25 @@ 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.
|
* If *stringp is NULL, strsep returns NULL.
|
||||||
*/
|
*/
|
||||||
char *strsep(char **stringp, const char *delim) {
|
char *strsep(char **stringp, const char *delim)
|
||||||
|
{
|
||||||
char *s;
|
char *s;
|
||||||
const char *spanp;
|
const char *spanp;
|
||||||
int c, sc;
|
int c, sc;
|
||||||
char *tok;
|
char *tok;
|
||||||
|
|
||||||
if ((s = *stringp) == NULL)
|
if ((s = *stringp) == NULL) return (NULL);
|
||||||
return (NULL);
|
for (tok = s;;)
|
||||||
for (tok = s;;) {
|
{
|
||||||
c = *s++;
|
c = *s++;
|
||||||
spanp = delim;
|
spanp = delim;
|
||||||
do {
|
do
|
||||||
if ((sc = *spanp++) == c) {
|
{
|
||||||
|
if ((sc = *spanp++) == c)
|
||||||
|
{
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
s = NULL;
|
s = NULL;
|
||||||
else
|
else s[-1] = 0;
|
||||||
s[-1] = 0;
|
|
||||||
*stringp = s;
|
*stringp = s;
|
||||||
return (tok);
|
return (tok);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -26,16 +26,12 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "attrib.h"
|
#include "attrib.h"
|
||||||
|
|
||||||
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
|
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b);
|
||||||
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,
|
||||||
s64 offs, s64 to_write, s64 rounded,
|
const void *b, int compressed_part, VCN *update_from);
|
||||||
const void *b, int compressed_part,
|
|
||||||
VCN *update_from);
|
|
||||||
|
|
||||||
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl,
|
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl, s64 offs, VCN *update_from);
|
||||||
s64 offs, VCN *update_from);
|
|
||||||
|
|
||||||
#endif /* defined _NTFS_COMPRESS_H */
|
#endif /* defined _NTFS_COMPRESS_H */
|
||||||
|
|
||||||
|
@ -45,20 +45,24 @@
|
|||||||
void ntfs_debug_runlist_dump(const runlist_element *rl)
|
void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
const char *lcn_str[5] =
|
||||||
|
{ "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||||
"LCN_unknown " };
|
"LCN_unknown "};
|
||||||
|
|
||||||
ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
|
ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
|
||||||
if (!rl) {
|
if (!rl)
|
||||||
|
{
|
||||||
ntfs_log_debug("Run list not present.\n");
|
ntfs_log_debug("Run list not present.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ntfs_log_debug("VCN LCN Run length\n");
|
ntfs_log_debug("VCN LCN Run length\n");
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
LCN lcn = (rl + i)->lcn;
|
LCN lcn = (rl + i)->lcn;
|
||||||
|
|
||||||
if (lcn < (LCN)0) {
|
if (lcn < (LCN)0)
|
||||||
|
{
|
||||||
int idx = -lcn - 1;
|
int idx = -lcn - 1;
|
||||||
|
|
||||||
if (idx > -LCN_EINVAL - 1)
|
if (idx > -LCN_EINVAL - 1)
|
||||||
@ -67,12 +71,13 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
|
|||||||
(long long)rl[i].vcn, lcn_str[idx],
|
(long long)rl[i].vcn, lcn_str[idx],
|
||||||
(long long)rl[i].length,
|
(long long)rl[i].length,
|
||||||
rl[i].length ? "" : " (runlist end)");
|
rl[i].length ? "" : " (runlist end)");
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ntfs_log_debug("%-16lld %-16lld %-16lld%s\n",
|
ntfs_log_debug("%-16lld %-16lld %-16lld%s\n",
|
||||||
(long long)rl[i].vcn, (long long)rl[i].lcn,
|
(long long)rl[i].vcn, (long long)rl[i].lcn,
|
||||||
(long long)rl[i].length,
|
(long long)rl[i].length,
|
||||||
rl[i].length ? "" : " (runlist end)");
|
rl[i].length ? "" : " (runlist end)");
|
||||||
} while (rl[i++].length);
|
}while (rl[i++].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,7 +33,9 @@ struct _runlist_element;
|
|||||||
#ifdef DEBUG
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
#define NTFS_BUG(msg) \
|
#define NTFS_BUG(msg) \
|
||||||
|
@ -103,19 +103,22 @@
|
|||||||
* On success return a pointer to the allocated ntfs device structure and on
|
* 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().
|
* 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 *ntfs_device_alloc(const char *name, const long state, struct ntfs_device_operations *dops,
|
||||||
struct ntfs_device_operations *dops, void *priv_data)
|
void *priv_data)
|
||||||
{
|
{
|
||||||
struct ntfs_device *dev;
|
struct ntfs_device *dev;
|
||||||
|
|
||||||
if (!name) {
|
if (!name)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = ntfs_malloc(sizeof(struct ntfs_device));
|
dev = ntfs_malloc(sizeof(struct ntfs_device));
|
||||||
if (dev) {
|
if (dev)
|
||||||
if (!(dev->d_name = strdup(name))) {
|
{
|
||||||
|
if (!(dev->d_name = strdup(name)))
|
||||||
|
{
|
||||||
int eo = errno;
|
int eo = errno;
|
||||||
free(dev);
|
free(dev);
|
||||||
errno = eo;
|
errno = eo;
|
||||||
@ -141,11 +144,13 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
|||||||
*/
|
*/
|
||||||
int ntfs_device_free(struct ntfs_device *dev)
|
int ntfs_device_free(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if (!dev)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (NDevOpen(dev)) {
|
if (NDevOpen(dev))
|
||||||
|
{
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -180,23 +185,22 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
|||||||
|
|
||||||
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;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!count)
|
if (!count) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
dops = dev->d_ops;
|
dops = dev->d_ops;
|
||||||
|
|
||||||
for (total = 0; count; count -= br, total += br) {
|
for (total = 0; count; count -= br, total += br)
|
||||||
br = dops->pread(dev, (char*)b + total, count, pos + total);
|
{
|
||||||
|
br = dops->pread(dev, (char*) b + total, count, pos + total);
|
||||||
/* If everything ok, continue. */
|
/* If everything ok, continue. */
|
||||||
if (br > 0)
|
if (br > 0) continue;
|
||||||
continue;
|
|
||||||
/* If EOF or error return number of bytes read. */
|
/* If EOF or error return number of bytes read. */
|
||||||
if (!br || total)
|
if (!br || total) return total;
|
||||||
return total;
|
|
||||||
/* Nothing read and error, return error status. */
|
/* Nothing read and error, return error status. */
|
||||||
return br;
|
return br;
|
||||||
}
|
}
|
||||||
@ -223,21 +227,21 @@ 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
|
* appropriately to the return code of either seek, write, or set
|
||||||
* to EINVAL in case of invalid arguments.
|
* to EINVAL in case of invalid arguments.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const void *b)
|
||||||
const void *b)
|
|
||||||
{
|
{
|
||||||
s64 written, total, ret = -1;
|
s64 written, total, ret = -1;
|
||||||
struct ntfs_device_operations *dops;
|
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;
|
errno = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!count)
|
if (!count) return 0;
|
||||||
return 0;
|
if (NDevReadOnly(dev))
|
||||||
if (NDevReadOnly(dev)) {
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -245,24 +249,21 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
dops = dev->d_ops;
|
dops = dev->d_ops;
|
||||||
|
|
||||||
NDevSetDirty(dev);
|
NDevSetDirty(dev);
|
||||||
for (total = 0; count; count -= written, total += written) {
|
for (total = 0; count; count -= written, total += written)
|
||||||
written = dops->pwrite(dev, (const char*)b + total, count,
|
{
|
||||||
pos + total);
|
written = dops->pwrite(dev, (const char*) b + total, count, pos + total);
|
||||||
/* If everything ok, continue. */
|
/* If everything ok, continue. */
|
||||||
if (written > 0)
|
if (written > 0) continue;
|
||||||
continue;
|
|
||||||
/*
|
/*
|
||||||
* If nothing written or error return number of bytes written.
|
* If nothing written or error return number of bytes written.
|
||||||
*/
|
*/
|
||||||
if (!written || total)
|
if (!written || total) break;
|
||||||
break;
|
|
||||||
/* Nothing written and error, return error status. */
|
/* Nothing written and error, return error status. */
|
||||||
total = written;
|
total = written;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret = total;
|
ret = total;
|
||||||
out:
|
out: return ret;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -294,19 +295,18 @@ out:
|
|||||||
* sector transfer error. This should be detected by the caller by checking for
|
* sector transfer error. This should be detected by the caller by checking for
|
||||||
* the magic being "BAAD".
|
* the magic being "BAAD".
|
||||||
*/
|
*/
|
||||||
s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b)
|
||||||
const u32 bksize, void *b)
|
|
||||||
{
|
{
|
||||||
s64 br, i;
|
s64 br, i;
|
||||||
|
|
||||||
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
|
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Do the read. */
|
/* Do the read. */
|
||||||
br = ntfs_pread(dev, pos, count * bksize, b);
|
br = ntfs_pread(dev, pos, count * bksize, b);
|
||||||
if (br < 0)
|
if (br < 0) return br;
|
||||||
return br;
|
|
||||||
/*
|
/*
|
||||||
* Apply fixups to successfully read data, disregarding any errors
|
* Apply fixups to successfully read data, disregarding any errors
|
||||||
* returned from the MST fixup function. This is because we want to
|
* returned from the MST fixup function. This is because we want to
|
||||||
@ -315,8 +315,7 @@ s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
*/
|
*/
|
||||||
count = br / bksize;
|
count = br / bksize;
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
ntfs_mst_post_read_fixup((NTFS_RECORD*)
|
ntfs_mst_post_read_fixup((NTFS_RECORD*) ((u8*) b + i * bksize), bksize);
|
||||||
((u8*)b + i * bksize), bksize);
|
|
||||||
/* Finally, return the number of complete blocks read. */
|
/* Finally, return the number of complete blocks read. */
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -351,27 +350,26 @@ 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
|
* simulating an mst read on the written data. This way cache coherency is
|
||||||
* achieved.
|
* achieved.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b)
|
||||||
const u32 bksize, void *b)
|
|
||||||
{
|
{
|
||||||
s64 written, i;
|
s64 written, i;
|
||||||
|
|
||||||
if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
|
if (count < 0 || bksize % NTFS_BLOCK_SIZE)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!count)
|
if (!count) return 0;
|
||||||
return 0;
|
|
||||||
/* Prepare data for writing. */
|
/* Prepare data for writing. */
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
|
err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) ((u8*) b + i * bksize), bksize);
|
||||||
((u8*)b + i * bksize), bksize);
|
if (err < 0)
|
||||||
if (err < 0) {
|
{
|
||||||
/* Abort write at this position. */
|
/* Abort write at this position. */
|
||||||
if (!i)
|
if (!i) return err;
|
||||||
return err;
|
|
||||||
count = i;
|
count = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -380,9 +378,8 @@ s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
written = ntfs_pwrite(dev, pos, count * bksize, b);
|
written = ntfs_pwrite(dev, pos, count * bksize, b);
|
||||||
/* Quickly deprotect the data again. */
|
/* Quickly deprotect the data again. */
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
|
ntfs_mst_post_write_fixup((NTFS_RECORD*) ((u8*) b + i * bksize));
|
||||||
if (written <= 0)
|
if (written <= 0) return written;
|
||||||
return written;
|
|
||||||
/* Finally, return the number of complete blocks written. */
|
/* Finally, return the number of complete blocks written. */
|
||||||
return written / bksize;
|
return written / bksize;
|
||||||
}
|
}
|
||||||
@ -398,25 +395,26 @@ 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,
|
* volume @vol into buffer @b. Return number of clusters read or -1 on error,
|
||||||
* with errno set to the error code.
|
* with errno set to the error code.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count, void *b)
|
||||||
void *b)
|
|
||||||
{
|
{
|
||||||
s64 br;
|
s64 br;
|
||||||
|
|
||||||
if (!vol || lcn < 0 || count < 0) {
|
if (!vol || lcn < 0 || count < 0)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (vol->nr_clusters < lcn + count) {
|
if (vol->nr_clusters < lcn + count)
|
||||||
|
{
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror("Trying to read outside of volume "
|
ntfs_log_perror("Trying to read outside of volume "
|
||||||
"(%lld < %lld)", (long long)vol->nr_clusters,
|
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||||
(long long)lcn + count);
|
(long long)lcn + count);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
|
br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits, count << vol->cluster_size_bits, b);
|
||||||
count << vol->cluster_size_bits, b);
|
if (br < 0)
|
||||||
if (br < 0) {
|
{
|
||||||
ntfs_log_perror("Error reading cluster(s)");
|
ntfs_log_perror("Error reading cluster(s)");
|
||||||
return br;
|
return br;
|
||||||
}
|
}
|
||||||
@ -434,16 +432,17 @@ 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
|
* buffer @b to volume @vol. Return the number of clusters written or -1 on
|
||||||
* error, with errno set to the error code.
|
* error, with errno set to the error code.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, const s64 count, const void *b)
|
||||||
const s64 count, const void *b)
|
|
||||||
{
|
{
|
||||||
s64 bw;
|
s64 bw;
|
||||||
|
|
||||||
if (!vol || lcn < 0 || count < 0) {
|
if (!vol || lcn < 0 || count < 0)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (vol->nr_clusters < lcn + count) {
|
if (vol->nr_clusters < lcn + count)
|
||||||
|
{
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror("Trying to write outside of volume "
|
ntfs_log_perror("Trying to write outside of volume "
|
||||||
"(%lld < %lld)", (long long)vol->nr_clusters,
|
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||||
@ -451,11 +450,10 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!NVolReadOnly(vol))
|
if (!NVolReadOnly(vol))
|
||||||
bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
|
bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits, count << vol->cluster_size_bits, b);
|
||||||
count << vol->cluster_size_bits, b);
|
else bw = count << vol->cluster_size_bits;
|
||||||
else
|
if (bw < 0)
|
||||||
bw = count << vol->cluster_size_bits;
|
{
|
||||||
if (bw < 0) {
|
|
||||||
ntfs_log_perror("Error writing cluster(s)");
|
ntfs_log_perror("Error writing cluster(s)");
|
||||||
return bw;
|
return bw;
|
||||||
}
|
}
|
||||||
@ -476,9 +474,7 @@ static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
|
|||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
|
if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 && dev->d_ops->read(dev, &ch, 1) == 1) return 0;
|
||||||
dev->d_ops->read(dev, &ch, 1) == 1)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,14 +494,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
{
|
{
|
||||||
s64 high, low;
|
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;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef BLKGETSIZE64
|
#ifdef BLKGETSIZE64
|
||||||
{ u64 size;
|
{ u64 size;
|
||||||
|
|
||||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
|
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0)
|
||||||
|
{
|
||||||
ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||||
(unsigned long long)size,
|
(unsigned long long)size,
|
||||||
(unsigned long long)size);
|
(unsigned long long)size);
|
||||||
@ -516,7 +514,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
#ifdef BLKGETSIZE
|
#ifdef BLKGETSIZE
|
||||||
{ unsigned long size;
|
{ unsigned long size;
|
||||||
|
|
||||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
|
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0)
|
||||||
|
{
|
||||||
ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
||||||
size, size);
|
size, size);
|
||||||
return (s64)size * 512 / block_size;
|
return (s64)size * 512 / block_size;
|
||||||
@ -526,7 +525,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
#ifdef FDGETPRM
|
#ifdef FDGETPRM
|
||||||
{ struct floppy_struct this_floppy;
|
{ struct floppy_struct this_floppy;
|
||||||
|
|
||||||
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
|
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0)
|
||||||
|
{
|
||||||
ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
||||||
(unsigned long)this_floppy.size,
|
(unsigned long)this_floppy.size,
|
||||||
(unsigned long)this_floppy.size);
|
(unsigned long)this_floppy.size);
|
||||||
@ -541,13 +541,13 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
low = 0LL;
|
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;
|
low = high;
|
||||||
while (low < high - 1LL) {
|
while (low < high - 1LL)
|
||||||
|
{
|
||||||
const s64 mid = (low + high) / 2;
|
const s64 mid = (low + high) / 2;
|
||||||
|
|
||||||
if (!ntfs_device_offset_valid(dev, mid))
|
if (!ntfs_device_offset_valid(dev, mid))
|
||||||
low = mid;
|
low = mid;
|
||||||
else
|
else high = mid;
|
||||||
high = mid;
|
|
||||||
}
|
}
|
||||||
dev->d_ops->seek(dev, 0LL, SEEK_SET);
|
dev->d_ops->seek(dev, 0LL, SEEK_SET);
|
||||||
return (low + 1LL) / block_size;
|
return (low + 1LL) / block_size;
|
||||||
@ -567,14 +567,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||||||
*/
|
*/
|
||||||
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;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo))
|
||||||
|
{
|
||||||
ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
||||||
geo.start, geo.start);
|
geo.start, geo.start);
|
||||||
return geo.start;
|
return geo.start;
|
||||||
@ -600,14 +602,16 @@ s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
|
|||||||
*/
|
*/
|
||||||
int ntfs_device_heads_get(struct ntfs_device *dev)
|
int ntfs_device_heads_get(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if (!dev)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo))
|
||||||
|
{
|
||||||
ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
|
ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
|
||||||
(unsigned)geo.heads,
|
(unsigned)geo.heads,
|
||||||
(unsigned)geo.heads);
|
(unsigned)geo.heads);
|
||||||
@ -634,14 +638,16 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
|
|||||||
*/
|
*/
|
||||||
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;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo))
|
||||||
|
{
|
||||||
ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
||||||
(unsigned)geo.sectors,
|
(unsigned)geo.sectors,
|
||||||
(unsigned)geo.sectors);
|
(unsigned)geo.sectors);
|
||||||
@ -668,7 +674,8 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
|
|||||||
*/
|
*/
|
||||||
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;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -676,7 +683,8 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
|||||||
{
|
{
|
||||||
int sect_size = 0;
|
int sect_size = 0;
|
||||||
|
|
||||||
if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) {
|
if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size))
|
||||||
|
{
|
||||||
ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
|
ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
|
||||||
sect_size);
|
sect_size);
|
||||||
return sect_size;
|
return sect_size;
|
||||||
@ -701,17 +709,18 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
|||||||
* EOPNOTSUPP System does not support BLKBSZSET ioctl
|
* EOPNOTSUPP System does not support BLKBSZSET ioctl
|
||||||
* ENOTTY @dev is a file or a device not supporting BLKBSZSET
|
* ENOTTY @dev is a file or a device not supporting BLKBSZSET
|
||||||
*/
|
*/
|
||||||
int ntfs_device_block_size_set(struct ntfs_device *dev,
|
int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size __attribute__((unused)))
|
||||||
int block_size __attribute__((unused)))
|
|
||||||
{
|
{
|
||||||
if (!dev) {
|
if (!dev)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef BLKBSZSET
|
#ifdef BLKBSZSET
|
||||||
{
|
{
|
||||||
size_t s_block_size = block_size;
|
size_t s_block_size = block_size;
|
||||||
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
|
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size))
|
||||||
|
{
|
||||||
ntfs_log_debug("Used BLKBSZSET to set block size to "
|
ntfs_log_debug("Used BLKBSZSET to set block size to "
|
||||||
"%d bytes.\n", block_size);
|
"%d bytes.\n", block_size);
|
||||||
return 0;
|
return 0;
|
||||||
@ -722,8 +731,7 @@ int ntfs_device_block_size_set(struct ntfs_device *dev,
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* If not a block device, pretend it was successful. */
|
/* If not a block device, pretend it was successful. */
|
||||||
if (!NDevBlock(dev))
|
if (!NDevBlock(dev)) return 0;
|
||||||
return 0;
|
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -36,11 +36,13 @@
|
|||||||
*
|
*
|
||||||
* Defined bits for the state field in the ntfs_device structure.
|
* Defined bits for the state field in the ntfs_device structure.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ND_Open, /* 1: Device is open. */
|
ND_Open, /* 1: Device is open. */
|
||||||
ND_ReadOnly, /* 1: Device is read-only. */
|
ND_ReadOnly, /* 1: Device is read-only. */
|
||||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||||
ND_Block, /* 1: Device is a block device. */
|
ND_Block,
|
||||||
|
/* 1: Device is a block device. */
|
||||||
} ntfs_device_state_bits;
|
} ntfs_device_state_bits;
|
||||||
|
|
||||||
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
|
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
|
||||||
@ -69,7 +71,8 @@ typedef enum {
|
|||||||
* The ntfs device structure defining all operations needed to access the low
|
* The ntfs device structure defining all operations needed to access the low
|
||||||
* level device underlying the ntfs volume.
|
* level device underlying the ntfs volume.
|
||||||
*/
|
*/
|
||||||
struct ntfs_device {
|
struct ntfs_device
|
||||||
|
{
|
||||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||||
unsigned long d_state; /* State of the device. */
|
unsigned long d_state; /* State of the device. */
|
||||||
char *d_name; /* Name of device. */
|
char *d_name; /* Name of device. */
|
||||||
@ -85,38 +88,32 @@ struct stat;
|
|||||||
* The ntfs device operations defining all operations that can be performed on
|
* The ntfs device operations defining all operations that can be performed on
|
||||||
* the low level device described by an ntfs device structure.
|
* the low level device described by an ntfs device structure.
|
||||||
*/
|
*/
|
||||||
struct ntfs_device_operations {
|
struct ntfs_device_operations
|
||||||
|
{
|
||||||
int (*open)(struct ntfs_device *dev, int flags);
|
int (*open)(struct ntfs_device *dev, int flags);
|
||||||
int (*close)(struct ntfs_device *dev);
|
int (*close)(struct ntfs_device *dev);
|
||||||
s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence);
|
s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence);
|
||||||
s64 (*read)(struct ntfs_device *dev, void *buf, s64 count);
|
s64 (*read)(struct ntfs_device *dev, void *buf, s64 count);
|
||||||
s64 (*write)(struct ntfs_device *dev, const 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 (*pread)(struct ntfs_device *dev, void *buf, s64 count, s64 offset);
|
||||||
s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count,
|
s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count, s64 offset);
|
||||||
s64 offset);
|
|
||||||
int (*sync)(struct ntfs_device *dev);
|
int (*sync)(struct ntfs_device *dev);
|
||||||
int (*stat)(struct ntfs_device *dev, struct stat *buf);
|
int (*stat)(struct ntfs_device *dev, struct stat *buf);
|
||||||
int (*ioctl)(struct ntfs_device *dev, int request, void *argp);
|
int (*ioctl)(struct ntfs_device *dev, int request, void *argp);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state, struct ntfs_device_operations *dops,
|
||||||
struct ntfs_device_operations *dops, void *priv_data);
|
void *priv_data);
|
||||||
extern int ntfs_device_free(struct ntfs_device *dev);
|
extern int ntfs_device_free(struct ntfs_device *dev);
|
||||||
|
|
||||||
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b);
|
||||||
void *b);
|
extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const 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,
|
extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b);
|
||||||
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_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,
|
extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count, void *b);
|
||||||
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_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_size_get(struct ntfs_device *dev, int block_size);
|
||||||
extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev);
|
extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev);
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
/**
|
/**
|
||||||
* struct hd_geometry -
|
* struct hd_geometry -
|
||||||
*/
|
*/
|
||||||
struct hd_geometry {
|
struct hd_geometry
|
||||||
|
{
|
||||||
unsigned char heads;
|
unsigned char heads;
|
||||||
unsigned char sectors;
|
unsigned char sectors;
|
||||||
unsigned short cylinders;
|
unsigned short cylinders;
|
||||||
@ -70,7 +71,6 @@ struct hd_geometry {
|
|||||||
|
|
||||||
#endif /* __CYGWIN32__ */
|
#endif /* __CYGWIN32__ */
|
||||||
|
|
||||||
|
|
||||||
/* Forward declaration. */
|
/* Forward declaration. */
|
||||||
struct ntfs_device_operations;
|
struct ntfs_device_operations;
|
||||||
|
|
||||||
|
1259
source/libntfs/dir.c
1259
source/libntfs/dir.c
File diff suppressed because it is too large
Load Diff
@ -59,27 +59,21 @@ extern ntfschar NTFS_INDEX_O[3];
|
|||||||
extern ntfschar NTFS_INDEX_Q[3];
|
extern ntfschar NTFS_INDEX_Q[3];
|
||||||
extern ntfschar NTFS_INDEX_R[3];
|
extern ntfschar NTFS_INDEX_R[3];
|
||||||
|
|
||||||
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
|
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname, const int uname_len);
|
||||||
const ntfschar *uname, const int uname_len);
|
|
||||||
extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name);
|
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,
|
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, u64 inum);
|
||||||
u64 inum);
|
|
||||||
|
|
||||||
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, const char *pathname);
|
||||||
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(ntfs_inode *dir_ni, le32 securid,
|
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid, ntfschar *name, u8 name_len, mode_t type,
|
||||||
ntfschar *name, u8 name_len, mode_t type);
|
dev_t dev);
|
||||||
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid, ntfschar *name, u8 name_len, ntfschar *target,
|
||||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev);
|
int target_len);
|
||||||
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_check_empty_dir(ntfs_inode *ni);
|
||||||
extern int ntfs_delete(ntfs_volume *vol, const char *path,
|
extern int ntfs_delete(ntfs_volume *vol, const char *path, ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||||
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,
|
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len);
|
||||||
u8 name_len);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File types (adapted from include <linux/fs.h>)
|
* File types (adapted from include <linux/fs.h>)
|
||||||
@ -100,19 +94,15 @@ extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
|||||||
* This allows the caller to read directories into their application or
|
* This allows the caller to read directories into their application or
|
||||||
* to have different dirent layouts depending on the binary type.
|
* 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 int name_len, const int name_type, const s64 pos,
|
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,
|
extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir);
|
||||||
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,
|
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, char *value, size_t size);
|
||||||
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_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_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||||
|
|
||||||
#if CACHE_INODE_SIZE
|
#if CACHE_INODE_SIZE
|
||||||
|
@ -60,14 +60,14 @@
|
|||||||
|
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
|
|
||||||
static ntfschar logged_utility_stream_name[] = {
|
static ntfschar logged_utility_stream_name[] =
|
||||||
|
{
|
||||||
const_cpu_to_le16('$'),
|
const_cpu_to_le16('$'),
|
||||||
const_cpu_to_le16('E'),
|
const_cpu_to_le16('E'),
|
||||||
const_cpu_to_le16('F'),
|
const_cpu_to_le16('F'),
|
||||||
const_cpu_to_le16('S'),
|
const_cpu_to_le16('S'),
|
||||||
const_cpu_to_le16(0)
|
const_cpu_to_le16(0)
|
||||||
} ;
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the ntfs EFS info into an extended attribute
|
* Get the ntfs EFS info into an extended attribute
|
||||||
@ -78,32 +78,44 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
|||||||
EFS_ATTR_HEADER *efs_info;
|
EFS_ATTR_HEADER *efs_info;
|
||||||
s64 attr_size = 0;
|
s64 attr_size = 0;
|
||||||
|
|
||||||
if (ni) {
|
if (ni)
|
||||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
{
|
||||||
|
if (ni->flags & FILE_ATTR_ENCRYPTED)
|
||||||
|
{
|
||||||
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
|
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
|
||||||
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
|
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
|
||||||
&attr_size);
|
&attr_size);
|
||||||
if (efs_info
|
if (efs_info
|
||||||
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
&& (le32_to_cpu(efs_info->length) == attr_size))
|
||||||
if (attr_size <= (s64)size) {
|
{
|
||||||
|
if (attr_size <= (s64)size)
|
||||||
|
{
|
||||||
if (value)
|
if (value)
|
||||||
memcpy(value,efs_info,attr_size);
|
memcpy(value,efs_info,attr_size);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
if (size) {
|
else
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
free (efs_info);
|
free (efs_info);
|
||||||
} else {
|
}
|
||||||
if (efs_info) {
|
else
|
||||||
|
{
|
||||||
|
if (efs_info)
|
||||||
|
{
|
||||||
free(efs_info);
|
free(efs_info);
|
||||||
ntfs_log_error("Bad efs_info for inode %lld\n",
|
ntfs_log_error("Bad efs_info for inode %lld\n",
|
||||||
(long long)ni->mft_no);
|
(long long)ni->mft_no);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_error("Could not get efsinfo"
|
ntfs_log_error("Could not get efsinfo"
|
||||||
" for inode %lld\n",
|
" for inode %lld\n",
|
||||||
(long long)ni->mft_no);
|
(long long)ni->mft_no);
|
||||||
@ -111,7 +123,9 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
|||||||
errno = EIO;
|
errno = EIO;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
ntfs_log_trace("Inode %lld is not encrypted\n",
|
ntfs_log_trace("Inode %lld is not encrypted\n",
|
||||||
(long long)ni->mft_no);
|
(long long)ni->mft_no);
|
||||||
@ -145,45 +159,57 @@ static int fixup_loop(ntfs_inode *ni)
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
maxcnt = 0;
|
maxcnt = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
restart = FALSE;
|
restart = FALSE;
|
||||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||||
if (!ctx) {
|
if (!ctx)
|
||||||
|
{
|
||||||
ntfs_log_error("Failed to get ctx for efs\n");
|
ntfs_log_error("Failed to get ctx for efs\n");
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
while (!restart && !res
|
while (!restart && !res
|
||||||
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
|
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx))
|
||||||
|
{
|
||||||
cnt++;
|
cnt++;
|
||||||
a = ctx->attr;
|
a = ctx->attr;
|
||||||
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
|
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
|
||||||
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
|
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
|
||||||
a->name_length);
|
a->name_length);
|
||||||
if (!na) {
|
if (!na)
|
||||||
|
{
|
||||||
ntfs_log_error("can't open DATA Attribute\n");
|
ntfs_log_error("can't open DATA Attribute\n");
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
|
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED))
|
||||||
|
{
|
||||||
if (!NAttrNonResident(na)
|
if (!NAttrNonResident(na)
|
||||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
&& ntfs_attr_make_non_resident(na, ctx))
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* ntfs_attr_make_non_resident fails if there
|
* ntfs_attr_make_non_resident fails if there
|
||||||
* is not enough space in the MFT record.
|
* is not enough space in the MFT record.
|
||||||
* When this happens, force making non-resident
|
* When this happens, force making non-resident
|
||||||
* so that some other attribute is expelled.
|
* so that some other attribute is expelled.
|
||||||
*/
|
*/
|
||||||
if (ntfs_attr_force_non_resident(na)) {
|
if (ntfs_attr_force_non_resident(na))
|
||||||
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* make sure there is some progress */
|
/* make sure there is some progress */
|
||||||
if (cnt <= maxcnt) {
|
if (cnt <= maxcnt)
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_error("Multiple failure"
|
ntfs_log_error("Multiple failure"
|
||||||
" making non resident\n");
|
" making non resident\n");
|
||||||
res = -1;
|
res = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_attr_put_search_ctx(ctx);
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||||
restart = TRUE;
|
restart = TRUE;
|
||||||
@ -192,7 +218,8 @@ static int fixup_loop(ntfs_inode *ni)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!restart && !res
|
if (!restart && !res
|
||||||
&& ntfs_efs_fixup_attribute(ctx, na)) {
|
&& ntfs_efs_fixup_attribute(ctx, na))
|
||||||
|
{
|
||||||
ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
|
ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
@ -201,7 +228,7 @@ static int fixup_loop(ntfs_inode *ni)
|
|||||||
ntfs_attr_close(na);
|
ntfs_attr_close(na);
|
||||||
}
|
}
|
||||||
first = FALSE;
|
first = FALSE;
|
||||||
} while (restart && !res);
|
}while (restart && !res);
|
||||||
if (ctx)
|
if (ctx)
|
||||||
ntfs_attr_put_search_ctx(ctx);
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
return (res);
|
return (res);
|
||||||
@ -223,13 +250,18 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
const EFS_ATTR_HEADER *info_header;
|
const EFS_ATTR_HEADER *info_header;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if (ni && value && size) {
|
if (ni && value && size)
|
||||||
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
{
|
||||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED))
|
||||||
|
{
|
||||||
|
if (ni->flags & FILE_ATTR_ENCRYPTED)
|
||||||
|
{
|
||||||
ntfs_log_trace("Inode %lld already encrypted\n",
|
ntfs_log_trace("Inode %lld already encrypted\n",
|
||||||
(long long)ni->mft_no);
|
(long long)ni->mft_no);
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Possible problem : if encrypted file was
|
* Possible problem : if encrypted file was
|
||||||
* restored in a compressed directory, it was
|
* restored in a compressed directory, it was
|
||||||
@ -244,13 +276,16 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
}
|
}
|
||||||
info_header = (const EFS_ATTR_HEADER*)value;
|
info_header = (const EFS_ATTR_HEADER*)value;
|
||||||
/* make sure we get a likely efsinfo */
|
/* 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;
|
errno = EINVAL;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
||||||
(ntfschar*)NULL,0)) {
|
(ntfschar*)NULL,0))
|
||||||
if (!(flags & XATTR_REPLACE)) {
|
{
|
||||||
|
if (!(flags & XATTR_REPLACE))
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* no logged_utility_stream attribute : add one,
|
* no logged_utility_stream attribute : add one,
|
||||||
* apparently, this does not feed the new value in
|
* apparently, this does not feed the new value in
|
||||||
@ -258,28 +293,36 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
|
res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
|
||||||
logged_utility_stream_name,4,
|
logged_utility_stream_name,4,
|
||||||
(u8*)NULL,(s64)size);
|
(u8*)NULL,(s64)size);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* open and update the existing efs data
|
* open and update the existing efs data
|
||||||
*/
|
*/
|
||||||
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
|
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
|
||||||
logged_utility_stream_name, 4);
|
logged_utility_stream_name, 4);
|
||||||
if (na) {
|
if (na)
|
||||||
|
{
|
||||||
/* resize attribute */
|
/* resize attribute */
|
||||||
res = ntfs_attr_truncate(na, (s64)size);
|
res = ntfs_attr_truncate(na, (s64)size);
|
||||||
/* overwrite value if any */
|
/* overwrite value if any */
|
||||||
if (!res && value) {
|
if (!res && value)
|
||||||
|
{
|
||||||
written = (int)ntfs_attr_pwrite(na,
|
written = (int)ntfs_attr_pwrite(na,
|
||||||
(s64)0, (s64)size, value);
|
(s64)0, (s64)size, value);
|
||||||
if (written != (s64)size) {
|
if (written != (s64)size)
|
||||||
|
{
|
||||||
ntfs_log_error("Failed to "
|
ntfs_log_error("Failed to "
|
||||||
"update efs data\n");
|
"update efs data\n");
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -287,12 +330,15 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ntfs_attr_close(na);
|
ntfs_attr_close(na);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res)
|
||||||
|
{
|
||||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
/* 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 */
|
/* iterate over AT_DATA attributes */
|
||||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||||
|
|
||||||
@ -303,7 +349,9 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
|||||||
NInoSetDirty(ni);
|
NInoSetDirty(ni);
|
||||||
NInoFileNameSetDirty(ni);
|
NInoFileNameSetDirty(ni);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
@ -330,24 +378,31 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
BOOL close_ctx = FALSE;
|
BOOL close_ctx = FALSE;
|
||||||
|
|
||||||
if (!na) {
|
if (!na)
|
||||||
|
{
|
||||||
ntfs_log_error("no na specified for efs_fixup_attribute\n");
|
ntfs_log_error("no na specified for efs_fixup_attribute\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (!ctx) {
|
if (!ctx)
|
||||||
|
{
|
||||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||||
if (!ctx) {
|
if (!ctx)
|
||||||
|
{
|
||||||
ntfs_log_error("Failed to get ctx for efs\n");
|
ntfs_log_error("Failed to get ctx for efs\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
close_ctx = TRUE;
|
close_ctx = TRUE;
|
||||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx))
|
||||||
|
{
|
||||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (!NAttrNonResident(na)) {
|
else
|
||||||
|
{
|
||||||
|
if (!NAttrNonResident(na))
|
||||||
|
{
|
||||||
ntfs_log_error("Cannot make non resident"
|
ntfs_log_error("Cannot make non resident"
|
||||||
" when a context has been allocated\n");
|
" when a context has been allocated\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
@ -356,19 +411,23 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
|
|
||||||
/* no extra bytes are added to void attributes */
|
/* no extra bytes are added to void attributes */
|
||||||
oldsize = na->data_size;
|
oldsize = na->data_size;
|
||||||
if (oldsize) {
|
if (oldsize)
|
||||||
|
{
|
||||||
/* make sure size is valid for a raw encrypted stream */
|
/* make sure size is valid for a raw encrypted stream */
|
||||||
if ((oldsize & 511) != 2) {
|
if ((oldsize & 511) != 2)
|
||||||
|
{
|
||||||
ntfs_log_error("Bad raw encrypted stream\n");
|
ntfs_log_error("Bad raw encrypted stream\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* read padding length from last two bytes of attribute */
|
/* read padding length from last two bytes of attribute */
|
||||||
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
|
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2)
|
||||||
|
{
|
||||||
ntfs_log_error("Error reading padding length\n");
|
ntfs_log_error("Error reading padding length\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
padding_length = le16_to_cpu(appended_bytes);
|
padding_length = le16_to_cpu(appended_bytes);
|
||||||
if (padding_length > 511 || padding_length > na->data_size-2) {
|
if (padding_length > 511 || padding_length > na->data_size-2)
|
||||||
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_error("invalid padding length %d for data_size %lld\n",
|
ntfs_log_error("invalid padding length %d for data_size %lld\n",
|
||||||
padding_length, (long long)oldsize);
|
padding_length, (long long)oldsize);
|
||||||
@ -380,11 +439,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
|
* for the last two bytes, but do not truncate to new size
|
||||||
* to avoid losing useful data
|
* to avoid losing useful data
|
||||||
*/
|
*/
|
||||||
if (ntfs_attr_truncate(na, oldsize - 2)) {
|
if (ntfs_attr_truncate(na, oldsize - 2))
|
||||||
|
{
|
||||||
ntfs_log_error("Error truncating attribute\n");
|
ntfs_log_error("Error truncating attribute\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
newsize = 0;
|
newsize = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -394,12 +455,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
* resident.
|
* resident.
|
||||||
*/
|
*/
|
||||||
if (!NAttrNonResident(na)
|
if (!NAttrNonResident(na)
|
||||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
&& ntfs_attr_make_non_resident(na, ctx))
|
||||||
|
{
|
||||||
if (!close_ctx
|
if (!close_ctx
|
||||||
|| ntfs_attr_force_non_resident(na)) {
|
|| ntfs_attr_force_non_resident(na))
|
||||||
|
{
|
||||||
ntfs_log_error("Error making DATA attribute non-resident\n");
|
ntfs_log_error("Error making DATA attribute non-resident\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* must reinitialize context after forcing
|
* must reinitialize context after forcing
|
||||||
* non-resident. We need a context for updating
|
* non-resident. We need a context for updating
|
||||||
@ -408,14 +473,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
*/
|
*/
|
||||||
ntfs_attr_reinit_search_ctx(ctx);
|
ntfs_attr_reinit_search_ctx(ctx);
|
||||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
CASE_SENSITIVE, 0, NULL, 0, ctx))
|
||||||
|
{
|
||||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ni = na->ni;
|
ni = na->ni;
|
||||||
if (!na->name_len) {
|
if (!na->name_len)
|
||||||
|
{
|
||||||
ni->data_size = newsize;
|
ni->data_size = newsize;
|
||||||
ni->allocated_size = na->allocated_size;
|
ni->allocated_size = na->allocated_size;
|
||||||
}
|
}
|
||||||
@ -430,7 +497,7 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
|||||||
ntfs_attr_put_search_ctx(ctx);
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
err_out:
|
err_out:
|
||||||
if (close_ctx && ctx)
|
if (close_ctx && ctx)
|
||||||
ntfs_attr_put_search_ctx(ctx);
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
return (-1);
|
return (-1);
|
||||||
|
@ -23,8 +23,7 @@
|
|||||||
|
|
||||||
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,
|
int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size, int flags);
|
||||||
const char *value, size_t size, int flags);
|
|
||||||
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);
|
||||||
|
|
||||||
#endif /* EFS_H */
|
#endif /* EFS_H */
|
||||||
|
@ -69,7 +69,8 @@
|
|||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -80,32 +81,37 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if (!interface) {
|
if (!interface)
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the device interface and ensure that it is inserted
|
// Start the device interface and ensure that it is inserted
|
||||||
if (!interface->startup()) {
|
if (!interface->startup())
|
||||||
|
{
|
||||||
ntfs_log_perror("device failed to start\n");
|
ntfs_log_perror("device failed to start\n");
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!interface->isInserted()) {
|
if (!interface->isInserted())
|
||||||
|
{
|
||||||
ntfs_log_perror("device media is not inserted\n");
|
ntfs_log_perror("device media is not inserted\n");
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device isn't already open (used by another volume?)
|
// Check that the device isn't already open (used by another volume?)
|
||||||
if (NDevOpen(dev)) {
|
if (NDevOpen(dev))
|
||||||
|
{
|
||||||
ntfs_log_perror("device is busy (already open)\n");
|
ntfs_log_perror("device is busy (already open)\n");
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
return -1;
|
return -1;
|
||||||
@ -113,12 +119,16 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
|||||||
|
|
||||||
// Check that there is a valid NTFS boot sector at the start of the device
|
// Check that there is a valid NTFS boot sector at the start of the device
|
||||||
NTFS_BOOT_SECTOR boot;
|
NTFS_BOOT_SECTOR boot;
|
||||||
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
if (interface->readSectors(fd->startSector, 1, &boot))
|
||||||
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
{
|
||||||
|
if (!ntfs_boot_sector_is_ntfs(&boot))
|
||||||
|
{
|
||||||
errno = EINVALPART;
|
errno = EINVALPART;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ntfs_log_perror("read failure @ sector %d\n", fd->startSector);
|
ntfs_log_perror("read failure @ sector %d\n", fd->startSector);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -133,12 +143,14 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
|||||||
fd->ino = le64_to_cpu(boot.volume_serial_number);
|
fd->ino = le64_to_cpu(boot.volume_serial_number);
|
||||||
|
|
||||||
// Mark the device as read-only (if required)
|
// Mark the device as read-only (if required)
|
||||||
if (flags & O_RDONLY) {
|
if (flags & O_RDONLY)
|
||||||
|
{
|
||||||
NDevSetReadOnly(dev);
|
NDevSetReadOnly(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the cache
|
// 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
|
// Mark the device as open
|
||||||
NDevSetBlock(dev);
|
NDevSetBlock(dev);
|
||||||
@ -156,13 +168,15 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device is actually open
|
// Check that the device is actually open
|
||||||
if (!NDevOpen(dev)) {
|
if (!NDevOpen(dev))
|
||||||
|
{
|
||||||
ntfs_log_perror("device is not open\n");
|
ntfs_log_perror("device is not open\n");
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -173,7 +187,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
|||||||
NDevClearBlock(dev);
|
NDevClearBlock(dev);
|
||||||
|
|
||||||
// Flush the device (if dirty and not read-only)
|
// Flush the device (if dirty and not read-only)
|
||||||
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
if (NDevDirty(dev) && !NDevReadOnly(dev))
|
||||||
|
{
|
||||||
ntfs_log_debug("device is dirty, will now sync\n");
|
ntfs_log_debug("device is dirty, will now sync\n");
|
||||||
|
|
||||||
// ...?
|
// ...?
|
||||||
@ -184,7 +199,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flush and destroy the cache (if required)
|
// Flush and destroy the cache (if required)
|
||||||
if (fd->cache) {
|
if (fd->cache)
|
||||||
|
{
|
||||||
_NTFS_cache_flush(fd->cache);
|
_NTFS_cache_flush(fd->cache);
|
||||||
_NTFS_cache_destructor(fd->cache);
|
_NTFS_cache_destructor(fd->cache);
|
||||||
}
|
}
|
||||||
@ -211,16 +227,24 @@ static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int wh
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the current position on the device (in bytes)
|
// Set the current position on the device (in bytes)
|
||||||
switch(whence) {
|
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_SET:
|
||||||
case SEEK_END: fd->pos = MIN(MAX(fd->len + offset, 0), fd->len); break;
|
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;
|
return 0;
|
||||||
@ -267,26 +291,27 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if (!interface) {
|
if (!interface)
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(offset < 0)
|
if (offset < 0)
|
||||||
{
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!count)
|
if (!count) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
sec_t sec_start = (sec_t) fd->startSector;
|
sec_t sec_start = (sec_t) fd->startSector;
|
||||||
sec_t sec_count = 1;
|
sec_t sec_count = 1;
|
||||||
@ -294,20 +319,24 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
u8 *buffer = NULL;
|
u8 *buffer = NULL;
|
||||||
|
|
||||||
// Determine the range of sectors required for this read
|
// Determine the range of sectors required for this read
|
||||||
if (offset > 0) {
|
if (offset > 0)
|
||||||
|
{
|
||||||
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||||
}
|
}
|
||||||
if (buffer_offset+count > fd->sectorSize) {
|
if (buffer_offset + count > fd->sectorSize)
|
||||||
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) 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 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
|
// Read from the device
|
||||||
ntfs_log_trace("direct read from 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)) {
|
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_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -319,8 +348,9 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Allocate a buffer to hold the read data
|
// Allocate a buffer to hold the read data
|
||||||
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
|
buffer = (u8*) ntfs_alloc(sec_count * fd->sectorSize);
|
||||||
if (!buffer) {
|
if (!buffer)
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -328,7 +358,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
|||||||
// Read from the device
|
// Read from the device
|
||||||
ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
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);
|
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)) {
|
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_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||||
ntfs_free(buffer);
|
ntfs_free(buffer);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -353,31 +384,34 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if (!interface) {
|
if (!interface)
|
||||||
|
{
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device can be written to
|
// Check that the device can be written to
|
||||||
if (NDevReadOnly(dev)) {
|
if (NDevReadOnly(dev))
|
||||||
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count < 0 || offset < 0) {
|
if (count < 0 || offset < 0)
|
||||||
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count == 0)
|
if (count == 0) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
sec_t sec_start = (sec_t) fd->startSector;
|
sec_t sec_start = (sec_t) fd->startSector;
|
||||||
sec_t sec_count = 1;
|
sec_t sec_count = 1;
|
||||||
@ -385,19 +419,22 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
u8 *buffer = NULL;
|
u8 *buffer = NULL;
|
||||||
|
|
||||||
// Determine the range of sectors required for this write
|
// Determine the range of sectors required for this write
|
||||||
if (offset > 0) {
|
if (offset > 0)
|
||||||
|
{
|
||||||
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||||
}
|
}
|
||||||
if ((buffer_offset+count) > fd->sectorSize) {
|
if ((buffer_offset + count) > fd->sectorSize)
|
||||||
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) 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 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
|
// Write to the device
|
||||||
ntfs_log_trace("direct write to 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)) {
|
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_perror("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -408,25 +445,29 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
{
|
{
|
||||||
// Allocate a buffer to hold the write data
|
// Allocate a buffer to hold the write data
|
||||||
buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
|
buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
|
||||||
if (!buffer) {
|
if (!buffer)
|
||||||
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Read the first and last sectors of the buffer from disc (if required)
|
// 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,
|
// 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
|
// 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))
|
||||||
{
|
{
|
||||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
|
||||||
ntfs_log_perror("read failure @ sector %d\n", sec_start);
|
ntfs_log_perror("read failure @ sector %d\n", sec_start);
|
||||||
ntfs_free(buffer);
|
ntfs_free(buffer);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
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)))
|
||||||
{
|
{
|
||||||
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_log_perror("read failure @ sector %d\n", sec_start + sec_count - 1);
|
||||||
ntfs_free(buffer);
|
ntfs_free(buffer);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -439,7 +480,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
|||||||
|
|
||||||
// Write to the device
|
// Write to the device
|
||||||
ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
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)) {
|
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer))
|
||||||
|
{
|
||||||
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
||||||
ntfs_free(buffer);
|
ntfs_free(buffer);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
@ -460,24 +502,26 @@ static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sect
|
|||||||
{
|
{
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Read the sectors from disc (or cache, if enabled)
|
// Read the sectors from disc (or cache, if enabled)
|
||||||
if (fd->cache)
|
if (fd->cache)
|
||||||
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
||||||
else
|
else return fd->interface->readSectors(sector, numSectors, buffer);
|
||||||
return fd->interface->readSectors(sector, numSectors, buffer);
|
|
||||||
|
|
||||||
return false;
|
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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -485,8 +529,7 @@ static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sec
|
|||||||
// Write the sectors to disc (or cache, if enabled)
|
// Write the sectors to disc (or cache, if enabled)
|
||||||
if (fd->cache)
|
if (fd->cache)
|
||||||
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
||||||
else
|
else return fd->interface->writeSectors(sector, numSectors, buffer);
|
||||||
return fd->interface->writeSectors(sector, numSectors, buffer);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -500,7 +543,8 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
|||||||
ntfs_log_trace("dev %p\n", dev);
|
ntfs_log_trace("dev %p\n", dev);
|
||||||
|
|
||||||
// Check that the device can be written to
|
// Check that the device can be written to
|
||||||
if (NDevReadOnly(dev)) {
|
if (NDevReadOnly(dev))
|
||||||
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -509,8 +553,10 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
|||||||
NDevClearDirty(dev);
|
NDevClearDirty(dev);
|
||||||
|
|
||||||
// Flush any sectors in the disc cache (if required)
|
// Flush any sectors in the disc cache (if required)
|
||||||
if (fd->cache) {
|
if (fd->cache)
|
||||||
if (!_NTFS_cache_flush(fd->cache)) {
|
{
|
||||||
|
if (!_NTFS_cache_flush(fd->cache))
|
||||||
|
{
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -528,19 +574,18 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases were we don't actually have to do anything
|
// Short circuit cases were we don't actually have to do anything
|
||||||
if (!buf)
|
if (!buf) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Build the device mode
|
// Build the device mode
|
||||||
mode_t mode = (S_IFBLK) |
|
mode_t mode = (S_IFBLK) | (S_IRUSR | S_IRGRP | S_IROTH)
|
||||||
(S_IRUSR | S_IRGRP | S_IROTH) |
|
| ((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
||||||
((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
|
||||||
|
|
||||||
// Zero out the stat buffer
|
// Zero out the stat buffer
|
||||||
memset(buf, 0, sizeof(struct stat));
|
memset(buf, 0, sizeof(struct stat));
|
||||||
@ -565,33 +610,38 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
|
|
||||||
// Get the device driver descriptor
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD(dev);
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if (!fd) {
|
if (!fd)
|
||||||
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out which i/o control was requested
|
// Figure out which i/o control was requested
|
||||||
switch (request) {
|
switch (request)
|
||||||
|
{
|
||||||
|
|
||||||
// Get block device size (sectors)
|
// Get block device size (sectors)
|
||||||
#if defined(BLKGETSIZE)
|
#if defined(BLKGETSIZE)
|
||||||
case BLKGETSIZE: {
|
case BLKGETSIZE:
|
||||||
|
{
|
||||||
*(u32*)argp = fd->sectorCount;
|
*(u32*)argp = fd->sectorCount;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get block device size (bytes)
|
// Get block device size (bytes)
|
||||||
#if defined(BLKGETSIZE64)
|
#if defined(BLKGETSIZE64)
|
||||||
case BLKGETSIZE64: {
|
case BLKGETSIZE64:
|
||||||
|
{
|
||||||
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get hard drive geometry
|
// Get hard drive geometry
|
||||||
#if defined(HDIO_GETGEO)
|
#if defined(HDIO_GETGEO)
|
||||||
case HDIO_GETGEO: {
|
case HDIO_GETGEO:
|
||||||
|
{
|
||||||
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
||||||
geo->sectors = 0;
|
geo->sectors = 0;
|
||||||
geo->heads = 0;
|
geo->heads = 0;
|
||||||
@ -599,27 +649,30 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
|||||||
geo->start = fd->hiddenSectors;
|
geo->start = fd->hiddenSectors;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get block device sector size (bytes)
|
// Get block device sector size (bytes)
|
||||||
#if defined(BLKSSZGET)
|
#if defined(BLKSSZGET)
|
||||||
case BLKSSZGET: {
|
case BLKSSZGET:
|
||||||
|
{
|
||||||
*(int*)argp = fd->sectorSize;
|
*(int*)argp = fd->sectorSize;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set block device block size (bytes)
|
// Set block device block size (bytes)
|
||||||
#if defined(BLKBSZSET)
|
#if defined(BLKBSZSET)
|
||||||
case BLKBSZSET: {
|
case BLKBSZSET:
|
||||||
|
{
|
||||||
int sectorSize = *(int*)argp;
|
int sectorSize = *(int*)argp;
|
||||||
fd->sectorSize = sectorSize;
|
fd->sectorSize = sectorSize;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Unimplemented ioctrl
|
// Unimplemented ioctrl
|
||||||
default: {
|
default:
|
||||||
|
{
|
||||||
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
return -1;
|
return -1;
|
||||||
@ -633,15 +686,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.
|
* 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,
|
||||||
.open = ntfs_device_gekko_io_open,
|
.close = ntfs_device_gekko_io_close, .seek = ntfs_device_gekko_io_seek, .read = ntfs_device_gekko_io_read,
|
||||||
.close = ntfs_device_gekko_io_close,
|
.write = ntfs_device_gekko_io_write, .pread = ntfs_device_gekko_io_pread,
|
||||||
.seek = ntfs_device_gekko_io_seek,
|
.pwrite = ntfs_device_gekko_io_pwrite, .sync = ntfs_device_gekko_io_sync, .stat = ntfs_device_gekko_io_stat,
|
||||||
.read = ntfs_device_gekko_io_read,
|
.ioctl = ntfs_device_gekko_io_ioctl, };
|
||||||
.write = ntfs_device_gekko_io_write,
|
|
||||||
.pread = ntfs_device_gekko_io_pread,
|
|
||||||
.pwrite = ntfs_device_gekko_io_pwrite,
|
|
||||||
.sync = ntfs_device_gekko_io_sync,
|
|
||||||
.stat = ntfs_device_gekko_io_stat,
|
|
||||||
.ioctl = ntfs_device_gekko_io_ioctl,
|
|
||||||
};
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
* gekko_io.h - Platform specifics for device io.
|
* gekko_io.h - Platform specifics for device io.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
||||||
*
|
*
|
||||||
* This program/include file is free software; you can redistribute it and/or
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as published
|
* modify it under the terms of the GNU General Public License as published
|
||||||
* by the Free Software Foundation; either version 2 of the License, or
|
* by the Free Software Foundation; either version 2 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program/include file is distributed in the hope that it will be
|
* This program/include file is distributed in the hope that it will be
|
||||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _GEKKO_IO_H
|
#ifndef _GEKKO_IO_H
|
||||||
#define _GEKKO_IO_H
|
#define _GEKKO_IO_H
|
||||||
@ -33,7 +33,8 @@
|
|||||||
/**
|
/**
|
||||||
* gekko_fd - Gekko device driver descriptor
|
* gekko_fd - Gekko device driver descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct _gekko_fd {
|
typedef struct _gekko_fd
|
||||||
|
{
|
||||||
const DISC_INTERFACE* interface; /* Device disc interface */
|
const DISC_INTERFACE* interface; /* Device disc interface */
|
||||||
sec_t startSector; /* LBA of partition start */
|
sec_t startSector; /* LBA of partition start */
|
||||||
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
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,7 @@
|
|||||||
|
|
||||||
#define MAX_PARENT_VCN 32
|
#define MAX_PARENT_VCN 32
|
||||||
|
|
||||||
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1, const void *data2, int len2);
|
||||||
const void *data2, int len2);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ntfs_index_context -
|
* struct ntfs_index_context -
|
||||||
@ -112,7 +111,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
|
* the call to ntfs_index_ctx_put() to ensure that the changes are written
|
||||||
* to disk.
|
* to disk.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
ntfschar *name;
|
ntfschar *name;
|
||||||
u32 name_len;
|
u32 name_len;
|
||||||
@ -133,21 +133,16 @@ typedef struct {
|
|||||||
u8 vcn_size_bits;
|
u8 vcn_size_bits;
|
||||||
} ntfs_index_context;
|
} ntfs_index_context;
|
||||||
|
|
||||||
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, ntfschar *name, u32 name_len);
|
||||||
ntfschar *name, u32 name_len);
|
|
||||||
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
|
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
|
||||||
extern void ntfs_index_ctx_reinit(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,
|
extern int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ictx) __attribute_warn_unused_result__;
|
||||||
ntfs_index_context *ictx) __attribute_warn_unused_result__;
|
|
||||||
|
|
||||||
extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie,
|
extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx);
|
||||||
ntfs_index_context *ictx);
|
|
||||||
|
|
||||||
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref);
|
||||||
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_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);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -40,7 +40,8 @@ typedef struct _ntfs_inode ntfs_inode;
|
|||||||
* Defined bits for the state field in the ntfs_inode structure.
|
* Defined bits for the state field in the ntfs_inode structure.
|
||||||
* (f) = files only, (d) = directories only
|
* (f) = files only, (d) = directories only
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||||
|
|
||||||
/* The NI_AttrList* tests only make sense for base inodes. */
|
/* The NI_AttrList* tests only make sense for base inodes. */
|
||||||
@ -51,7 +52,8 @@ typedef enum {
|
|||||||
in the index. */
|
in the index. */
|
||||||
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
|
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
|
||||||
NI_TimesSet, /* 1: Use times which were set */
|
NI_TimesSet, /* 1: Use times which were set */
|
||||||
NI_KnownSize, /* 1: Set if sizes are meaningful */
|
NI_KnownSize,
|
||||||
|
/* 1: Set if sizes are meaningful */
|
||||||
} ntfs_inode_state_bits;
|
} ntfs_inode_state_bits;
|
||||||
|
|
||||||
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
|
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
|
||||||
@ -73,7 +75,6 @@ typedef enum {
|
|||||||
#define NInoSetAttrList(ni) set_nino_flag(ni, AttrList)
|
#define NInoSetAttrList(ni) set_nino_flag(ni, AttrList)
|
||||||
#define NInoClearAttrList(ni) clear_nino_flag(ni, AttrList)
|
#define NInoClearAttrList(ni) clear_nino_flag(ni, AttrList)
|
||||||
|
|
||||||
|
|
||||||
#define test_nino_al_flag(ni, flag) test_nino_flag(ni, AttrList##flag)
|
#define test_nino_al_flag(ni, flag) test_nino_flag(ni, AttrList##flag)
|
||||||
#define set_nino_al_flag(ni, flag) set_nino_flag(ni, AttrList##flag)
|
#define set_nino_al_flag(ni, flag) set_nino_flag(ni, AttrList##flag)
|
||||||
#define clear_nino_al_flag(ni, flag) clear_nino_flag(ni, AttrList##flag)
|
#define clear_nino_al_flag(ni, flag) clear_nino_flag(ni, AttrList##flag)
|
||||||
@ -103,7 +104,8 @@ typedef enum {
|
|||||||
* It is just used as an extension to the fields already provided in the VFS
|
* It is just used as an extension to the fields already provided in the VFS
|
||||||
* inode.
|
* inode.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_inode {
|
struct _ntfs_inode
|
||||||
|
{
|
||||||
u64 mft_no; /* Inode / mft record number. */
|
u64 mft_no; /* Inode / mft record number. */
|
||||||
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
||||||
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
||||||
@ -122,7 +124,8 @@ struct _ntfs_inode {
|
|||||||
s32 nr_extents; /* For a base mft record, the number of
|
s32 nr_extents; /* For a base mft record, the number of
|
||||||
attached extent inodes (0 if none), for
|
attached extent inodes (0 if none), for
|
||||||
extent records this is -1. */
|
extent records this is -1. */
|
||||||
union { /* This union is only used if nr_extents != 0. */
|
union
|
||||||
|
{ /* This union is only used if nr_extents != 0. */
|
||||||
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
||||||
ntfs inodes of the extent mft
|
ntfs inodes of the extent mft
|
||||||
records belonging to this base
|
records belonging to this base
|
||||||
@ -166,10 +169,9 @@ struct _ntfs_inode {
|
|||||||
le64 usn;
|
le64 usn;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
NTFS_UPDATE_ATIME = 1 << 0,
|
{
|
||||||
NTFS_UPDATE_MTIME = 1 << 1,
|
NTFS_UPDATE_ATIME = 1 << 0, NTFS_UPDATE_MTIME = 1 << 1, NTFS_UPDATE_CTIME = 1 << 2,
|
||||||
NTFS_UPDATE_CTIME = 1 << 2,
|
|
||||||
} ntfs_time_update_flags;
|
} ntfs_time_update_flags;
|
||||||
|
|
||||||
#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME)
|
#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME)
|
||||||
@ -195,9 +197,7 @@ extern int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref);
|
||||||
extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
|
|
||||||
const MFT_REF mref);
|
|
||||||
|
|
||||||
extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
|
extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
|
||||||
|
|
||||||
@ -215,8 +215,7 @@ extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a);
|
|||||||
|
|
||||||
extern int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size);
|
extern int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size);
|
||||||
|
|
||||||
extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value,
|
extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, int flags);
|
||||||
size_t size, int flags);
|
|
||||||
|
|
||||||
/* debugging */
|
/* debugging */
|
||||||
#define debug_double_inode(num, type)
|
#define debug_double_inode(num, type)
|
||||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user