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">
|
||||
<name> USB Loader GX</name>
|
||||
<coder>USB Loader GX Team</coder>
|
||||
<version>1.0 r961</version>
|
||||
<release_date>201009222057</release_date>
|
||||
<version>1.0 r962</version>
|
||||
<release_date>201009232353</release_date>
|
||||
<short_description>Loads games from USB-devices</short_description>
|
||||
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
||||
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||
|
@ -32,14 +32,12 @@ static u32 MainFontSize = font_ttf_size;
|
||||
|
||||
void ClearFontData()
|
||||
{
|
||||
if ( fontSystem )
|
||||
delete fontSystem;
|
||||
if (fontSystem) delete fontSystem;
|
||||
fontSystem = NULL;
|
||||
|
||||
if (MainFont != (FT_Byte *) font_ttf)
|
||||
{
|
||||
if ( MainFont != NULL )
|
||||
delete [] MainFont;
|
||||
if (MainFont != NULL) delete[] MainFont;
|
||||
MainFont = (FT_Byte *) font_ttf;
|
||||
MainFontSize = font_ttf_size;
|
||||
}
|
||||
@ -52,8 +50,7 @@ bool SetupDefaultFont( const char *path )
|
||||
|
||||
ClearFontData();
|
||||
|
||||
if ( path )
|
||||
pfile = fopen( path, "rb" );
|
||||
if (path) pfile = fopen(path, "rb");
|
||||
|
||||
if (pfile)
|
||||
{
|
||||
|
@ -36,12 +36,10 @@ using namespace std;
|
||||
|
||||
wchar_t* charToWideChar(const char* strChar)
|
||||
{
|
||||
if ( !strChar )
|
||||
return NULL;
|
||||
if (!strChar) return NULL;
|
||||
|
||||
wchar_t *strWChar = new (std::nothrow) wchar_t[strlen(strChar) + 1];
|
||||
if ( !strWChar )
|
||||
return NULL;
|
||||
if (!strWChar) return NULL;
|
||||
|
||||
int bt = mbstowcs(strWChar, strChar, strlen(strChar));
|
||||
if (bt > 0)
|
||||
@ -51,7 +49,8 @@ wchar_t* charToWideChar( const char* strChar )
|
||||
}
|
||||
|
||||
wchar_t *tempDest = strWChar;
|
||||
while ( ( *tempDest++ = *strChar++ ) );
|
||||
while ((*tempDest++ = *strChar++))
|
||||
;
|
||||
|
||||
return strWChar;
|
||||
}
|
||||
@ -104,8 +103,7 @@ void FreeTypeGX::setVertexFormat( uint8_t vertexInd )
|
||||
*/
|
||||
void FreeTypeGX::unloadFont()
|
||||
{
|
||||
if ( this->fontData.size() == 0 )
|
||||
return;
|
||||
if (this->fontData.size() == 0) return;
|
||||
|
||||
map<int16_t, map<wchar_t, ftgxCharData> >::iterator itr;
|
||||
map<wchar_t, ftgxCharData>::iterator itr2;
|
||||
@ -208,8 +206,7 @@ uint16_t FreeTypeGX::cacheGlyphDataComplete( int16_t pixelSize )
|
||||
FT_ULong charCode = FT_Get_First_Char(ftFace, &gIndex);
|
||||
while (gIndex != 0)
|
||||
{
|
||||
if ( cacheGlyphData( charCode, pixelSize ) != NULL )
|
||||
++i;
|
||||
if (cacheGlyphData(charCode, pixelSize) != NULL) ++i;
|
||||
charCode = FT_Get_Next_Char(ftFace, charCode, &gIndex);
|
||||
}
|
||||
return (uint16_t) (i);
|
||||
@ -232,8 +229,7 @@ void FreeTypeGX::loadGlyphData( FT_Bitmap *bmp, ftgxCharData *charData )
|
||||
int length = ((((charData->textureWidth + 3) >> 2) * ((charData->textureHeight + 3) >> 2) * 32 * 2 + 31) & ~31);
|
||||
|
||||
uint8_t * glyphData = (uint8_t *) memalign(32, length);
|
||||
if ( !glyphData )
|
||||
return;
|
||||
if (!glyphData) return;
|
||||
|
||||
memset(glyphData, 0x00, length);
|
||||
|
||||
@ -244,7 +240,8 @@ void FreeTypeGX::loadGlyphData( FT_Bitmap *bmp, ftgxCharData *charData )
|
||||
{
|
||||
for (int imagePosX = 0; imagePosX < bmp->width; ++imagePosX)
|
||||
{
|
||||
offset = ( ( ( ( imagePosY >> 2 ) * ( charData->textureWidth >> 2 ) + ( imagePosX >> 2 ) ) << 5 ) + ( ( imagePosY & 3 ) << 2 ) + ( imagePosX & 3 ) ) << 1;
|
||||
offset = ((((imagePosY >> 2) * (charData->textureWidth >> 2) + (imagePosX >> 2)) << 5) + ((imagePosY & 3)
|
||||
<< 2) + (imagePosX & 3)) << 1;
|
||||
glyphData[offset] = *src;
|
||||
glyphData[offset + 1] = *src;
|
||||
glyphData[offset + 32] = *src;
|
||||
@ -271,8 +268,7 @@ int16_t FreeTypeGX::getStyleOffsetWidth( uint16_t width, uint16_t format )
|
||||
return 0;
|
||||
else if (format & FTGX_JUSTIFY_CENTER)
|
||||
return -(width >> 1);
|
||||
else if ( format & FTGX_JUSTIFY_RIGHT )
|
||||
return -width;
|
||||
else if (format & FTGX_JUSTIFY_RIGHT) return -width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -287,8 +283,7 @@ int16_t FreeTypeGX::getStyleOffsetWidth( uint16_t width, uint16_t format )
|
||||
int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize)
|
||||
{
|
||||
map<int16_t, ftgxDataOffset>::iterator itrAlign = ftgxAlign.find(pixelSize);
|
||||
if ( itrAlign == ftgxAlign.end() )
|
||||
return 0;
|
||||
if (itrAlign == ftgxAlign.end()) return 0;
|
||||
|
||||
switch (format & FTGX_ALIGN_MASK)
|
||||
{
|
||||
@ -330,10 +325,10 @@ int16_t FreeTypeGX::getStyleOffsetHeight( int16_t format, uint16_t pixelSize )
|
||||
* @param textStyle Flags which specify any styling which should be applied to the rendered string.
|
||||
* @return The number of characters printed.
|
||||
*/
|
||||
uint16_t FreeTypeGX::drawText( int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color, uint16_t textStyle, uint16_t textWidth, uint16_t widthLimit )
|
||||
uint16_t FreeTypeGX::drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color,
|
||||
uint16_t textStyle, uint16_t textWidth, uint16_t widthLimit)
|
||||
{
|
||||
if ( !text )
|
||||
return 0;
|
||||
if (!text) return 0;
|
||||
|
||||
uint16_t fullTextWidth = textWidth > 0 ? textWidth : getWidth(text, pixelSize);
|
||||
uint16_t x_pos = x, printed = 0;
|
||||
@ -354,8 +349,7 @@ uint16_t FreeTypeGX::drawText( int16_t x, int16_t y, int16_t z, const wchar_t *t
|
||||
|
||||
while (text[i])
|
||||
{
|
||||
if ( widthLimit > 0 && ( x_pos - x ) > widthLimit )
|
||||
break;
|
||||
if (widthLimit > 0 && (x_pos - x) > widthLimit) break;
|
||||
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
|
||||
@ -363,12 +357,15 @@ uint16_t FreeTypeGX::drawText( int16_t x, int16_t y, int16_t z, const wchar_t *t
|
||||
{
|
||||
if (ftKerningEnabled && i > 0)
|
||||
{
|
||||
FT_Get_Kerning( ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
|
||||
FT_Get_Kerning(ftFace, fontData[pixelSize][text[i - 1]].glyphIndex, glyphData->glyphIndex,
|
||||
FT_KERNING_DEFAULT, &pairDelta);
|
||||
x_pos += pairDelta.x >> 6;
|
||||
}
|
||||
|
||||
GX_InitTexObj( &glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth, glyphData->textureHeight, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE );
|
||||
copyTextureToFramebuffer( &glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos + glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, z, color );
|
||||
GX_InitTexObj(&glyphTexture, glyphData->glyphDataTexture, glyphData->textureWidth,
|
||||
glyphData->textureHeight, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
copyTextureToFramebuffer(&glyphTexture, glyphData->textureWidth, glyphData->textureHeight, x_pos
|
||||
+ glyphData->renderOffsetX + x_offset, y - glyphData->renderOffsetY + y_offset, z, color);
|
||||
|
||||
x_pos += glyphData->glyphAdvanceX;
|
||||
++printed;
|
||||
@ -379,21 +376,22 @@ uint16_t FreeTypeGX::drawText( int16_t x, int16_t y, int16_t z, const wchar_t *t
|
||||
if (textStyle & FTGX_STYLE_MASK)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void FreeTypeGX::drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color )
|
||||
void FreeTypeGX::drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width,
|
||||
ftgxDataOffset *offsetData, uint16_t format, GXColor color)
|
||||
{
|
||||
uint16_t featureHeight = pixelSize >> 4 > 0 ? pixelSize >> 4 : 1;
|
||||
|
||||
if ( format & FTGX_STYLE_UNDERLINE )
|
||||
this->copyFeatureToFramebuffer( width, featureHeight, x, y + 1, z, color );
|
||||
if (format & FTGX_STYLE_UNDERLINE) this->copyFeatureToFramebuffer(width, featureHeight, x, y + 1, z, color);
|
||||
|
||||
if ( format & FTGX_STYLE_STRIKE )
|
||||
this->copyFeatureToFramebuffer( width, featureHeight, x, y - ( ( offsetData->max ) >> 1 ), z, color );
|
||||
if (format & FTGX_STYLE_STRIKE) this->copyFeatureToFramebuffer(width, featureHeight, x, y
|
||||
- ((offsetData->max) >> 1), z, color);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,8 +405,7 @@ void FreeTypeGX::drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixel
|
||||
*/
|
||||
uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize)
|
||||
{
|
||||
if ( !text )
|
||||
return 0;
|
||||
if (!text) return 0;
|
||||
|
||||
uint16_t strWidth = 0;
|
||||
FT_Vector pairDelta;
|
||||
@ -422,7 +419,8 @@ uint16_t FreeTypeGX::getWidth( const wchar_t *text, int16_t pixelSize )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -446,7 +444,8 @@ uint16_t FreeTypeGX::getCharWidth( const wchar_t wChar, int16_t pixelSize, const
|
||||
if (ftKerningEnabled && prevChar != 0x0000)
|
||||
{
|
||||
FT_Vector pairDelta;
|
||||
FT_Get_Kerning( ftFace, fontData[pixelSize][prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta );
|
||||
FT_Get_Kerning(ftFace, fontData[pixelSize][prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT,
|
||||
&pairDelta);
|
||||
strWidth += pairDelta.x >> 6;
|
||||
}
|
||||
strWidth += glyphData->glyphAdvanceX;
|
||||
@ -483,8 +482,7 @@ uint16_t FreeTypeGX::getHeight( const wchar_t *text, int16_t pixelSize )
|
||||
*/
|
||||
void FreeTypeGX::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit)
|
||||
{
|
||||
if ( ftgxAlign.find( pixelSize ) != ftgxAlign.end() )
|
||||
return;
|
||||
if (ftgxAlign.find(pixelSize) != ftgxAlign.end()) return;
|
||||
|
||||
int16_t strMax = 0, strMin = 9999;
|
||||
uint16_t currWidth = 0;
|
||||
@ -493,8 +491,7 @@ void FreeTypeGX::getOffset( const wchar_t *text, int16_t pixelSize, uint16_t wid
|
||||
|
||||
while (text[i])
|
||||
{
|
||||
if ( widthLimit > 0 && currWidth >= widthLimit )
|
||||
break;
|
||||
if (widthLimit > 0 && currWidth >= widthLimit) break;
|
||||
|
||||
ftgxCharData* glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
|
||||
@ -532,7 +529,8 @@ 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 color Color to apply to the texture.
|
||||
*/
|
||||
void FreeTypeGX::copyTextureToFramebuffer( GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color )
|
||||
void FreeTypeGX::copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX,
|
||||
int16_t screenY, int16_t screenZ, GXColor color)
|
||||
{
|
||||
GX_LoadTexObj(texObj, GX_TEXMAP0);
|
||||
GX_InvalidateTexAll();
|
||||
@ -573,7 +571,8 @@ void FreeTypeGX::copyTextureToFramebuffer( GXTexObj *texObj, f32 texWidth, f32 t
|
||||
* @param screenY The screen Y coordinate at which to output the quad.
|
||||
* @param color Color to apply to the texture.
|
||||
*/
|
||||
void FreeTypeGX::copyFeatureToFramebuffer( f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color )
|
||||
void FreeTypeGX::copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY,
|
||||
int16_t screenZ, GXColor color)
|
||||
{
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
||||
|
@ -89,7 +89,8 @@ typedef struct ftgxDataOffset_ ftgxDataOffset;
|
||||
#define FTGX_STYLE_STRIKE 0x2000
|
||||
#define FTGX_STYLE_MASK 0xf000
|
||||
|
||||
const GXColor ftgxWhite = ( GXColor ) {0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */
|
||||
const GXColor ftgxWhite = ( GXColor )
|
||||
{ 0xff, 0xff, 0xff, 0xff}; /**< Constant color value used only to sanitize Doxygen documentation. */
|
||||
|
||||
wchar_t* charToWideChar(const char* p);
|
||||
|
||||
@ -123,9 +124,12 @@ class FreeTypeGX
|
||||
|
||||
void setDefaultMode();
|
||||
|
||||
void drawTextFeature( int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width, ftgxDataOffset *offsetData, uint16_t format, GXColor color );
|
||||
void copyTextureToFramebuffer( GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color );
|
||||
void copyFeatureToFramebuffer( f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY, int16_t screenZ, GXColor color );
|
||||
void drawTextFeature(int16_t x, int16_t y, int16_t z, int16_t pixelSize, uint16_t width,
|
||||
ftgxDataOffset *offsetData, uint16_t format, GXColor color);
|
||||
void copyTextureToFramebuffer(GXTexObj *texObj, f32 texWidth, f32 texHeight, int16_t screenX, int16_t screenY,
|
||||
int16_t screenZ, GXColor color);
|
||||
void copyFeatureToFramebuffer(f32 featureWidth, f32 featureHeight, int16_t screenX, int16_t screenY,
|
||||
int16_t screenZ, GXColor color);
|
||||
|
||||
public:
|
||||
FreeTypeGX(const uint8_t* fontBuffer, FT_Long bufferSize);
|
||||
@ -133,7 +137,8 @@ class FreeTypeGX
|
||||
|
||||
void setVertexFormat(uint8_t vertexIndex);
|
||||
|
||||
uint16_t drawText( int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color = ftgxWhite, uint16_t textStyling = FTGX_NULL, uint16_t textWidth = 0, uint16_t widthLimit = 0 );
|
||||
uint16_t drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, GXColor color =
|
||||
ftgxWhite, uint16_t textStyling = FTGX_NULL, uint16_t textWidth = 0, uint16_t widthLimit = 0);
|
||||
|
||||
uint16_t getWidth(const wchar_t *text, int16_t pixelSize);
|
||||
uint16_t getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000);
|
||||
|
@ -42,8 +42,7 @@
|
||||
ZipFile::ZipFile(const char *filepath)
|
||||
{
|
||||
File = unzOpen(filepath);
|
||||
if ( File )
|
||||
this->LoadList();
|
||||
if (File) this->LoadList();
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile()
|
||||
@ -58,29 +57,26 @@ bool ZipFile::LoadList()
|
||||
|
||||
bool ZipFile::ExtractAll(const char *dest)
|
||||
{
|
||||
if ( !File )
|
||||
return false;
|
||||
if (!File) return false;
|
||||
|
||||
bool Stop = false;
|
||||
|
||||
u32 blocksize = 1024 * 50;
|
||||
u8 *buffer = new u8[blocksize];
|
||||
|
||||
if ( !buffer )
|
||||
return false;
|
||||
if (!buffer) return false;
|
||||
|
||||
char writepath[MAXPATHLEN];
|
||||
char filename[MAXPATHLEN];
|
||||
memset(filename, 0, sizeof(filename));
|
||||
|
||||
int ret = unzGoToFirstFile(File);
|
||||
if ( ret != UNZ_OK )
|
||||
Stop = true;
|
||||
if (ret != UNZ_OK) Stop = true;
|
||||
|
||||
while (!Stop)
|
||||
{
|
||||
if ( unzGetCurrentFileInfo( File, &cur_file_info, filename, sizeof( filename ), NULL, NULL, NULL, NULL ) != UNZ_OK )
|
||||
Stop = true;
|
||||
if (unzGetCurrentFileInfo(File, &cur_file_info, filename, sizeof(filename), NULL, NULL, NULL, NULL) != UNZ_OK) Stop
|
||||
= true;
|
||||
|
||||
if (!Stop && filename[strlen(filename) - 1] != '/')
|
||||
{
|
||||
@ -109,27 +105,23 @@ bool ZipFile::ExtractAll( const char *dest )
|
||||
{
|
||||
ShowProgress(tr( "Extracting files..." ), 0, pointer + 1, done, uncompressed_size);
|
||||
|
||||
if ( uncompressed_size - done < blocksize )
|
||||
blocksize = uncompressed_size - done;
|
||||
if (uncompressed_size - done < blocksize) blocksize = uncompressed_size - done;
|
||||
|
||||
ret = unzReadCurrentFile(File, buffer, blocksize);
|
||||
|
||||
if ( ret == 0 )
|
||||
break;
|
||||
if (ret == 0) break;
|
||||
|
||||
fwrite(buffer, 1, blocksize, pfile);
|
||||
|
||||
done += ret;
|
||||
|
||||
}
|
||||
while ( done < uncompressed_size );
|
||||
} while (done < uncompressed_size);
|
||||
|
||||
fclose(pfile);
|
||||
unzCloseCurrentFile(File);
|
||||
}
|
||||
}
|
||||
if ( unzGoToNextFile( File ) != UNZ_OK )
|
||||
Stop = true;
|
||||
if (unzGoToNextFile(File) != UNZ_OK) Stop = true;
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
|
@ -86,7 +86,6 @@
|
||||
|
||||
#include "MD5.h"
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Static Constants:
|
||||
*
|
||||
@ -110,46 +109,34 @@
|
||||
* 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). */
|
||||
{ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, /* R2 */
|
||||
{ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, /* R3 */
|
||||
{ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 } /* R4 */
|
||||
};
|
||||
|
||||
static const uint8_t S[4][4] =
|
||||
{
|
||||
{ 7, 12, 17, 22 }, /* Round 1 */
|
||||
static const uint8_t S[4][4] = { { 7, 12, 17, 22 }, /* Round 1 */
|
||||
{ 5, 9, 14, 20 }, /* Round 2 */
|
||||
{ 4, 11, 16, 23 }, /* Round 3 */
|
||||
{ 6, 10, 15, 21 } /* Round 4 */
|
||||
};
|
||||
|
||||
|
||||
static const uint32_t T[4][16] =
|
||||
{
|
||||
{ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 },
|
||||
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 },
|
||||
|
||||
{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a },
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
|
||||
0x676f02d9, 0x8d2a4c8a },
|
||||
|
||||
{ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 },
|
||||
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 },
|
||||
};
|
||||
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235,
|
||||
0x2ad7d2bb, 0xeb86d391 }, };
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Macros:
|
||||
@ -172,7 +159,6 @@ static const uint32_t T[4][16] =
|
||||
|
||||
#define STR2HEX(x) ((x >= 0x30) && (x <= 0x39)) ? x - 0x30 : toupper((int)x)-0x37
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Static Functions:
|
||||
*/
|
||||
@ -295,7 +281,6 @@ static void Permute( uint32_t ABCD[4], const unsigned char block[64] )
|
||||
|
||||
} /* Permute */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions:
|
||||
*/
|
||||
@ -347,10 +332,7 @@ auth_md5Ctx *auth_md5InitCtx( auth_md5Ctx *ctx )
|
||||
return (ctx);
|
||||
} /* 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.
|
||||
*
|
||||
@ -392,7 +374,6 @@ auth_md5Ctx *auth_md5SumCtx( auth_md5Ctx *ctx,
|
||||
return (ctx);
|
||||
} /* auth_md5SumCtx */
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst)
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
@ -466,7 +447,6 @@ auth_md5Ctx *auth_md5CloseCtx( auth_md5Ctx *ctx, unsigned char *dst )
|
||||
return (ctx);
|
||||
} /* auth_md5CloseCtx */
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len)
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
@ -510,8 +490,6 @@ unsigned char * MD5( unsigned char *dst, const unsigned char *src, const int len
|
||||
return (dst); /* Makes life easy. */
|
||||
} /* auth_md5Sum */
|
||||
|
||||
|
||||
|
||||
unsigned char * MD5fromFile(unsigned char *dst, const char *src)
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
@ -565,8 +543,7 @@ unsigned char * MD5fromFile( unsigned char *dst, const char *src )
|
||||
|
||||
if (filesize < 1048576) //1MB cache for files bigger than 1 MB
|
||||
blksize = filesize;
|
||||
else
|
||||
blksize = 1048576;
|
||||
else blksize = 1048576;
|
||||
|
||||
unsigned char * buffer = malloc(blksize);
|
||||
|
||||
@ -582,8 +559,7 @@ unsigned char * MD5fromFile( unsigned char *dst, const char *src )
|
||||
read = fread(buffer, 1, blksize, file);
|
||||
(void) auth_md5SumCtx(ctx, buffer, read); /* Pass only one block. */
|
||||
|
||||
}
|
||||
while ( read > 0 );
|
||||
} while (read > 0);
|
||||
|
||||
fclose(file);
|
||||
free(buffer);
|
||||
@ -593,7 +569,6 @@ unsigned char * MD5fromFile( unsigned char *dst, const char *src )
|
||||
return (dst); /* Makes life easy. */
|
||||
} /* auth_md5Sum */
|
||||
|
||||
|
||||
const char * MD5ToString(const unsigned char * hash, char * dst)
|
||||
{
|
||||
char hexchar[3];
|
||||
@ -630,5 +605,4 @@ unsigned char * StringToMD5( const char * hash, unsigned char * dst )
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
@ -5,6 +5,7 @@
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* ========================================================================== **
|
||||
*
|
||||
* MD5.h
|
||||
@ -93,7 +94,6 @@ extern "C"
|
||||
unsigned char block[64];
|
||||
} auth_md5Ctx;
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions:
|
||||
*/
|
||||
@ -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.
|
||||
*
|
||||
@ -147,7 +144,6 @@ extern "C"
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst);
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Close an MD5 Message Digest context and generate the final MD5 sum.
|
||||
@ -168,7 +164,6 @@ extern "C"
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
|
||||
|
||||
unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len);
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Compute an MD5 message digest.
|
||||
|
@ -34,8 +34,7 @@ s32 dump_banner( const u8* discid, const char * dest )
|
||||
s32 ret;
|
||||
|
||||
ret = __Disc_FindPartition(&offset);
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
if (ret < 0) return ret;
|
||||
|
||||
ret = WDVD_OpenPartition(offset);
|
||||
|
||||
@ -55,8 +54,7 @@ s32 dump_banner( const u8* discid, const char * dest )
|
||||
}
|
||||
|
||||
ret = WDVD_Read(buffer, 0x20, 0x420);
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
if (ret < 0) return ret;
|
||||
|
||||
// Read fst.bin
|
||||
void *fstbuffer = memalign(32, buffer[2] * 4);
|
||||
@ -70,8 +68,7 @@ s32 dump_banner( const u8* discid, const char * dest )
|
||||
}
|
||||
|
||||
ret = WDVD_Read(fstbuffer, buffer[2] * 4, buffer[1] * 4);
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
if (ret < 0) return ret;
|
||||
|
||||
free(buffer);
|
||||
|
||||
@ -106,8 +103,7 @@ s32 dump_banner( const u8* discid, const char * dest )
|
||||
}
|
||||
|
||||
ret = WDVD_Read((void *) banner, fst[index].filelen, fst[index].fileoffset * 4);
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
if (ret < 0) return ret;
|
||||
|
||||
WDVD_Reset();
|
||||
WDVD_ClosePartition();
|
||||
|
@ -70,8 +70,7 @@ GuiBanner::GuiBanner( const char *tplfilepath )
|
||||
|
||||
GuiBanner::GuiBanner(void *mem, u32 len, int w, int h)
|
||||
{
|
||||
if ( !mem || !len )
|
||||
return;
|
||||
if (!mem || !len) return;
|
||||
memory = mem;
|
||||
tplfilesize = len;
|
||||
width = w;
|
||||
@ -112,12 +111,12 @@ GuiBanner::~GuiBanner()
|
||||
void GuiBanner::Draw()
|
||||
{
|
||||
LOCK( this );
|
||||
if ( !filecheck || !this->IsVisible() )
|
||||
return;
|
||||
if (!filecheck || !this->IsVisible()) return;
|
||||
|
||||
float currScale = this->GetScale();
|
||||
|
||||
Menu_DrawTPLImg( this->GetLeft(), this->GetTop(), 0, width, height, &texObj, imageangle, widescreen ? currScale*0.80 : currScale, currScale, this->GetAlpha(), xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4 );
|
||||
Menu_DrawTPLImg(this->GetLeft(), this->GetTop(), 0, width, height, &texObj, imageangle, widescreen ? currScale
|
||||
* 0.80 : currScale, currScale, this->GetAlpha(), xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4);
|
||||
|
||||
this->UpdateEffects();
|
||||
}
|
||||
|
@ -71,7 +71,6 @@ void md5( u8 *data, u32 len, u8 *hash )
|
||||
MD5(hash, data, len);
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 zeroes[0x40];
|
||||
@ -241,9 +240,9 @@ static int write_imd5_lz77( u8* data, size_t size, char* outname )
|
||||
if (tag == 0x4C5A3737)
|
||||
{
|
||||
// "LZ77" - uncompress
|
||||
decompressed_data = decompress_lz77( data + sizeof( imd5_header_t ), size - sizeof( imd5_header_t ), &decompressed_size );
|
||||
if ( decompressed_data == NULL )
|
||||
return -7;
|
||||
decompressed_data = decompress_lz77(data + sizeof(imd5_header_t), size - sizeof(imd5_header_t),
|
||||
&decompressed_size);
|
||||
if (decompressed_data == NULL) return -7;
|
||||
write_file(decompressed_data, decompressed_size, outname);
|
||||
//printf(", uncompressed %d bytes, md5 ok", decompressed_size);
|
||||
|
||||
@ -467,7 +466,8 @@ int extractbnrfile( const char * filepath, const char * destpath )
|
||||
|
||||
int unpackBin(const char * filename, const char * outdir)
|
||||
{
|
||||
FILE *fp = fopen( filename, "rb" );;
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
;
|
||||
if (fp)
|
||||
{
|
||||
subfoldercreate(outdir);
|
||||
@ -556,8 +556,6 @@ int unpackBanner( const u8 *gameid, int what, const char *outdir )
|
||||
error: fclose(fp);
|
||||
}
|
||||
ramdiskUnmount("BANNER");
|
||||
error2:
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
error2: if (ret < 0) return ret;
|
||||
return 1;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "language/gettext.h"
|
||||
#include "bannersound.h"
|
||||
|
||||
|
||||
struct IMD5Header
|
||||
{
|
||||
u32 fcc;
|
||||
@ -81,15 +80,13 @@ inline u16 le16( u16 i )
|
||||
static u8 *uncompressLZ77(const u8 *inBuf, u32 inLength, u32 &size)
|
||||
{
|
||||
u8 *buffer = NULL;
|
||||
if ( inLength <= 0x8 || *( ( const u32 * )inBuf ) != 0x4C5A3737 /*"LZ77"*/ || inBuf[4] != 0x10 )
|
||||
return NULL;
|
||||
if (inLength <= 0x8 || *((const u32 *) inBuf) != 0x4C5A3737 /*"LZ77"*/|| inBuf[4] != 0x10) return NULL;
|
||||
u32 uncSize = le32(((const u32 *) inBuf)[1] << 8);
|
||||
|
||||
const u8 *inBufEnd = inBuf + inLength;
|
||||
inBuf += 8;
|
||||
buffer = new (std::nothrow) u8[uncSize];
|
||||
if ( !buffer )
|
||||
return buffer;
|
||||
if (!buffer) return buffer;
|
||||
|
||||
u8 *bufCur = buffer;
|
||||
u8 *bufEnd = buffer + uncSize;
|
||||
@ -105,8 +102,7 @@ static u8 *uncompressLZ77( const u8 *inBuf, u32 inLength, u32 &size )
|
||||
const LZ77Info &info = *(const LZ77Info *) inBuf;
|
||||
inBuf += sizeof(LZ77Info);
|
||||
int length = info.length + 3;
|
||||
if ( bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd )
|
||||
return buffer;
|
||||
if (bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd) return buffer;
|
||||
memcpy(bufCur, bufCur - info.offset - 1, length);
|
||||
bufCur += length;
|
||||
}
|
||||
@ -125,8 +121,7 @@ static u8 *uncompressLZ77( const u8 *inBuf, u32 inLength, u32 &size )
|
||||
|
||||
const u8 *LoadBannerSound(const u8 *discid, u32 *size)
|
||||
{
|
||||
if ( !discid )
|
||||
return NULL;
|
||||
if (!discid) return NULL;
|
||||
|
||||
Disc_SetUSB(NULL);
|
||||
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) discid);
|
||||
@ -165,8 +160,7 @@ const u8 *LoadBannerSound( const u8 *discid, u32 *size )
|
||||
fst = (const U8Entry *) (((const u8 *) bnrArcHdr) + bnrArcHdr->rootNodeOffset);
|
||||
u32 i;
|
||||
for (i = 1; i < fst[0].numEntries; ++i)
|
||||
if ( fst[i].fileType == 0 && strcasecmp( u8Filename( fst, i ), "sound.bin" ) == 0 )
|
||||
break;
|
||||
if (fst[i].fileType == 0 && strcasecmp(u8Filename(fst, i), "sound.bin") == 0) break;
|
||||
if (i >= fst[0].numEntries)
|
||||
{
|
||||
/* Not all games have a sound.bin and this message is annoying **/
|
||||
@ -181,7 +175,8 @@ const u8 *LoadBannerSound( const u8 *discid, u32 *size )
|
||||
free(opening_bnr);
|
||||
return NULL;
|
||||
}
|
||||
const u8 *soundChunk = sound_bin + sizeof ( IMD5Header );;
|
||||
const u8 *soundChunk = sound_bin + sizeof(IMD5Header);
|
||||
;
|
||||
u32 soundChunkSize = fst[i].fileLength - sizeof(IMD5Header);
|
||||
|
||||
if (*((u32*) soundChunk) == 0x4C5A3737 /*"LZ77"*/)
|
||||
|
@ -76,20 +76,20 @@ int CheatMenu( const char * gameID )
|
||||
if (download == 1)
|
||||
{
|
||||
download = CodeDownload(gameID);
|
||||
if ( download < 0 || c.openTxtfile( txtfilename ) != 1 )
|
||||
break;
|
||||
if (download < 0 || c.openTxtfile(txtfilename) != 1) break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
else break;
|
||||
case 1:
|
||||
int cntcheats = c.getCnt();
|
||||
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",
|
||||
bg_options_settings_png, 1, 90);
|
||||
chtBrowser.SetPosition(0, 90);
|
||||
chtBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
chtBrowser.SetClickable(true);
|
||||
|
||||
GuiText titleTxt( c.getGameName().c_str(), 28, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText titleTxt(c.getGameName().c_str(), 28, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
titleTxt.SetMaxWidth(350, SCROLL_HORIZONTAL);
|
||||
titleTxt.SetPosition(12, 40);
|
||||
|
@ -81,14 +81,12 @@ string GCTCheats::getCheatComment( int nr )
|
||||
int GCTCheats::createGCT(int nr, const char * filename)
|
||||
{
|
||||
|
||||
if ( nr == 0 )
|
||||
return 0;
|
||||
if (nr == 0) return 0;
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
if (filestr.fail()) return 0;
|
||||
|
||||
//Header and Footer
|
||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde };
|
||||
@ -121,8 +119,7 @@ int GCTCheats::createGCT( const char * chtbuffer, const char * filename )
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
if (filestr.fail()) return 0;
|
||||
|
||||
//Header and Footer
|
||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde };
|
||||
@ -154,14 +151,12 @@ int GCTCheats::createGCT( const char * chtbuffer, const char * filename )
|
||||
int GCTCheats::createGCT(int nr[], int cnt, const char * filename)
|
||||
{
|
||||
|
||||
if ( cnt == 0 )
|
||||
return 0;
|
||||
if (cnt == 0) return 0;
|
||||
|
||||
ofstream filestr;
|
||||
filestr.open(filename);
|
||||
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
if (filestr.fail()) return 0;
|
||||
|
||||
//Header and Footer
|
||||
char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde };
|
||||
@ -201,8 +196,7 @@ int GCTCheats::openTxtfile( const char * filename )
|
||||
string str;
|
||||
filestr.open(filename);
|
||||
|
||||
if ( filestr.fail() )
|
||||
return 0;
|
||||
if (filestr.fail()) return 0;
|
||||
|
||||
filestr.seekg(0, ios_base::end);
|
||||
int size = filestr.tellg();
|
||||
@ -210,22 +204,18 @@ int GCTCheats::openTxtfile( const char * filename )
|
||||
filestr.seekg(0, ios_base::beg);
|
||||
|
||||
getline(filestr, sGameID);
|
||||
if ( sGameID[sGameID.length() - 1] == '\r' )
|
||||
sGameID.erase( sGameID.length() - 1 );
|
||||
if (sGameID[sGameID.length() - 1] == '\r') sGameID.erase(sGameID.length() - 1);
|
||||
|
||||
getline(filestr, sGameTitle);
|
||||
if ( sGameTitle[sGameTitle.length() - 1] == '\r' )
|
||||
sGameTitle.erase( sGameTitle.length() - 1 );
|
||||
if (sGameTitle[sGameTitle.length() - 1] == '\r') sGameTitle.erase(sGameTitle.length() - 1);
|
||||
|
||||
getline(filestr, sCheatName[i]); // skip first line if file uses CRLF
|
||||
if ( !sGameTitle[sGameTitle.length() - 1] == '\r' )
|
||||
filestr.seekg( 0, ios_base::beg );
|
||||
if (!sGameTitle[sGameTitle.length() - 1] == '\r') filestr.seekg(0, ios_base::beg);
|
||||
|
||||
while (!filestr.eof())
|
||||
{
|
||||
getline(filestr, sCheatName[i]); // '\n' delimiter by default
|
||||
if ( sCheatName[i][sCheatName[i].length() - 1] == '\r' )
|
||||
sCheatName[i].erase( sCheatName[i].length() - 1 );
|
||||
if (sCheatName[i][sCheatName[i].length() - 1] == '\r') sCheatName[i].erase(sCheatName[i].length() - 1);
|
||||
|
||||
string cheatdata;
|
||||
bool emptyline = false;
|
||||
@ -233,8 +223,7 @@ int GCTCheats::openTxtfile( const char * filename )
|
||||
do
|
||||
{
|
||||
getline(filestr, str);
|
||||
if ( str[str.length() - 1] == '\r' )
|
||||
str.erase( str.length() - 1 );
|
||||
if (str[str.length() - 1] == '\r') str.erase(str.length() - 1);
|
||||
|
||||
if (str == "" || str[0] == '\r' || str[0] == '\n')
|
||||
{
|
||||
@ -260,8 +249,7 @@ int GCTCheats::openTxtfile( const char * filename )
|
||||
}
|
||||
if (filestr.eof()) break;
|
||||
|
||||
}
|
||||
while ( !emptyline );
|
||||
} while (!emptyline);
|
||||
|
||||
sCheats[i] = cheatdata;
|
||||
i++;
|
||||
@ -279,8 +267,10 @@ bool GCTCheats::IsCode( const std::string& str )
|
||||
// accept strings longer than 17 in case there is a comment on the same line as the code
|
||||
char part1[9];
|
||||
char part2[9];
|
||||
snprintf( part1, sizeof( part1 ), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7] );
|
||||
snprintf( part2, sizeof( part2 ), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14], str[15], str[16] );
|
||||
snprintf(part1, sizeof(part1), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6],
|
||||
str[7]);
|
||||
snprintf(part2, sizeof(part2), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14],
|
||||
str[15], str[16]);
|
||||
if ((strtok(part1, "0123456789ABCDEFabcdef") == NULL) && (strtok(part2, "0123456789ABCDEFabcdef") == NULL))
|
||||
{
|
||||
return true;
|
||||
|
@ -124,8 +124,7 @@ void WBFSDevice_deInit()
|
||||
|
||||
int isInserted(const char *path)
|
||||
{
|
||||
if ( !strncmp( path, "USB:", 4 ) )
|
||||
return 1;
|
||||
if (!strncmp(path, "USB:", 4)) return 1;
|
||||
|
||||
return __io_sdhc.isInserted() || __io_wiisd.isInserted();
|
||||
}
|
||||
|
@ -41,10 +41,8 @@ bool InitGecko()
|
||||
|
||||
char ascii(char s)
|
||||
{
|
||||
if ( s < 0x20 )
|
||||
return '.';
|
||||
if ( s > 0x7E )
|
||||
return '.';
|
||||
if (s < 0x20) return '.';
|
||||
if (s > 0x7E) return '.';
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -63,19 +61,15 @@ void hexdump( void *d, int len )
|
||||
for (i = 0; i < 16; i++)
|
||||
if ((i + off) >= len)
|
||||
gprintf(" ");
|
||||
else
|
||||
gprintf( "%02x ", data[off+i] );
|
||||
else gprintf("%02x ", data[off + i]);
|
||||
|
||||
gprintf(" ");
|
||||
for (i = 0; i < 16; i++)
|
||||
if ((i + off) >= len)
|
||||
gprintf(" ");
|
||||
else
|
||||
gprintf( "%c", ascii( data[off+i] ) );
|
||||
else gprintf("%c", ascii(data[off + i]));
|
||||
gprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* NO_DEBUG */
|
||||
|
@ -1,5 +1,4 @@
|
||||
|
||||
|
||||
#ifndef _GECKO_H_
|
||||
#define _GECKO_H_
|
||||
|
||||
@ -21,8 +20,6 @@ extern "C"
|
||||
#define hexdump( x, y )
|
||||
#endif /* NO_DEBUG */
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -153,7 +153,6 @@ int BootHomebrew( const char * filepath )
|
||||
#include "fatmounter.h"
|
||||
#include "dolloader.h"
|
||||
|
||||
|
||||
void *innetbuffer = NULL;
|
||||
static u8 *homebrewbuffer = (u8 *) 0x92000000;
|
||||
u32 homebrewsize = 0;
|
||||
@ -166,8 +165,7 @@ int AllocHomebrewMemory( u32 filesize )
|
||||
|
||||
innetbuffer = malloc(filesize);
|
||||
|
||||
if ( !innetbuffer )
|
||||
return -1;
|
||||
if (!innetbuffer) return -1;
|
||||
|
||||
homebrewsize = filesize;
|
||||
return 1;
|
||||
@ -203,8 +201,7 @@ void FreeHomebrewBuffer()
|
||||
|
||||
static int SetupARGV(struct __argv * args)
|
||||
{
|
||||
if ( !args )
|
||||
return -1;
|
||||
if (!args) return -1;
|
||||
|
||||
bzero(args, sizeof(struct __argv));
|
||||
args->argvMagic = ARGV_MAGIC;
|
||||
@ -220,8 +217,7 @@ static int SetupARGV( struct __argv * args )
|
||||
args->length = stringlength;
|
||||
args->commandLine = (char*) malloc(args->length);
|
||||
|
||||
if ( !args->commandLine )
|
||||
return -1;
|
||||
if (!args->commandLine) return -1;
|
||||
|
||||
u32 argc = 0;
|
||||
u32 position = 0;
|
||||
@ -247,8 +243,7 @@ static int SetupARGV( struct __argv * args )
|
||||
|
||||
static int RunAppbooter()
|
||||
{
|
||||
if ( homebrewsize == 0 )
|
||||
return -1;
|
||||
if (homebrewsize == 0) return -1;
|
||||
|
||||
struct __argv args;
|
||||
SetupARGV(&args);
|
||||
@ -270,8 +265,7 @@ static int RunAppbooter()
|
||||
{
|
||||
if (Set_Stub_Split(0x00010001, "ULNR") < 0)
|
||||
{
|
||||
if ( !currentStub )
|
||||
currentStub = 0x100000002ULL;
|
||||
if (!currentStub) currentStub = 0x100000002ULL;
|
||||
|
||||
Set_Stub(currentStub);
|
||||
}
|
||||
@ -300,8 +294,7 @@ int BootHomebrew( char * filepath )
|
||||
|
||||
FILE *file = fopen(filepath, "rb");
|
||||
|
||||
if ( !file )
|
||||
Sys_BackToLoader();
|
||||
if (!file) Sys_BackToLoader();
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
filesize = ftell(file);
|
||||
|
@ -51,8 +51,7 @@ int roundup( float number )
|
||||
{
|
||||
if (number == (int) number)
|
||||
return (int) number;
|
||||
else
|
||||
return ( int ) ( number + 1 );
|
||||
else return (int) (number + 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -75,13 +74,10 @@ int MenuHomebrewBrowse()
|
||||
|
||||
enum
|
||||
{
|
||||
FADE,
|
||||
LEFT,
|
||||
RIGHT
|
||||
FADE, LEFT, RIGHT
|
||||
};
|
||||
|
||||
if ( IsNetworkInit() )
|
||||
ResumeNetworkWait();
|
||||
if (IsNetworkInit()) ResumeNetworkWait();
|
||||
|
||||
int slidedirection = FADE;
|
||||
|
||||
@ -118,7 +114,6 @@ int MenuHomebrewBrowse()
|
||||
snprintf(imgPath, sizeof(imgPath), "%sChannel_btn.png", Settings.theme_path);
|
||||
GuiImageData channelImgData(imgPath, Channel_btn_png);
|
||||
|
||||
|
||||
GuiImage background(&bgData);
|
||||
|
||||
/*** Trigger Variables ***/
|
||||
@ -137,7 +132,8 @@ int MenuHomebrewBrowse()
|
||||
GuiTrigger trigPlus;
|
||||
trigPlus.SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, 0);
|
||||
|
||||
GuiText titleTxt( tr( "Homebrew Launcher" ), 28, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText titleTxt(tr( "Homebrew Launcher" ), 28, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
titleTxt.SetPosition(0, 40);
|
||||
|
||||
@ -195,15 +191,18 @@ int MenuHomebrewBrowse()
|
||||
|
||||
GuiImage MainButton1Img(&MainButtonImgData);
|
||||
GuiImage MainButton1ImgOver(&MainButtonImgOverData);
|
||||
GuiText MainButton1Txt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText MainButton1Txt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton1Txt.SetMaxWidth(MainButton1Img.GetWidth() - 150, DOTTED);
|
||||
MainButton1Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton1Txt.SetPosition(148, -12);
|
||||
GuiText MainButton1DescTxt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText MainButton1DescTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton1DescTxt.SetMaxWidth(MainButton1Img.GetWidth() - 150, DOTTED);
|
||||
MainButton1DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton1DescTxt.SetPosition(148, 15);
|
||||
GuiText MainButton1DescOverTxt( MainButtonText, 18, ( GXColor ) { 0, 0, 0, 255} );
|
||||
GuiText MainButton1DescOverTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton1DescOverTxt.SetMaxWidth(MainButton1Img.GetWidth() - 150, SCROLL_HORIZONTAL);
|
||||
MainButton1DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton1DescOverTxt.SetPosition(148, 15);
|
||||
@ -222,15 +221,18 @@ int MenuHomebrewBrowse()
|
||||
|
||||
GuiImage MainButton2Img(&MainButtonImgData);
|
||||
GuiImage MainButton2ImgOver(&MainButtonImgOverData);
|
||||
GuiText MainButton2Txt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255 } );
|
||||
GuiText MainButton2Txt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton2Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton2Txt.SetPosition(148, -12);
|
||||
MainButton2Txt.SetMaxWidth(MainButton2Img.GetWidth() - 150, DOTTED);
|
||||
GuiText MainButton2DescTxt( MainButtonText, 18, ( GXColor ) { 0, 0, 0, 255} );
|
||||
GuiText MainButton2DescTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton2DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton2DescTxt.SetPosition(148, 15);
|
||||
MainButton2DescTxt.SetMaxWidth(MainButton2Img.GetWidth() - 150, DOTTED);
|
||||
GuiText MainButton2DescOverTxt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText MainButton2DescOverTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton2DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton2DescOverTxt.SetPosition(148, 15);
|
||||
MainButton2DescOverTxt.SetMaxWidth(MainButton2Img.GetWidth() - 150, SCROLL_HORIZONTAL);
|
||||
@ -249,15 +251,18 @@ int MenuHomebrewBrowse()
|
||||
|
||||
GuiImage MainButton3Img(&MainButtonImgData);
|
||||
GuiImage MainButton3ImgOver(&MainButtonImgOverData);
|
||||
GuiText MainButton3Txt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText MainButton3Txt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton3Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton3Txt.SetPosition(148, -12);
|
||||
MainButton3Txt.SetMaxWidth(MainButton3Img.GetWidth() - 150, DOTTED);
|
||||
GuiText MainButton3DescTxt( MainButtonText, 18, ( GXColor ) { 0, 0, 0, 255} );
|
||||
GuiText MainButton3DescTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton3DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton3DescTxt.SetPosition(148, 15);
|
||||
MainButton3DescTxt.SetMaxWidth(MainButton3Img.GetWidth() - 150, DOTTED);
|
||||
GuiText MainButton3DescOverTxt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255 } );
|
||||
GuiText MainButton3DescOverTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton3DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton3DescOverTxt.SetPosition(148, 15);
|
||||
MainButton3DescOverTxt.SetMaxWidth(MainButton3Img.GetWidth() - 150, SCROLL_HORIZONTAL);
|
||||
@ -276,15 +281,18 @@ int MenuHomebrewBrowse()
|
||||
|
||||
GuiImage MainButton4Img(&MainButtonImgData);
|
||||
GuiImage MainButton4ImgOver(&MainButtonImgOverData);
|
||||
GuiText MainButton4Txt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText MainButton4Txt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton4Txt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton4Txt.SetPosition(148, -12);
|
||||
MainButton4Txt.SetMaxWidth(MainButton4Img.GetWidth() - 150, DOTTED);
|
||||
GuiText MainButton4DescTxt( MainButtonText, 18, ( GXColor ) {0, 0, 0, 255} );
|
||||
GuiText MainButton4DescTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton4DescTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton4DescTxt.SetPosition(148, 15);
|
||||
MainButton4DescTxt.SetMaxWidth(MainButton4Img.GetWidth() - 150, DOTTED);
|
||||
GuiText MainButton4DescOverTxt( MainButtonText, 18, ( GXColor ) { 0, 0, 0, 255} );
|
||||
GuiText MainButton4DescOverTxt(MainButtonText, 18, ( GXColor )
|
||||
{ 0, 0, 0, 255});
|
||||
MainButton4DescOverTxt.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
MainButton4DescOverTxt.SetPosition(148, 15);
|
||||
MainButton4DescOverTxt.SetMaxWidth(MainButton4Img.GetWidth() - 150, SCROLL_HORIZONTAL);
|
||||
@ -328,7 +336,6 @@ int MenuHomebrewBrowse()
|
||||
|
||||
GuiTooltip * titleTT = NULL;
|
||||
|
||||
|
||||
GuiWindow w(screenwidth, screenheight);
|
||||
|
||||
/*** XML Variables ***/
|
||||
@ -358,7 +365,8 @@ int MenuHomebrewBrowse()
|
||||
MainButton2.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60);
|
||||
MainButton3.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60);
|
||||
MainButton4.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 60);
|
||||
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
||||
while (MainButton1.GetEffect() > 0)
|
||||
usleep(50);
|
||||
}
|
||||
else if (slidedirection == LEFT)
|
||||
{
|
||||
@ -366,7 +374,8 @@ int MenuHomebrewBrowse()
|
||||
MainButton2.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60);
|
||||
MainButton3.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60);
|
||||
MainButton4.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 60);
|
||||
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
||||
while (MainButton1.GetEffect() > 0)
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
HaltGui();
|
||||
@ -403,20 +412,16 @@ int MenuHomebrewBrowse()
|
||||
|
||||
if (IconImg[0] != 0)
|
||||
MainButton1.SetIcon(IconImg[0]);
|
||||
else
|
||||
MainButton1.SetIcon( NULL );
|
||||
else MainButton1.SetIcon(NULL);
|
||||
if (IconImg[1] != 0)
|
||||
MainButton2.SetIcon(IconImg[1]);
|
||||
else
|
||||
MainButton2.SetIcon( NULL );
|
||||
else MainButton2.SetIcon(NULL);
|
||||
if (IconImg[2] != 0)
|
||||
MainButton3.SetIcon(IconImg[2]);
|
||||
else
|
||||
MainButton3.SetIcon( NULL );
|
||||
else MainButton3.SetIcon(NULL);
|
||||
if (IconImg[3] != 0)
|
||||
MainButton4.SetIcon(IconImg[3]);
|
||||
else
|
||||
MainButton4.SetIcon( NULL );
|
||||
else MainButton4.SetIcon(NULL);
|
||||
|
||||
mainWindow->Append(&w);
|
||||
w.RemoveAll();
|
||||
@ -448,9 +453,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset));
|
||||
XMLInfo[0].SetName(MainButtonText);
|
||||
MainButton1Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -472,9 +479,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 1)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 1));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset + 1));
|
||||
XMLInfo[1].SetName(MainButtonText);
|
||||
MainButton2Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -496,9 +505,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 2)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 2));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset + 2));
|
||||
XMLInfo[2].SetName(MainButtonText);
|
||||
MainButton3Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -520,9 +531,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 3)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 3));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset + 3));
|
||||
XMLInfo[3].SetName(MainButtonText);
|
||||
MainButton4Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -548,9 +561,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset));
|
||||
XMLInfo[0].SetName(MainButtonText);
|
||||
MainButton1Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -571,9 +586,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 1)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 1));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset + 1));
|
||||
XMLInfo[1].SetName(MainButtonText);
|
||||
MainButton2Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -594,9 +611,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 2)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 2));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset + 2));
|
||||
XMLInfo[2].SetName(MainButtonText);
|
||||
MainButton3Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -616,9 +635,11 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 3)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 3));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf( MainButtonText, sizeof( MainButtonText ), "%s/%s", shortpath, HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), "%s/%s", shortpath, HomebrewFiles.GetFilename(
|
||||
fileoffset + 3));
|
||||
XMLInfo[3].SetName(MainButtonText);
|
||||
MainButton4Txt.SetText(MainButtonText);
|
||||
snprintf(MainButtonText, sizeof(MainButtonText), " ");
|
||||
@ -665,7 +686,8 @@ int MenuHomebrewBrowse()
|
||||
|
||||
ResumeGui();
|
||||
|
||||
while ( MainButton1.GetEffect() > 0 ) usleep( 50 );
|
||||
while (MainButton1.GetEffect() > 0)
|
||||
usleep(50);
|
||||
|
||||
while (!changed)
|
||||
{
|
||||
@ -687,16 +709,19 @@ int MenuHomebrewBrowse()
|
||||
//get filesize
|
||||
u64 filesize = HomebrewFiles.GetFilesize(fileoffset);
|
||||
//write short filename
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset ) ), "%s", HomebrewFiles.GetFilepath( fileoffset ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf(temp, sizeof(temp), "%s/%s", shortpath, HomebrewFiles.GetFilename(fileoffset));
|
||||
|
||||
int choice = HBCWindowPrompt( XMLInfo[0].GetName(), XMLInfo[0].GetCoder(), XMLInfo[0].GetVersion(), XMLInfo[0].GetReleasedate(), XMLInfo[0].GetLongDescription(), iconpath, filesize );
|
||||
int choice = HBCWindowPrompt(XMLInfo[0].GetName(), XMLInfo[0].GetCoder(), XMLInfo[0].GetVersion(),
|
||||
XMLInfo[0].GetReleasedate(), XMLInfo[0].GetLongDescription(), iconpath, filesize);
|
||||
if (choice == 1)
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset ), HomebrewFiles.GetFilename( fileoffset ) );
|
||||
snprintf(Settings.selected_homebrew, sizeof(Settings.selected_homebrew), "%s%s",
|
||||
HomebrewFiles.GetFilepath(fileoffset), HomebrewFiles.GetFilename(fileoffset));
|
||||
break;
|
||||
}
|
||||
MainButton1.ResetState();
|
||||
@ -717,16 +742,19 @@ int MenuHomebrewBrowse()
|
||||
//get filesize
|
||||
u64 filesize = HomebrewFiles.GetFilesize(fileoffset + 1);
|
||||
//write short filename
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 1 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 1 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 1)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 1));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf(temp, sizeof(temp), "%s/%s", shortpath, HomebrewFiles.GetFilename(fileoffset + 1));
|
||||
|
||||
int choice = HBCWindowPrompt( XMLInfo[1].GetName(), XMLInfo[1].GetCoder(), XMLInfo[1].GetVersion(), XMLInfo[1].GetReleasedate(), XMLInfo[1].GetLongDescription(), iconpath, filesize );
|
||||
int choice = HBCWindowPrompt(XMLInfo[1].GetName(), XMLInfo[1].GetCoder(), XMLInfo[1].GetVersion(),
|
||||
XMLInfo[1].GetReleasedate(), XMLInfo[1].GetLongDescription(), iconpath, filesize);
|
||||
if (choice == 1)
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 1 ), HomebrewFiles.GetFilename( fileoffset + 1 ) );
|
||||
snprintf(Settings.selected_homebrew, sizeof(Settings.selected_homebrew), "%s%s",
|
||||
HomebrewFiles.GetFilepath(fileoffset + 1), HomebrewFiles.GetFilename(fileoffset + 1));
|
||||
break;
|
||||
}
|
||||
MainButton2.ResetState();
|
||||
@ -747,16 +775,19 @@ int MenuHomebrewBrowse()
|
||||
//get filesize
|
||||
u64 filesize = HomebrewFiles.GetFilesize(fileoffset + 2);
|
||||
//write short filename
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 2 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 2 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 2)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 2));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf(temp, sizeof(temp), "%s/%s", shortpath, HomebrewFiles.GetFilename(fileoffset + 2));
|
||||
|
||||
int choice = HBCWindowPrompt( XMLInfo[2].GetName(), XMLInfo[2].GetCoder(), XMLInfo[2].GetVersion(), XMLInfo[2].GetReleasedate(), XMLInfo[2].GetLongDescription(), iconpath, filesize );
|
||||
int choice = HBCWindowPrompt(XMLInfo[2].GetName(), XMLInfo[2].GetCoder(), XMLInfo[2].GetVersion(),
|
||||
XMLInfo[2].GetReleasedate(), XMLInfo[2].GetLongDescription(), iconpath, filesize);
|
||||
if (choice == 1)
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 2 ), HomebrewFiles.GetFilename( fileoffset + 2 ) );
|
||||
snprintf(Settings.selected_homebrew, sizeof(Settings.selected_homebrew), "%s%s",
|
||||
HomebrewFiles.GetFilepath(fileoffset + 2), HomebrewFiles.GetFilename(fileoffset + 2));
|
||||
break;
|
||||
}
|
||||
MainButton3.ResetState();
|
||||
@ -777,16 +808,19 @@ int MenuHomebrewBrowse()
|
||||
//get filesize
|
||||
u64 filesize = HomebrewFiles.GetFilesize(fileoffset + 3);
|
||||
//write short filename
|
||||
snprintf( temp, strlen( HomebrewFiles.GetFilepath( fileoffset + 3 ) ), "%s", HomebrewFiles.GetFilepath( fileoffset + 3 ) );
|
||||
snprintf(temp, strlen(HomebrewFiles.GetFilepath(fileoffset + 3)), "%s", HomebrewFiles.GetFilepath(
|
||||
fileoffset + 3));
|
||||
shortpath = strrchr(temp, '/');
|
||||
snprintf(temp, sizeof(temp), "%s/%s", shortpath, HomebrewFiles.GetFilename(fileoffset + 3));
|
||||
|
||||
int choice = HBCWindowPrompt( XMLInfo[3].GetName(), XMLInfo[3].GetCoder(), XMLInfo[3].GetVersion(), XMLInfo[3].GetReleasedate(), XMLInfo[3].GetLongDescription(), iconpath, filesize );
|
||||
int choice = HBCWindowPrompt(XMLInfo[3].GetName(), XMLInfo[3].GetCoder(), XMLInfo[3].GetVersion(),
|
||||
XMLInfo[3].GetReleasedate(), XMLInfo[3].GetLongDescription(), iconpath, filesize);
|
||||
if (choice == 1)
|
||||
{
|
||||
boothomebrew = 1;
|
||||
menu = MENU_EXIT;
|
||||
snprintf( Settings.selected_homebrew, sizeof( Settings.selected_homebrew ), "%s%s", HomebrewFiles.GetFilepath( fileoffset + 3 ), HomebrewFiles.GetFilename( fileoffset + 3 ) );
|
||||
snprintf(Settings.selected_homebrew, sizeof(Settings.selected_homebrew), "%s%s",
|
||||
HomebrewFiles.GetFilepath(fileoffset + 3), HomebrewFiles.GetFilename(fileoffset + 3));
|
||||
break;
|
||||
}
|
||||
MainButton4.ResetState();
|
||||
@ -807,8 +841,7 @@ int MenuHomebrewBrowse()
|
||||
{
|
||||
pageToDisplay--;
|
||||
/** Change direction of the flying buttons **/
|
||||
if ( pageToDisplay < 1 )
|
||||
pageToDisplay = pages;
|
||||
if (pageToDisplay < 1) pageToDisplay = pages;
|
||||
slidedirection = LEFT;
|
||||
changed = true;
|
||||
GoLeftBtn.ResetState();
|
||||
@ -818,8 +851,7 @@ int MenuHomebrewBrowse()
|
||||
{
|
||||
pageToDisplay++;
|
||||
/** Change direction of the flying buttons **/
|
||||
if ( pageToDisplay > pages )
|
||||
pageToDisplay = 1;
|
||||
if (pageToDisplay > pages) pageToDisplay = 1;
|
||||
slidedirection = RIGHT;
|
||||
changed = true;
|
||||
GoRightBtn.ResetState();
|
||||
@ -860,8 +892,7 @@ int MenuHomebrewBrowse()
|
||||
|
||||
if (infilesize < MB_SIZE)
|
||||
snprintf(filesizetxt, sizeof(filesizetxt), tr( "Incoming file %0.2fKB" ), infilesize / KB_SIZE);
|
||||
else
|
||||
snprintf( filesizetxt, sizeof( filesizetxt ), tr( "Incoming file %0.2fMB" ), infilesize / MB_SIZE );
|
||||
else snprintf(filesizetxt, sizeof(filesizetxt), tr( "Incoming file %0.2fMB" ), infilesize / MB_SIZE);
|
||||
|
||||
snprintf(temp, sizeof(temp), tr( "Load file from: %s ?" ), GetIncommingIP());
|
||||
|
||||
@ -893,8 +924,7 @@ int MenuHomebrewBrowse()
|
||||
|
||||
if (infilesize - read < (u32) len)
|
||||
len = infilesize - read;
|
||||
else
|
||||
len = NETWORKBLOCKSIZE;
|
||||
else len = NETWORKBLOCKSIZE;
|
||||
|
||||
int result = network_read(ptr, len);
|
||||
|
||||
@ -992,8 +1022,8 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( strstr( filename, ".dol" ) || strstr( filename, ".DOL" )
|
||||
|| strstr( filename, ".elf" ) || strstr( filename, ".ELF" ) )
|
||||
if (strstr(filename, ".dol") || strstr(filename, ".DOL") || strstr(filename, ".elf")
|
||||
|| strstr(filename, ".ELF"))
|
||||
{
|
||||
boothomebrew = 2;
|
||||
AddBootArgument(filename);
|
||||
@ -1003,7 +1033,8 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
else if (strstr(filename, ".zip"))
|
||||
{
|
||||
WindowPrompt( tr( "Success:" ), tr( "Uploaded ZIP file installed to homebrew directory." ), tr( "OK" ) );
|
||||
WindowPrompt(tr( "Success:" ),
|
||||
tr( "Uploaded ZIP file installed to homebrew directory." ), tr( "OK" ));
|
||||
CloseConnection();
|
||||
}
|
||||
else
|
||||
@ -1027,7 +1058,6 @@ int MenuHomebrewBrowse()
|
||||
w.SetState(STATE_DEFAULT);
|
||||
channelBtn.ResetState();
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (IsNetworkInit())
|
||||
@ -1046,7 +1076,8 @@ int MenuHomebrewBrowse()
|
||||
}
|
||||
|
||||
w.SetEffect(EFFECT_FADE, -20);
|
||||
while ( w.GetEffect() > 0 ) usleep( 50 );
|
||||
while (w.GetEffect() > 0)
|
||||
usleep(50);
|
||||
|
||||
HaltGui();
|
||||
|
||||
@ -1067,8 +1098,7 @@ int MenuHomebrewBrowse()
|
||||
delete titleTT;
|
||||
titleTT = NULL;
|
||||
|
||||
if ( IsNetworkInit() )
|
||||
HaltNetworkThread();
|
||||
if (IsNetworkInit()) HaltNetworkThread();
|
||||
|
||||
mainWindow->RemoveAll();
|
||||
mainWindow->Append(bgImg);
|
||||
|
@ -65,8 +65,8 @@ bool HomebrewFiles::LoadPath( const char * folderpath )
|
||||
temp[i] = filename[strlen(filename) - 4 + i];
|
||||
}
|
||||
|
||||
if ( ( strncasecmp( temp, ".dol", 4 ) == 0 || strncasecmp( temp, ".elf", 4 ) == 0 )
|
||||
&& filecount < MAXHOMEBREWS && filename[0] != '.' )
|
||||
if ((strncasecmp(temp, ".dol", 4) == 0 || strncasecmp(temp, ".elf", 4) == 0) && filecount < MAXHOMEBREWS
|
||||
&& filename[0] != '.')
|
||||
{
|
||||
|
||||
FileInfo = (FileInfos *) realloc(FileInfo, (filecount + 1) * sizeof(FileInfos));
|
||||
@ -98,24 +98,21 @@ char * HomebrewFiles::GetFilename( int ind )
|
||||
{
|
||||
if (ind > filecount)
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FileName;
|
||||
else return FileInfo[ind].FileName;
|
||||
}
|
||||
|
||||
char * HomebrewFiles::GetFilepath(int ind)
|
||||
{
|
||||
if (ind > filecount)
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FilePath;
|
||||
else return FileInfo[ind].FilePath;
|
||||
}
|
||||
|
||||
unsigned int HomebrewFiles::GetFilesize(int ind)
|
||||
{
|
||||
if (ind > filecount || !filecount || !FileInfo)
|
||||
return NULL;
|
||||
else
|
||||
return FileInfo[ind].FileSize;
|
||||
else return FileInfo[ind].FileSize;
|
||||
}
|
||||
|
||||
int HomebrewFiles::GetFilecount()
|
||||
|
@ -11,6 +11,17 @@
|
||||
|
||||
#define ENTRIE_SIZE 8192
|
||||
|
||||
/* 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;
|
||||
@ -19,18 +30,15 @@ int HomebrewXML::LoadHomebrewXMLData( const char* filename )
|
||||
/* Load XML file */
|
||||
FILE *filexml;
|
||||
filexml = fopen(filename, "rb");
|
||||
if ( !filexml )
|
||||
return -1;
|
||||
if (!filexml) return -1;
|
||||
|
||||
nodetreeHB = mxmlLoadFile(NULL, filexml, MXML_OPAQUE_CALLBACK);
|
||||
fclose(filexml);
|
||||
|
||||
if ( nodetreeHB == NULL )
|
||||
return -2;
|
||||
if (nodetreeHB == NULL) return -2;
|
||||
|
||||
nodedataHB = mxmlFindElement(nodetreeHB, nodetreeHB, "app", NULL, NULL, MXML_DESCEND);
|
||||
if ( nodedataHB == NULL )
|
||||
return -5;
|
||||
if (nodedataHB == NULL) return -5;
|
||||
|
||||
char * Entrie = new char[ENTRIE_SIZE];
|
||||
|
||||
@ -53,11 +61,11 @@ int HomebrewXML::LoadHomebrewXMLData( const char* filename )
|
||||
|
||||
int len = (strlen(Entrie) - 6); //length of the date string without the 200000 at the end
|
||||
if (len == 8)
|
||||
snprintf( Entrie, ENTRIE_SIZE, "%c%c/%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[6], Entrie[7], Entrie[0], Entrie[1], Entrie[2], Entrie[3] );
|
||||
snprintf(Entrie, ENTRIE_SIZE, "%c%c/%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[6], Entrie[7], Entrie[0],
|
||||
Entrie[1], Entrie[2], Entrie[3]);
|
||||
else if (len == 6)
|
||||
snprintf(Entrie, ENTRIE_SIZE, "%c%c/%c%c%c%c", Entrie[4], Entrie[5], Entrie[0], Entrie[1], Entrie[2], Entrie[3]);
|
||||
else
|
||||
snprintf( Entrie, ENTRIE_SIZE, "%s", Entrie );
|
||||
else snprintf(Entrie, ENTRIE_SIZE, "%s", Entrie);
|
||||
|
||||
Releasedate = Entrie;
|
||||
|
||||
@ -68,3 +76,45 @@ int HomebrewXML::LoadHomebrewXMLData( const char* filename )
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
//!Constructor
|
||||
//!\param path Path for the xml file
|
||||
HomebrewXML() { };
|
||||
//!Destructor
|
||||
~HomebrewXML() { };
|
||||
//!\param filename Filepath of the XML file
|
||||
HomebrewXML();
|
||||
~HomebrewXML();
|
||||
|
||||
int LoadHomebrewXMLData(const char* filename);
|
||||
//! Get name
|
||||
const char * GetName() { return Name.c_str(); };
|
||||
//! Get coder
|
||||
const char * GetCoder() { return Coder.c_str(); };
|
||||
//! Get version
|
||||
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; };
|
||||
|
||||
const char * GetName();
|
||||
void SetName(char * newName);
|
||||
const char * GetCoder();
|
||||
const char * GetVersion();
|
||||
const char * GetReleasedate();
|
||||
const char * GetShortDescription();
|
||||
const char * GetLongDescription();
|
||||
|
||||
protected:
|
||||
std::string Name;
|
||||
std::string Coder;
|
||||
|
@ -11,7 +11,6 @@ extern "C"
|
||||
|
||||
u32 load_dol(const void *dolstart, struct __argv *argv);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -48,8 +48,7 @@ void UpdatePads()
|
||||
userInput[i].pad.triggerL = PAD_TriggerL(i);
|
||||
userInput[i].pad.triggerR = PAD_TriggerR(i);
|
||||
|
||||
if ( Settings.rumble == RumbleOn )
|
||||
DoRumble( i );
|
||||
if (Settings.rumble == RumbleOn) DoRumble(i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,8 +103,7 @@ void DoRumble( int i )
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rumbleCount[i] )
|
||||
rumbleCount[i]--;
|
||||
if (rumbleCount[i]) rumbleCount[i]--;
|
||||
WPAD_Rumble(i, 0); // rumble off
|
||||
}
|
||||
}
|
||||
@ -151,7 +149,8 @@ s8 WPAD_Stick( u8 chan, u8 right, int axis )
|
||||
}
|
||||
|
||||
/* calculate x/y value (angle need to be converted into radian) */
|
||||
if ( mag > 1.0 ) mag = 1.0;
|
||||
if (mag > 1.0)
|
||||
mag = 1.0;
|
||||
else if (mag < -1.0) mag = -1.0;
|
||||
double val;
|
||||
|
||||
|
@ -46,7 +46,8 @@ int updateLanguageFiles()
|
||||
{
|
||||
char savepath[150];
|
||||
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",
|
||||
languageFiles[j]);
|
||||
snprintf(savepath, sizeof(savepath), "%s%s", Settings.languagefiles_path, languageFiles[j]);
|
||||
|
||||
struct block file = downloadfile(codeurl);
|
||||
@ -75,5 +76,3 @@ int updateLanguageFiles()
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -12,14 +12,12 @@ typedef struct _MSG
|
||||
} MSG;
|
||||
static MSG *baseMSG = 0;
|
||||
|
||||
|
||||
#define HASHWORDBITS 32
|
||||
|
||||
/* Defines the so called `hashpjw' function by P.J. Weinberger
|
||||
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
||||
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
||||
static inline u32
|
||||
hash_string ( const char *str_param )
|
||||
static inline u32 hash_string(const char *str_param)
|
||||
{
|
||||
u32 hval, g;
|
||||
const char *str = str_param;
|
||||
@ -53,8 +51,7 @@ expand_escape ( const char *str )
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != '\\')
|
||||
*rp++ = *cp++;
|
||||
if ( cp[0] == '\0' )
|
||||
goto terminate;
|
||||
if (cp[0] == '\0') goto terminate;
|
||||
do
|
||||
{
|
||||
|
||||
@ -129,12 +126,10 @@ expand_escape ( const char *str )
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != '\\')
|
||||
*rp++ = *cp++;
|
||||
}
|
||||
while ( cp[0] != '\0' );
|
||||
} while (cp[0] != '\0');
|
||||
|
||||
/* Terminate string. */
|
||||
terminate:
|
||||
*rp = '\0';
|
||||
terminate: *rp = '\0';
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -143,8 +138,7 @@ static MSG *findMSG( u32 id )
|
||||
MSG *msg;
|
||||
for (msg = baseMSG; msg; msg = msg->next)
|
||||
{
|
||||
if ( msg->id == id )
|
||||
return msg;
|
||||
if (msg->id == id) return msg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -184,7 +178,6 @@ void gettextCleanUp( void )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool gettextLoadLanguage(const char* langFile)
|
||||
{
|
||||
FILE *f;
|
||||
@ -193,8 +186,7 @@ bool gettextLoadLanguage( const char* langFile )
|
||||
|
||||
gettextCleanUp();
|
||||
f = fopen(langFile, "r");
|
||||
if ( !f )
|
||||
return false;
|
||||
if (!f) return false;
|
||||
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
@ -221,8 +213,7 @@ bool gettextLoadLanguage( const char* langFile )
|
||||
{
|
||||
char *msgstr, *end;
|
||||
|
||||
if ( lastID == NULL )
|
||||
continue;
|
||||
if (lastID == NULL) continue;
|
||||
|
||||
msgstr = &line[8];
|
||||
end = strrchr(msgstr, '"');
|
||||
@ -247,5 +238,3 @@ const char *gettext( const char *msgid )
|
||||
return msgid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -6,7 +6,6 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
bool gettextLoadLanguage(const char* langFile);
|
||||
void gettextCleanUp(void);
|
||||
/*
|
||||
@ -17,7 +16,6 @@ extern "C"
|
||||
#define tr(s) gettext(s)
|
||||
#define trNOOP(s) (s)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -81,7 +81,8 @@ 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_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
|
||||
@ -91,7 +92,8 @@ offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
bool _FAT_cache_eraseWritePartialSector(CACHE* cache, const void* buffer, sec_t sector, unsigned int offset,
|
||||
size_t size);
|
||||
|
||||
/*
|
||||
Read several sectors from the cache
|
||||
@ -126,9 +128,9 @@ Clear out the contents of the cache without writing any dirty sectors first
|
||||
*/
|
||||
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);
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Platform specific includes
|
||||
#include <gctypes.h>
|
||||
#include <ogc/disc_io.h>
|
||||
|
@ -72,7 +72,8 @@ enum LFN_offset
|
||||
LFN_offset_char11 = 0x1C,
|
||||
LFN_offset_char12 = 0x1E
|
||||
};
|
||||
static const int LFN_offset_table[13] = {0x01, 0x03, 0x05, 0x07, 0x09, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1C, 0x1E};
|
||||
static const int LFN_offset_table[13] =
|
||||
{ 0x01, 0x03, 0x05, 0x07, 0x09, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1C, 0x1E };
|
||||
|
||||
#define LFN_END 0x40
|
||||
#define LFN_DEL 0x80
|
||||
@ -222,13 +223,11 @@ static int _FAT_directory_mbsncasecmp ( const char* s1, const char* s2, size_t l
|
||||
break;
|
||||
}
|
||||
len1 -= b1;
|
||||
}
|
||||
while ( len1 > 0 && towlower( wc1 ) == towlower( wc2 ) && wc1 != 0 );
|
||||
} while (len1 > 0 && towlower(wc1) == towlower(wc2) && wc1 != 0);
|
||||
|
||||
return towlower(wc1) - towlower(wc2);
|
||||
}
|
||||
|
||||
|
||||
static bool _FAT_directory_entryGetAlias(const u8* entryData, char* destName)
|
||||
{
|
||||
int i = 0;
|
||||
@ -286,7 +285,8 @@ uint32_t _FAT_directory_entryGetCluster ( PARTITION* partition, const uint8_t* e
|
||||
}
|
||||
}
|
||||
|
||||
static bool _FAT_directory_incrementDirEntryPosition ( PARTITION* partition, DIR_ENTRY_POSITION* entryPosition, bool extendDirectory )
|
||||
static bool _FAT_directory_incrementDirEntryPosition(PARTITION* partition, DIR_ENTRY_POSITION* entryPosition,
|
||||
bool extendDirectory)
|
||||
{
|
||||
DIR_ENTRY_POSITION position = *entryPosition;
|
||||
uint32_t tempCluster;
|
||||
@ -321,7 +321,8 @@ static bool _FAT_directory_incrementDirEntryPosition ( PARTITION* partition, DIR
|
||||
}
|
||||
position.cluster = tempCluster;
|
||||
}
|
||||
else if ( ( position.cluster == FAT16_ROOT_DIR_CLUSTER ) && ( position.sector == ( partition->dataStart - partition->rootDirStart ) ) )
|
||||
else if ((position.cluster == FAT16_ROOT_DIR_CLUSTER) && (position.sector == (partition->dataStart
|
||||
- partition->rootDirStart)))
|
||||
{
|
||||
return false; // Got to end of root directory, can't extend it
|
||||
}
|
||||
@ -366,9 +367,8 @@ bool _FAT_directory_getNextEntry ( PARTITION* partition, DIR_ENTRY* entry )
|
||||
notFound = true;
|
||||
}
|
||||
|
||||
_FAT_cache_readPartialSector ( partition->cache, entryData,
|
||||
_FAT_fat_clusterToSector( partition, entryEnd.cluster ) + entryEnd.sector,
|
||||
entryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_readPartialSector(partition->cache, entryData, _FAT_fat_clusterToSector(partition, entryEnd.cluster)
|
||||
+ entryEnd.sector, entryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
if (entryData[DIR_ENTRY_attributes] == ATTRIB_LFN)
|
||||
{
|
||||
@ -389,7 +389,8 @@ bool _FAT_directory_getNextEntry ( PARTITION* partition, DIR_ENTRY* entry )
|
||||
}
|
||||
lfn[lfnPos] = '\0'; // Set end of lfn to null character
|
||||
lfnChkSum = entryData[LFN_offset_checkSum];
|
||||
} if ( lfnChkSum != entryData[LFN_offset_checkSum] )
|
||||
}
|
||||
if (lfnChkSum != entryData[LFN_offset_checkSum])
|
||||
{
|
||||
lfnExists = false;
|
||||
}
|
||||
@ -415,7 +416,8 @@ bool _FAT_directory_getNextEntry ( PARTITION* partition, DIR_ENTRY* entry )
|
||||
{
|
||||
notFound = true;
|
||||
}
|
||||
else if ( ( entryData[0] != DIR_ENTRY_FREE ) && ( entryData[0] > 0x20 ) && !( entryData[DIR_ENTRY_attributes] & ATTRIB_VOL ) )
|
||||
else if ((entryData[0] != DIR_ENTRY_FREE) && (entryData[0] > 0x20) && !(entryData[DIR_ENTRY_attributes]
|
||||
& ATTRIB_VOL))
|
||||
{
|
||||
if (lfnExists)
|
||||
{
|
||||
@ -513,17 +515,14 @@ bool _FAT_directory_entryFromPosition ( PARTITION* partition, DIR_ENTRY* entry )
|
||||
memset(entry->filename, '\0', MAX_FILENAME_LENGTH);
|
||||
|
||||
// Create an empty directory entry to overwrite the old ones with
|
||||
for ( entryStillValid = true, finished = false;
|
||||
entryStillValid && !finished;
|
||||
entryStillValid = _FAT_directory_incrementDirEntryPosition ( partition, &entryStart, false ) )
|
||||
for (entryStillValid = true, finished = false; entryStillValid && !finished; entryStillValid
|
||||
= _FAT_directory_incrementDirEntryPosition(partition, &entryStart, false))
|
||||
{
|
||||
_FAT_cache_readPartialSector ( partition->cache, entryData,
|
||||
_FAT_fat_clusterToSector( partition, entryStart.cluster ) + entryStart.sector,
|
||||
entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_readPartialSector(partition->cache, entryData, _FAT_fat_clusterToSector(partition,
|
||||
entryStart.cluster) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
if ( ( entryStart.cluster == entryEnd.cluster )
|
||||
&& ( entryStart.sector == entryEnd.sector )
|
||||
&& ( entryStart.offset == entryEnd.offset ) )
|
||||
if ((entryStart.cluster == entryEnd.cluster) && (entryStart.sector == entryEnd.sector) && (entryStart.offset
|
||||
== entryEnd.offset))
|
||||
{
|
||||
// Copy the entry data and stop, since this is the last section of the directory entry
|
||||
memcpy(entry->entryData, entryData, DIR_ENTRY_DATA_SIZE);
|
||||
@ -549,9 +548,8 @@ bool _FAT_directory_entryFromPosition ( PARTITION* partition, DIR_ENTRY* entry )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ( entryStart.cluster == entryEnd.cluster )
|
||||
&& ( entryStart.sector == entryEnd.sector )
|
||||
&& ( entryStart.offset == entryEnd.offset ) )
|
||||
if ((entryStart.cluster == entryEnd.cluster) && (entryStart.sector == entryEnd.sector) && (entryStart.offset
|
||||
== entryEnd.offset))
|
||||
{
|
||||
// Since the entry doesn't have a long file name, extract the short filename
|
||||
if (!_FAT_directory_entryGetAlias(entry->entryData, entry->filename))
|
||||
@ -571,8 +569,6 @@ bool _FAT_directory_entryFromPosition ( PARTITION* partition, DIR_ENTRY* entry )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool _FAT_directory_entryFromPath(PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd)
|
||||
{
|
||||
size_t dirnameLength;
|
||||
@ -649,16 +645,16 @@ bool _FAT_directory_entryFromPath ( PARTITION* partition, DIR_ENTRY* entry, cons
|
||||
while (foundFile && !found && !notFound) // It hasn't already found the file
|
||||
{
|
||||
// Check if the filename matches
|
||||
if ( ( dirnameLength == strnlen( entry->filename, MAX_FILENAME_LENGTH ) )
|
||||
&& ( _FAT_directory_mbsncasecmp( pathPosition, entry->filename, dirnameLength ) == 0 ) )
|
||||
if ((dirnameLength == strnlen(entry->filename, MAX_FILENAME_LENGTH)) && (_FAT_directory_mbsncasecmp(
|
||||
pathPosition, entry->filename, dirnameLength) == 0))
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
|
||||
// Check if the alias matches
|
||||
_FAT_directory_entryGetAlias(entry->entryData, alias);
|
||||
if ( ( dirnameLength == strnlen( alias, MAX_ALIAS_LENGTH ) )
|
||||
&& ( strncasecmp( pathPosition, alias, dirnameLength ) == 0 ) )
|
||||
if ((dirnameLength == strnlen(alias, MAX_ALIAS_LENGTH)) && (strncasecmp(pathPosition, alias, dirnameLength)
|
||||
== 0))
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
@ -709,8 +705,8 @@ bool _FAT_directory_entryFromPath ( PARTITION* partition, DIR_ENTRY* entry, cons
|
||||
|
||||
if (found && !notFound)
|
||||
{
|
||||
if ( partition->filesysType == FS_FAT32 && ( entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR ) &&
|
||||
_FAT_directory_entryGetCluster ( partition, entry->entryData ) == CLUSTER_ROOT )
|
||||
if (partition->filesysType == FS_FAT32 && (entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR)
|
||||
&& _FAT_directory_entryGetCluster(partition, entry->entryData) == CLUSTER_ROOT)
|
||||
{
|
||||
// On FAT32 it should specify an actual cluster for the root entry,
|
||||
// not cluster 0 as on FAT16
|
||||
@ -733,14 +729,16 @@ bool _FAT_directory_removeEntry ( PARTITION* partition, DIR_ENTRY* entry )
|
||||
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
||||
|
||||
// Create an empty directory entry to overwrite the old ones with
|
||||
for ( entryStillValid = true, finished = false;
|
||||
entryStillValid && !finished;
|
||||
entryStillValid = _FAT_directory_incrementDirEntryPosition ( partition, &entryStart, false ) )
|
||||
for (entryStillValid = true, finished = false; entryStillValid && !finished; entryStillValid
|
||||
= _FAT_directory_incrementDirEntryPosition(partition, &entryStart, false))
|
||||
{
|
||||
_FAT_cache_readPartialSector ( partition->cache, entryData, _FAT_fat_clusterToSector( partition, entryStart.cluster ) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_readPartialSector(partition->cache, entryData, _FAT_fat_clusterToSector(partition,
|
||||
entryStart.cluster) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
entryData[0] = DIR_ENTRY_FREE;
|
||||
_FAT_cache_writePartialSector ( partition->cache, entryData, _FAT_fat_clusterToSector( partition, entryStart.cluster ) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
if ( ( entryStart.cluster == entryEnd.cluster ) && ( entryStart.sector == entryEnd.sector ) && ( entryStart.offset == entryEnd.offset ) )
|
||||
_FAT_cache_writePartialSector(partition->cache, entryData, _FAT_fat_clusterToSector(partition,
|
||||
entryStart.cluster) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
if ((entryStart.cluster == entryEnd.cluster) && (entryStart.sector == entryEnd.sector) && (entryStart.offset
|
||||
== entryEnd.offset))
|
||||
{
|
||||
finished = true;
|
||||
}
|
||||
@ -775,9 +773,8 @@ static bool _FAT_directory_findEntryGap ( PARTITION* partition, DIR_ENTRY* entry
|
||||
|
||||
while (entryStillValid && !endOfDirectory && (dirEntryRemain > 0))
|
||||
{
|
||||
_FAT_cache_readPartialSector ( partition->cache, entryData,
|
||||
_FAT_fat_clusterToSector( partition, gapEnd.cluster ) + gapEnd.sector,
|
||||
gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_readPartialSector(partition->cache, entryData, _FAT_fat_clusterToSector(partition, gapEnd.cluster)
|
||||
+ gapEnd.sector, gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
if (entryData[0] == DIR_ENTRY_LAST)
|
||||
{
|
||||
gapStart = gapEnd;
|
||||
@ -824,9 +821,8 @@ static bool _FAT_directory_findEntryGap ( PARTITION* partition, DIR_ENTRY* entry
|
||||
entryStillValid = _FAT_directory_incrementDirEntryPosition(partition, &gapEnd, true);
|
||||
--dirEntryRemain;
|
||||
// Fill the entry with blanks
|
||||
_FAT_cache_writePartialSector ( partition->cache, entryData,
|
||||
_FAT_fat_clusterToSector( partition, gapEnd.cluster ) + gapEnd.sector,
|
||||
gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_writePartialSector(partition->cache, entryData, _FAT_fat_clusterToSector(partition,
|
||||
gapEnd.cluster) + gapEnd.sector, gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
}
|
||||
if (!entryStillValid)
|
||||
{
|
||||
@ -861,8 +857,8 @@ static bool _FAT_directory_entryExists ( PARTITION* partition, const char* name,
|
||||
while (foundFile) // It hasn't already found the file
|
||||
{
|
||||
// Check if the filename matches
|
||||
if ( ( dirnameLength == strnlen( tempEntry.filename, MAX_FILENAME_LENGTH ) )
|
||||
&& ( _FAT_directory_mbsncasecmp( name, tempEntry.filename, dirnameLength ) == 0 ) )
|
||||
if ((dirnameLength == strnlen(tempEntry.filename, MAX_FILENAME_LENGTH)) && (_FAT_directory_mbsncasecmp(name,
|
||||
tempEntry.filename, dirnameLength) == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -1045,7 +1041,8 @@ bool _FAT_directory_addEntry ( PARTITION* partition, DIR_ENTRY* entry, uint32_t
|
||||
entry->filename[i] = '\0';
|
||||
}
|
||||
// Remove leading spaces
|
||||
for ( i = 0; ( i < ( int )strlen ( entry->filename ) ) && ( entry->filename[i] == ' ' ); ++i ) ;
|
||||
for (i = 0; (i < (int) strlen(entry->filename)) && (entry->filename[i] == ' '); ++i)
|
||||
;
|
||||
if (i > 0)
|
||||
{
|
||||
memmove(entry->filename, entry->filename + i, strlen(entry->filename + i));
|
||||
@ -1097,13 +1094,14 @@ bool _FAT_directory_addEntry ( PARTITION* partition, DIR_ENTRY* entry, uint32_t
|
||||
|
||||
// Generate full alias for all cases except when the alias is simply an upper case version of the LFN
|
||||
// and there isn't already a file with that name
|
||||
if ( strncasecmp ( alias, entry->filename, MAX_ALIAS_LENGTH ) != 0 ||
|
||||
_FAT_directory_entryExists ( partition, alias, dirCluster ) )
|
||||
if (strncasecmp(alias, entry->filename, MAX_ALIAS_LENGTH) != 0 || _FAT_directory_entryExists(partition,
|
||||
alias, dirCluster))
|
||||
{
|
||||
// expand primary part to 8 characters long by padding the end with underscores
|
||||
i = MAX_ALIAS_PRI_LENGTH - 1;
|
||||
// Move extension to last 3 characters
|
||||
while ( alias[i] != '.' && i > 0 ) i--;
|
||||
while (alias[i] != '.' && i > 0)
|
||||
i--;
|
||||
if (i > 0)
|
||||
{
|
||||
j = MAX_ALIAS_LENGTH - MAX_ALIAS_EXT_LENGTH - 2; // 1 char for '.', one for NUL, 3 for extension
|
||||
@ -1187,8 +1185,8 @@ bool _FAT_directory_addEntry ( PARTITION* partition, DIR_ENTRY* entry, uint32_t
|
||||
ucs2_t lfn[MAX_LFN_LENGTH] = { 0 };
|
||||
_FAT_directory_mbstoucs2(lfn, entry->filename, MAX_LFN_LENGTH);
|
||||
|
||||
for ( entryStillValid = true, i = entrySize; entryStillValid && i > 0;
|
||||
entryStillValid = _FAT_directory_incrementDirEntryPosition ( partition, &curEntryPos, false ), -- i )
|
||||
for (entryStillValid = true, i = entrySize; entryStillValid && i > 0; entryStillValid
|
||||
= _FAT_directory_incrementDirEntryPosition(partition, &curEntryPos, false), --i)
|
||||
{
|
||||
if (i > 1)
|
||||
{
|
||||
@ -1217,12 +1215,16 @@ bool _FAT_directory_addEntry ( PARTITION* partition, DIR_ENTRY* entry, uint32_t
|
||||
lfnEntry[LFN_offset_flag] = ATTRIB_LFN;
|
||||
lfnEntry[LFN_offset_reserved1] = 0;
|
||||
u16_to_u8array(lfnEntry, LFN_offset_reserved2, 0);
|
||||
_FAT_cache_writePartialSector ( partition->cache, lfnEntry, _FAT_fat_clusterToSector( partition, curEntryPos.cluster ) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_writePartialSector(partition->cache, lfnEntry, _FAT_fat_clusterToSector(partition,
|
||||
curEntryPos.cluster) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE,
|
||||
DIR_ENTRY_DATA_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Alias & file data
|
||||
_FAT_cache_writePartialSector ( partition->cache, entry->entryData, _FAT_fat_clusterToSector( partition, curEntryPos.cluster ) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_writePartialSector(partition->cache, entry->entryData, _FAT_fat_clusterToSector(partition,
|
||||
curEntryPos.cluster) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE,
|
||||
DIR_ENTRY_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1255,28 +1257,20 @@ void _FAT_directory_entryStat ( PARTITION* partition, DIR_ENTRY* entry, struct s
|
||||
// Some of the values are faked for the sake of compatibility
|
||||
st->st_dev = _FAT_disc_hostType(partition->disc); // The device is the 32bit ioType value
|
||||
st->st_ino = (ino_t) (_FAT_directory_entryGetCluster(partition, entry->entryData)); // The file serial number is the start cluster
|
||||
st->st_mode = ( _FAT_directory_isDirectory( entry ) ? S_IFDIR : S_IFREG ) |
|
||||
( S_IRUSR | S_IRGRP | S_IROTH ) |
|
||||
( _FAT_directory_isWritable ( entry ) ? ( S_IWUSR | S_IWGRP | S_IWOTH ) : 0 ); // Mode bits based on dirEntry ATTRIB byte
|
||||
st->st_mode = (_FAT_directory_isDirectory(entry) ? S_IFDIR : S_IFREG) | (S_IRUSR | S_IRGRP | S_IROTH)
|
||||
| (_FAT_directory_isWritable(entry) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0); // Mode bits based on dirEntry ATTRIB byte
|
||||
st->st_nlink = 1; // Always one hard link on a FAT file
|
||||
st->st_uid = 1; // Faked for FAT
|
||||
st->st_gid = 2; // Faked for FAT
|
||||
st->st_rdev = st->st_dev;
|
||||
st->st_size = u8array_to_u32(entry->entryData, DIR_ENTRY_fileSize); // File size
|
||||
st->st_atime = _FAT_filetime_to_time_t (
|
||||
0,
|
||||
u8array_to_u16 ( entry->entryData, DIR_ENTRY_aDate )
|
||||
);
|
||||
st->st_atime = _FAT_filetime_to_time_t(0, u8array_to_u16(entry->entryData, DIR_ENTRY_aDate));
|
||||
st->st_spare1 = 0;
|
||||
st->st_mtime = _FAT_filetime_to_time_t (
|
||||
u8array_to_u16 ( entry->entryData, DIR_ENTRY_mTime ),
|
||||
u8array_to_u16 ( entry->entryData, DIR_ENTRY_mDate )
|
||||
);
|
||||
st->st_mtime = _FAT_filetime_to_time_t(u8array_to_u16(entry->entryData, DIR_ENTRY_mTime), u8array_to_u16(
|
||||
entry->entryData, DIR_ENTRY_mDate));
|
||||
st->st_spare2 = 0;
|
||||
st->st_ctime = _FAT_filetime_to_time_t (
|
||||
u8array_to_u16 ( entry->entryData, DIR_ENTRY_cTime ),
|
||||
u8array_to_u16 ( entry->entryData, DIR_ENTRY_cDate )
|
||||
);
|
||||
st->st_ctime = _FAT_filetime_to_time_t(u8array_to_u16(entry->entryData, DIR_ENTRY_cTime), u8array_to_u16(
|
||||
entry->entryData, DIR_ENTRY_cDate));
|
||||
st->st_spare3 = 0;
|
||||
st->st_blksize = BYTES_PER_READ; // Prefered file I/O block size
|
||||
st->st_blocks = (st->st_size + BYTES_PER_READ - 1) / BYTES_PER_READ; // File size in blocks
|
||||
|
@ -56,8 +56,10 @@
|
||||
#define ATTRIB_SYS 0x04 // System
|
||||
#define ATTRIB_HID 0x02 // Hidden
|
||||
#define ATTRIB_RO 0x01 // Read only
|
||||
|
||||
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
||||
typedef enum
|
||||
{
|
||||
FT_DIRECTORY, FT_FILE
|
||||
} FILE_TYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -107,8 +109,8 @@ static inline bool _FAT_directory_isWritable ( DIR_ENTRY* entry )
|
||||
|
||||
static inline bool _FAT_directory_isDot(DIR_ENTRY* entry)
|
||||
{
|
||||
return ( ( entry->filename[0] == '.' ) && ( ( entry->filename[1] == '\0' ) ||
|
||||
( ( entry->filename[1] == '.' ) && entry->filename[2] == '\0' ) ) );
|
||||
return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') || ((entry->filename[1] == '.')
|
||||
&& entry->filename[2] == '\0')));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -70,7 +70,8 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to read from
|
||||
*/
|
||||
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
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);
|
||||
}
|
||||
|
@ -61,12 +61,6 @@ static const DISC_INTERFACE* get_io_gcsdb ( void )
|
||||
return &__io_gcsdb;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] =
|
||||
{
|
||||
{"sd", get_io_wiisd},
|
||||
{"usb", get_io_usbstorage},
|
||||
{"carda", get_io_gcsda},
|
||||
{"cardb", get_io_gcsdb},
|
||||
{NULL, NULL}
|
||||
};
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = { { "sd", get_io_wiisd }, { "usb", get_io_usbstorage }, { "carda",
|
||||
get_io_gcsda }, { "cardb", get_io_gcsdb }, { NULL, NULL } };
|
||||
|
||||
|
@ -70,7 +70,8 @@ else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to read from
|
||||
*/
|
||||
static inline bool _FAT_disc_writeSectors ( const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
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);
|
||||
}
|
||||
|
@ -26,7 +26,6 @@
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _LIBFAT_H
|
||||
#define _LIBFAT_H
|
||||
|
||||
@ -67,7 +66,8 @@ extern "C"
|
||||
cacheSize specifies the number of pages to allocate for the cache.
|
||||
This will not startup the disc, so you need to call interface->startup(); first.
|
||||
*/
|
||||
extern bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage );
|
||||
extern bool fatMount(const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize,
|
||||
uint32_t SectorsPerPage);
|
||||
/*
|
||||
Unmount the partition specified by name.
|
||||
If there are open files, it will attempt to synchronise them to disc.
|
||||
|
@ -46,7 +46,8 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition )
|
||||
CACHE* _FAT_cache_constructor(unsigned int numberOfPages, unsigned int sectorsPerPage,
|
||||
const DISC_INTERFACE* discInterface, sec_t endOfPartition)
|
||||
{
|
||||
CACHE* cache;
|
||||
unsigned int i;
|
||||
@ -73,7 +74,6 @@ CACHE* _FAT_cache_constructor ( unsigned int numberOfPages, unsigned int sectors
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
|
||||
|
||||
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate(sizeof(CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL)
|
||||
{
|
||||
@ -110,7 +110,6 @@ void _FAT_cache_destructor ( CACHE* cache )
|
||||
_FAT_mem_free(cache);
|
||||
}
|
||||
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime()
|
||||
@ -119,7 +118,6 @@ static u32 accessTime()
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
|
||||
static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache, sec_t sector)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -149,7 +147,8 @@ static CACHE_ENTRY* _FAT_cache_getPage( CACHE *cache, sec_t sector )
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -218,10 +217,17 @@ bool _FAT_cache_readLittleEndianValue ( CACHE* cache, uint32_t *value, sec_t sec
|
||||
|
||||
switch (num_bytes)
|
||||
{
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
default: return false;
|
||||
case 1:
|
||||
*value = buf[0];
|
||||
break;
|
||||
case 2:
|
||||
*value = u8array_to_u16(buf, 0);
|
||||
break;
|
||||
case 4:
|
||||
*value = u8array_to_u32(buf, 0);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -252,10 +258,17 @@ bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||
default: return false;
|
||||
case 1:
|
||||
buf[0] = value;
|
||||
break;
|
||||
case 2:
|
||||
u16_to_u8array(buf, 0, value);
|
||||
break;
|
||||
case 4:
|
||||
u32_to_u8array(buf, 0, value);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return _FAT_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
@ -264,7 +277,8 @@ bool _FAT_cache_writeLittleEndianValue ( CACHE* cache, const uint32_t value, sec
|
||||
/*
|
||||
Writes some data to a cache page, zeroing out the page first
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
bool _FAT_cache_eraseWritePartialSector(CACHE* cache, const void* buffer, sec_t sector, unsigned int offset,
|
||||
size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
@ -282,7 +296,6 @@ bool _FAT_cache_eraseWritePartialSector ( CACHE* cache, const void* buffer, sec_
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static CACHE_ENTRY* _FAT_cache_findPage(CACHE *cache, sec_t sector, sec_t count)
|
||||
{
|
||||
|
||||
@ -376,7 +389,8 @@ bool _FAT_cache_flush ( CACHE* cache )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -81,7 +81,8 @@ 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_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
|
||||
@ -91,7 +92,8 @@ offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector ( CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size );
|
||||
bool _FAT_cache_eraseWritePartialSector(CACHE* cache, const void* buffer, sec_t sector, unsigned int offset,
|
||||
size_t size);
|
||||
|
||||
/*
|
||||
Read several sectors from the cache
|
||||
@ -126,9 +128,9 @@ Clear out the contents of the cache without writing any dirty sectors first
|
||||
*/
|
||||
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);
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "filetime.h"
|
||||
#include "lock.h"
|
||||
|
||||
|
||||
int _FAT_stat_r(struct _reent *r, const char *path, struct stat *st)
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
@ -139,7 +138,6 @@ int _FAT_unlink_r ( struct _reent *r, const char *path )
|
||||
|
||||
cluster = _FAT_directory_entryGetCluster(partition, dirEntry.entryData);
|
||||
|
||||
|
||||
// If this is a directory, make sure it is empty
|
||||
if (_FAT_directory_isDirectory(&dirEntry))
|
||||
{
|
||||
@ -319,8 +317,8 @@ int _FAT_rename_r ( struct _reent *r, const char *oldName, const char *newName )
|
||||
{
|
||||
// Path was specified -- get the right dirCluster
|
||||
// Recycling newDirEntry, since it needs to be recreated anyway
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &newDirEntry, newName, pathEnd ) ||
|
||||
!_FAT_directory_isDirectory( &newDirEntry ) )
|
||||
if (!_FAT_directory_entryFromPath(partition, &newDirEntry, newName, pathEnd) || !_FAT_directory_isDirectory(
|
||||
&newDirEntry))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOTDIR;
|
||||
@ -425,8 +423,8 @@ int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
|
||||
{
|
||||
// Path was specified -- get the right parentCluster
|
||||
// Recycling dirEntry, since it needs to be recreated anyway
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
|
||||
!_FAT_directory_isDirectory( &dirEntry ) )
|
||||
if (!_FAT_directory_entryFromPath(partition, &dirEntry, path, pathEnd)
|
||||
|| !_FAT_directory_isDirectory(&dirEntry))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOTDIR;
|
||||
@ -480,23 +478,21 @@ int _FAT_mkdir_r ( struct _reent *r, const char *path, int mode )
|
||||
u16_to_u8array(newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||
|
||||
// Write it to the directory, erasing that sector in the process
|
||||
_FAT_cache_eraseWritePartialSector ( partition->cache, newEntryData,
|
||||
_FAT_fat_clusterToSector ( partition, dirCluster ), 0, DIR_ENTRY_DATA_SIZE );
|
||||
|
||||
_FAT_cache_eraseWritePartialSector(partition->cache, newEntryData, _FAT_fat_clusterToSector(partition, dirCluster),
|
||||
0, DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
// Create the double dot entry within the directory
|
||||
|
||||
// if ParentDir == Rootdir then ".."" always link to Cluster 0
|
||||
if ( parentCluster == partition->rootDirCluster )
|
||||
parentCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
if (parentCluster == partition->rootDirCluster) parentCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
|
||||
newEntryData[DIR_ENTRY_name + 1] = '.';
|
||||
u16_to_u8array(newEntryData, DIR_ENTRY_cluster, parentCluster);
|
||||
u16_to_u8array(newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16);
|
||||
|
||||
// Write it to the directory
|
||||
_FAT_cache_writePartialSector ( partition->cache, newEntryData,
|
||||
_FAT_fat_clusterToSector ( partition, dirCluster ), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_writePartialSector(partition->cache, newEntryData, _FAT_fat_clusterToSector(partition, dirCluster),
|
||||
DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush(partition->cache))
|
||||
@ -601,8 +597,7 @@ DIR_ITER* _FAT_diropen_r( struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
state->startCluster = _FAT_directory_entryGetCluster(state->partition, dirEntry.entryData);
|
||||
|
||||
// Get the first entry for use with a call to dirnext
|
||||
state->validEntry =
|
||||
_FAT_directory_getFirstEntry ( state->partition, &( state->currentEntry ), state->startCluster );
|
||||
state->validEntry = _FAT_directory_getFirstEntry(state->partition, &(state->currentEntry), state->startCluster);
|
||||
|
||||
// We are now using this entry
|
||||
state->inUse = true;
|
||||
@ -625,8 +620,7 @@ int _FAT_dirreset_r ( struct _reent *r, DIR_ITER *dirState )
|
||||
}
|
||||
|
||||
// Get the first entry for use with a call to dirnext
|
||||
state->validEntry =
|
||||
_FAT_directory_getFirstEntry ( state->partition, &( state->currentEntry ), state->startCluster );
|
||||
state->validEntry = _FAT_directory_getFirstEntry(state->partition, &(state->currentEntry), state->startCluster);
|
||||
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
return 0;
|
||||
@ -663,8 +657,7 @@ int _FAT_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struc
|
||||
}
|
||||
|
||||
// Look for the next entry for use next time
|
||||
state->validEntry =
|
||||
_FAT_directory_getNextEntry ( state->partition, &( state->currentEntry ) );
|
||||
state->validEntry = _FAT_directory_getNextEntry(state->partition, &(state->currentEntry));
|
||||
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
return 0;
|
||||
|
@ -28,7 +28,6 @@
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __FATDIR_H
|
||||
#define __FATDIR_H
|
||||
|
||||
@ -70,5 +69,4 @@ extern int _FAT_dirreset_r ( struct _reent *r, DIR_ITER *dirState );
|
||||
extern int _FAT_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
|
||||
extern int _FAT_dirclose_r(struct _reent *r, DIR_ITER *dirState);
|
||||
|
||||
|
||||
#endif // _FATDIR_H
|
||||
|
@ -30,7 +30,6 @@
|
||||
2009-10-23 oggzee: fixes for cluster aligned file size (write, truncate, seek)
|
||||
*/
|
||||
|
||||
|
||||
#include "fatfile.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
@ -155,8 +154,8 @@ int _FAT_open_r ( struct _reent *r, void *fileStruct, const char *path, int flag
|
||||
{
|
||||
// Path was specified -- get the right dirCluster
|
||||
// Recycling dirEntry, since it needs to be recreated anyway
|
||||
if ( !_FAT_directory_entryFromPath ( partition, &dirEntry, path, pathEnd ) ||
|
||||
!_FAT_directory_isDirectory( &dirEntry ) )
|
||||
if (!_FAT_directory_entryFromPath(partition, &dirEntry, path, pathEnd) || !_FAT_directory_isDirectory(
|
||||
&dirEntry))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOTDIR;
|
||||
@ -299,9 +298,9 @@ int _FAT_syncToDisc ( FILE_STRUCT* file )
|
||||
if (file->write && file->modified)
|
||||
{
|
||||
// Load the old entry
|
||||
_FAT_cache_readPartialSector ( file->partition->cache, dirEntryData,
|
||||
_FAT_fat_clusterToSector( file->partition, file->dirEntryEnd.cluster ) + file->dirEntryEnd.sector,
|
||||
file->dirEntryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_readPartialSector(file->partition->cache, dirEntryData, _FAT_fat_clusterToSector(file->partition,
|
||||
file->dirEntryEnd.cluster) + file->dirEntryEnd.sector, file->dirEntryEnd.offset * DIR_ENTRY_DATA_SIZE,
|
||||
DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
// Write new data to the directory entry
|
||||
// File size
|
||||
@ -322,9 +321,9 @@ int _FAT_syncToDisc ( FILE_STRUCT* file )
|
||||
dirEntryData[DIR_ENTRY_attributes] |= ATTRIB_ARCH;
|
||||
|
||||
// Write the new entry
|
||||
_FAT_cache_writePartialSector ( file->partition->cache, dirEntryData,
|
||||
_FAT_fat_clusterToSector( file->partition, file->dirEntryEnd.cluster ) + file->dirEntryEnd.sector,
|
||||
file->dirEntryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE );
|
||||
_FAT_cache_writePartialSector(file->partition->cache, dirEntryData, _FAT_fat_clusterToSector(file->partition,
|
||||
file->dirEntryEnd.cluster) + file->dirEntryEnd.sector, file->dirEntryEnd.offset * DIR_ENTRY_DATA_SIZE,
|
||||
DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
// Flush any sectors in the disc cache
|
||||
if (!_FAT_cache_flush(file->partition->cache))
|
||||
@ -338,7 +337,6 @@ int _FAT_syncToDisc ( FILE_STRUCT* file )
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int _FAT_close_r(struct _reent *r, int fd)
|
||||
{
|
||||
FILE_STRUCT* file = (FILE_STRUCT*) fd;
|
||||
@ -439,8 +437,8 @@ ssize_t _FAT_read_r ( struct _reent *r, int fd, char *ptr, size_t len )
|
||||
|
||||
if ((tempVar < BYTES_PER_READ) && flagNoError)
|
||||
{
|
||||
_FAT_cache_readPartialSector ( cache, ptr, _FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector,
|
||||
position.byte, tempVar );
|
||||
_FAT_cache_readPartialSector(cache, ptr, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, position.byte, tempVar);
|
||||
|
||||
remain -= tempVar;
|
||||
ptr += tempVar;
|
||||
@ -513,15 +511,14 @@ ssize_t _FAT_read_r ( struct _reent *r, int fd, char *ptr, size_t len )
|
||||
chunkEnd = nextChunkStart;
|
||||
nextChunkStart = _FAT_fat_nextCluster(partition, chunkEnd);
|
||||
chunkSize += partition->bytesPerCluster;
|
||||
}
|
||||
while ( ( nextChunkStart == chunkEnd + 1 ) &&
|
||||
} while ((nextChunkStart == chunkEnd + 1) &&
|
||||
#ifdef LIMIT_SECTORS
|
||||
( chunkSize + partition->bytesPerCluster <= LIMIT_SECTORS * BYTES_PER_READ ) &&
|
||||
#endif
|
||||
(chunkSize + partition->bytesPerCluster <= remain));
|
||||
|
||||
if ( !_FAT_cache_readSectors ( cache, _FAT_fat_clusterToSector ( partition, position.cluster ),
|
||||
chunkSize / BYTES_PER_READ, ptr ) )
|
||||
if (!_FAT_cache_readSectors(cache, _FAT_fat_clusterToSector(partition, position.cluster), chunkSize
|
||||
/ BYTES_PER_READ, ptr))
|
||||
{
|
||||
flagNoError = false;
|
||||
r->_errno = EIO;
|
||||
@ -552,8 +549,7 @@ ssize_t _FAT_read_r ( struct _reent *r, int fd, char *ptr, size_t len )
|
||||
tempVar = remain / BYTES_PER_READ; // Number of sectors left
|
||||
if ((tempVar > 0) && flagNoError)
|
||||
{
|
||||
if ( !_FAT_cache_readSectors ( cache, _FAT_fat_clusterToSector ( partition, position.cluster ),
|
||||
tempVar, ptr ) )
|
||||
if (!_FAT_cache_readSectors(cache, _FAT_fat_clusterToSector(partition, position.cluster), tempVar, ptr))
|
||||
{
|
||||
flagNoError = false;
|
||||
r->_errno = EIO;
|
||||
@ -570,8 +566,8 @@ ssize_t _FAT_read_r ( struct _reent *r, int fd, char *ptr, size_t len )
|
||||
// Check if anything is left
|
||||
if ((remain > 0) && flagNoError)
|
||||
{
|
||||
_FAT_cache_readPartialSector ( cache, ptr,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, 0, remain );
|
||||
_FAT_cache_readPartialSector(cache, ptr, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, 0, remain);
|
||||
position.byte += remain;
|
||||
remain = 0;
|
||||
}
|
||||
@ -591,8 +587,8 @@ ssize_t _FAT_read_r ( struct _reent *r, int fd, char *ptr, size_t len )
|
||||
// then get next cluster or allocate next cluster
|
||||
// this solves the over-allocation problems when file size is aligned to cluster size
|
||||
// return true on succes, false on error
|
||||
static bool _FAT_check_position_for_next_cluster( struct _reent *r,
|
||||
FILE_POSITION *position, PARTITION* partition, size_t remain, bool *flagNoError )
|
||||
static bool _FAT_check_position_for_next_cluster(struct _reent *r, FILE_POSITION *position, PARTITION* partition,
|
||||
size_t remain, bool *flagNoError)
|
||||
{
|
||||
uint32_t tempNextCluster;
|
||||
// do nothing if no more data to write
|
||||
@ -623,8 +619,7 @@ static bool _FAT_check_position_for_next_cluster( struct _reent *r,
|
||||
position->cluster = tempNextCluster;
|
||||
}
|
||||
return true;
|
||||
err:
|
||||
if ( flagNoError ) *flagNoError = false;
|
||||
err: if (flagNoError) *flagNoError = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -666,17 +661,16 @@ static bool _FAT_file_extend_r ( struct _reent *r, FILE_STRUCT* file )
|
||||
if (remain + position.byte < BYTES_PER_READ)
|
||||
{
|
||||
// Only need to clear to the end of the sector
|
||||
_FAT_cache_writePartialSector ( cache, zeroBuffer,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, position.byte, remain );
|
||||
_FAT_cache_writePartialSector(cache, zeroBuffer, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, position.byte, remain);
|
||||
position.byte += remain;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (position.byte > 0)
|
||||
{
|
||||
_FAT_cache_writePartialSector ( cache, zeroBuffer,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, position.byte,
|
||||
BYTES_PER_READ - position.byte );
|
||||
_FAT_cache_writePartialSector(cache, zeroBuffer, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, position.byte, BYTES_PER_READ - position.byte);
|
||||
remain -= (BYTES_PER_READ - position.byte);
|
||||
position.byte = 0;
|
||||
position.sector++;
|
||||
@ -713,8 +707,8 @@ static bool _FAT_file_extend_r ( struct _reent *r, FILE_STRUCT* file )
|
||||
|
||||
if (remain > 0)
|
||||
{
|
||||
_FAT_cache_writePartialSector ( cache, zeroBuffer,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, 0, remain );
|
||||
_FAT_cache_writePartialSector(cache, zeroBuffer, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, 0, remain);
|
||||
position.byte = remain;
|
||||
}
|
||||
}
|
||||
@ -824,14 +818,13 @@ ssize_t _FAT_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
if ((tempVar < BYTES_PER_READ) && flagNoError)
|
||||
{
|
||||
// Write partial sector to disk
|
||||
_FAT_cache_writePartialSector ( cache, ptr,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, position.byte, tempVar );
|
||||
_FAT_cache_writePartialSector(cache, ptr, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, position.byte, tempVar);
|
||||
|
||||
remain -= tempVar;
|
||||
ptr += tempVar;
|
||||
position.byte += tempVar;
|
||||
|
||||
|
||||
// Move onto next sector
|
||||
if (position.byte >= BYTES_PER_READ)
|
||||
{
|
||||
@ -853,8 +846,8 @@ ssize_t _FAT_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
|
||||
if ((tempVar > 0 && tempVar < partition->sectorsPerCluster) && flagNoError)
|
||||
{
|
||||
if ( !_FAT_cache_writeSectors ( cache,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, tempVar, ptr ) )
|
||||
if (!_FAT_cache_writeSectors(cache, _FAT_fat_clusterToSector(partition, position.cluster) + position.sector,
|
||||
tempVar, ptr))
|
||||
{
|
||||
flagNoError = false;
|
||||
r->_errno = EIO;
|
||||
@ -889,8 +882,7 @@ ssize_t _FAT_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
// pretend to use up all sectors in next_position
|
||||
next_position.sector = partition->sectorsPerCluster;
|
||||
// get or allocate next cluster
|
||||
_FAT_check_position_for_next_cluster( r, &next_position, partition,
|
||||
remain - chunkSize, &flagNoError );
|
||||
_FAT_check_position_for_next_cluster(r, &next_position, partition, remain - chunkSize, &flagNoError);
|
||||
if (!flagNoError) break; // exit loop on error
|
||||
nextChunkStart = next_position.cluster;
|
||||
if (nextChunkStart != chunkEnd + 1) break; // exit loop if not consecutive
|
||||
@ -898,8 +890,8 @@ ssize_t _FAT_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
chunkSize += partition->bytesPerCluster;
|
||||
}
|
||||
|
||||
if ( !_FAT_cache_writeSectors ( cache,
|
||||
_FAT_fat_clusterToSector( partition, position.cluster ), chunkSize / BYTES_PER_READ, ptr ) )
|
||||
if (!_FAT_cache_writeSectors(cache, _FAT_fat_clusterToSector(partition, position.cluster), chunkSize
|
||||
/ BYTES_PER_READ, ptr))
|
||||
{
|
||||
flagNoError = false;
|
||||
r->_errno = EIO;
|
||||
@ -947,19 +939,18 @@ ssize_t _FAT_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
{
|
||||
if (flagAppending)
|
||||
{
|
||||
_FAT_cache_eraseWritePartialSector ( cache, ptr,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, 0, remain );
|
||||
_FAT_cache_eraseWritePartialSector(cache, ptr, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, 0, remain);
|
||||
}
|
||||
else
|
||||
{
|
||||
_FAT_cache_writePartialSector ( cache, ptr,
|
||||
_FAT_fat_clusterToSector ( partition, position.cluster ) + position.sector, 0, remain );
|
||||
_FAT_cache_writePartialSector(cache, ptr, _FAT_fat_clusterToSector(partition, position.cluster)
|
||||
+ position.sector, 0, remain);
|
||||
}
|
||||
position.byte += remain;
|
||||
remain = 0;
|
||||
}
|
||||
|
||||
|
||||
// Amount written is the originally requested amount minus stuff remaining
|
||||
len = len - remain;
|
||||
|
||||
@ -986,7 +977,6 @@ ssize_t _FAT_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
off_t _FAT_seek_r(struct _reent *r, int fd, off_t pos, int dir)
|
||||
{
|
||||
FILE_STRUCT* file = (FILE_STRUCT*) fd;
|
||||
@ -1100,8 +1090,6 @@ off_t _FAT_seek_r ( struct _reent *r, int fd, off_t pos, int dir )
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _FAT_fstat_r(struct _reent *r, int fd, struct stat *st)
|
||||
{
|
||||
FILE_STRUCT* file = (FILE_STRUCT*) fd;
|
||||
@ -1339,16 +1327,14 @@ int _FAT_get_fragments ( const char *path, _frag_append_t append_fragment, void
|
||||
}
|
||||
offset += partition->sectorsPerCluster;
|
||||
cluster = _FAT_fat_nextCluster(partition, cluster);
|
||||
}
|
||||
while ( offset < size );
|
||||
} while (offset < size);
|
||||
|
||||
// set size
|
||||
append_fragment(callback_data, size, 0, 0);
|
||||
// success
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
_FAT_unlock( &partition->lock );
|
||||
out: _FAT_unlock(&partition->lock);
|
||||
_FAT_close_r(&r, fd);
|
||||
return ret;
|
||||
}
|
||||
|
@ -28,7 +28,6 @@
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FATFILE_H
|
||||
#define _FATFILE_H
|
||||
|
||||
@ -40,7 +39,6 @@
|
||||
#include "directory.h"
|
||||
|
||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 cluster;
|
||||
|
@ -27,7 +27,6 @@
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "file_allocation_table.h"
|
||||
#include "partition.h"
|
||||
#include <string.h>
|
||||
@ -58,7 +57,6 @@ uint32_t _FAT_fat_nextCluster( PARTITION* partition, uint32_t cluster )
|
||||
sector = partition->fat.fatStart + (((cluster * 3) / 2) / BYTES_PER_READ);
|
||||
offset = ((cluster * 3) / 2) % BYTES_PER_READ;
|
||||
|
||||
|
||||
_FAT_cache_readLittleEndianValue(partition->cache, &nextCluster, sector, offset, sizeof(u8));
|
||||
|
||||
offset++;
|
||||
@ -303,15 +301,12 @@ uint32_t _FAT_fat_linkFreeClusterCleared ( PARTITION* partition, uint32_t cluste
|
||||
memset(emptySector, 0, BYTES_PER_READ);
|
||||
for (i = 0; i < partition->sectorsPerCluster; i++)
|
||||
{
|
||||
_FAT_cache_writeSectors ( partition->cache,
|
||||
_FAT_fat_clusterToSector ( partition, newCluster ) + i,
|
||||
1, emptySector );
|
||||
_FAT_cache_writeSectors(partition->cache, _FAT_fat_clusterToSector(partition, newCluster) + i, 1, emptySector);
|
||||
}
|
||||
|
||||
return newCluster;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
_FAT_fat_clearLinks
|
||||
frees any cluster used by a file
|
||||
@ -320,8 +315,7 @@ bool _FAT_fat_clearLinks ( PARTITION* partition, uint32_t cluster )
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if ( ( cluster < CLUSTER_FIRST ) || ( cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */ ) )
|
||||
return false;
|
||||
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */)) return false;
|
||||
|
||||
// If this clears up more space in the FAT before the current free pointer, move it backwards
|
||||
if (cluster < partition->fat.firstFree)
|
||||
@ -393,7 +387,8 @@ Trace the cluster links until the last one is found
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_lastCluster(PARTITION* partition, uint32_t cluster)
|
||||
{
|
||||
while ( ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_FREE ) && ( _FAT_fat_nextCluster( partition, cluster ) != CLUSTER_EOF ) )
|
||||
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster)
|
||||
!= CLUSTER_EOF))
|
||||
{
|
||||
cluster = _FAT_fat_nextCluster(partition, cluster);
|
||||
}
|
||||
|
@ -43,7 +43,6 @@
|
||||
#define CLUSTERS_PER_FAT12 4085
|
||||
#define CLUSTERS_PER_FAT16 65525
|
||||
|
||||
|
||||
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster);
|
||||
|
||||
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster);
|
||||
@ -59,9 +58,8 @@ unsigned int _FAT_fat_freeClusterCount ( PARTITION* partition );
|
||||
|
||||
static inline sec_t _FAT_fat_clusterToSector(PARTITION* partition, uint32_t cluster)
|
||||
{
|
||||
return ( cluster >= CLUSTER_FIRST ) ?
|
||||
( ( cluster - CLUSTER_FIRST ) * ( sec_t )partition->sectorsPerCluster ) + partition->dataStart :
|
||||
partition->rootDirStart;
|
||||
return (cluster >= CLUSTER_FIRST) ? ((cluster - CLUSTER_FIRST) * (sec_t) partition->sectorsPerCluster)
|
||||
+ partition->dataStart : partition->rootDirStart;
|
||||
}
|
||||
|
||||
static inline bool _FAT_fat_isValidCluster(PARTITION* partition, uint32_t cluster)
|
||||
|
@ -26,7 +26,6 @@
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <time.h>
|
||||
#include "filetime.h"
|
||||
#include "common.h"
|
||||
@ -58,17 +57,12 @@ uint16_t _FAT_filetime_getTimeFromRTC ( void )
|
||||
if ((timeParts.tm_min < 0) || (timeParts.tm_min > MAX_MINUTE)) return 0;
|
||||
if ((timeParts.tm_sec < 0) || (timeParts.tm_sec > MAX_SECOND)) return 0;
|
||||
|
||||
return (
|
||||
( ( timeParts.tm_hour & 0x1F ) << 11 ) |
|
||||
( ( timeParts.tm_min & 0x3F ) << 5 ) |
|
||||
( ( timeParts.tm_sec >> 1 ) & 0x1F )
|
||||
);
|
||||
return (((timeParts.tm_hour & 0x1F) << 11) | ((timeParts.tm_min & 0x3F) << 5) | ((timeParts.tm_sec >> 1) & 0x1F));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint16_t _FAT_filetime_getDateFromRTC(void)
|
||||
{
|
||||
#ifdef USE_RTC_TIME
|
||||
@ -84,11 +78,8 @@ uint16_t _FAT_filetime_getDateFromRTC ( void )
|
||||
if ((timeParts.tm_mon < MIN_MONTH) || (timeParts.tm_mon > MAX_MONTH)) return 0;
|
||||
if ((timeParts.tm_mday < MIN_DAY) || (timeParts.tm_mday > MAX_DAY)) return 0;
|
||||
|
||||
return (
|
||||
( ( ( timeParts.tm_year - 80 ) & 0x7F ) << 9 ) | // Adjust for MS-FAT base year (1980 vs 1900 for tm_year)
|
||||
( ( ( timeParts.tm_mon + 1 ) & 0xF ) << 5 ) |
|
||||
( timeParts.tm_mday & 0x1F )
|
||||
);
|
||||
return ((((timeParts.tm_year - 80) & 0x7F) << 9) | // Adjust for MS-FAT base year (1980 vs 1900 for tm_year)
|
||||
(((timeParts.tm_mon + 1) & 0xF) << 5) | (timeParts.tm_mday & 0x1F));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -37,5 +37,4 @@ uint16_t _FAT_filetime_getDateFromRTC ( void );
|
||||
|
||||
time_t _FAT_filetime_to_time_t(uint16_t t, uint16_t d);
|
||||
|
||||
|
||||
#endif // _FILETIME_H
|
||||
|
@ -38,41 +38,20 @@
|
||||
#include "mem_allocate.h"
|
||||
#include "disc_fat.h"
|
||||
|
||||
static const devoptab_t dotab_fat =
|
||||
{
|
||||
"fat",
|
||||
sizeof ( FILE_STRUCT ),
|
||||
_FAT_open_r,
|
||||
_FAT_close_r,
|
||||
_FAT_write_r,
|
||||
_FAT_read_r,
|
||||
_FAT_seek_r,
|
||||
_FAT_fstat_r,
|
||||
_FAT_stat_r,
|
||||
_FAT_link_r,
|
||||
_FAT_unlink_r,
|
||||
_FAT_chdir_r,
|
||||
_FAT_rename_r,
|
||||
_FAT_mkdir_r,
|
||||
sizeof ( DIR_STATE_STRUCT ),
|
||||
_FAT_diropen_r,
|
||||
_FAT_dirreset_r,
|
||||
_FAT_dirnext_r,
|
||||
_FAT_dirclose_r,
|
||||
_FAT_statvfs_r,
|
||||
_FAT_ftruncate_r,
|
||||
_FAT_fsync_r,
|
||||
NULL /* Device data */
|
||||
static const devoptab_t dotab_fat = { "fat", sizeof(FILE_STRUCT), _FAT_open_r, _FAT_close_r, _FAT_write_r, _FAT_read_r,
|
||||
_FAT_seek_r, _FAT_fstat_r, _FAT_stat_r, _FAT_link_r, _FAT_unlink_r, _FAT_chdir_r, _FAT_rename_r, _FAT_mkdir_r,
|
||||
sizeof(DIR_STATE_STRUCT), _FAT_diropen_r, _FAT_dirreset_r, _FAT_dirnext_r, _FAT_dirclose_r, _FAT_statvfs_r,
|
||||
_FAT_ftruncate_r, _FAT_fsync_r, NULL /* Device data */
|
||||
};
|
||||
|
||||
bool fatMount ( const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage )
|
||||
bool fatMount(const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize,
|
||||
uint32_t SectorsPerPage)
|
||||
{
|
||||
PARTITION* partition;
|
||||
devoptab_t* devops;
|
||||
char* nameCopy;
|
||||
|
||||
if ( !interface->startup() )
|
||||
return false;
|
||||
if (!interface->startup()) return false;
|
||||
|
||||
if (!interface->isInserted())
|
||||
{
|
||||
@ -150,9 +129,7 @@ bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
|
||||
int defaultDevice = -1;
|
||||
const DISC_INTERFACE *disc;
|
||||
|
||||
for ( i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++ )
|
||||
for (i = 0; _FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL; i++)
|
||||
{
|
||||
disc = _FAT_disc_interfaces[i].getInterface();
|
||||
if (fatMount(_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE))
|
||||
@ -177,16 +154,15 @@ bool fatInit ( uint32_t cacheSize, bool setAsDefaultDevice )
|
||||
strcpy(filePath, _FAT_disc_interfaces[defaultDevice].name);
|
||||
strcat(filePath, ":/");
|
||||
#ifdef ARGV_MAGIC
|
||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' ) != NULL )
|
||||
if (__system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr(__system_argv->argv[0], '/')
|
||||
!= NULL)
|
||||
{
|
||||
// Check the app's path against each of our mounted devices, to see
|
||||
// if we can support it. If so, change to that path.
|
||||
for ( i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++ )
|
||||
for (i = 0; _FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL; i++)
|
||||
{
|
||||
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
||||
strlen( _FAT_disc_interfaces[i].name ) ) )
|
||||
if (!strncasecmp(__system_argv->argv[0], _FAT_disc_interfaces[i].name, strlen(
|
||||
_FAT_disc_interfaces[i].name)))
|
||||
{
|
||||
char *lastSlash;
|
||||
strcpy(filePath, __system_argv->argv[0]);
|
||||
@ -212,4 +188,3 @@ bool fatInitDefault ( void )
|
||||
return fatInit(DEFAULT_CACHE_PAGES, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,6 +82,4 @@ static inline void _FAT_unlock( mutex_t *mutex )
|
||||
|
||||
#endif // USE_LWP_LOCK
|
||||
|
||||
|
||||
#endif // _LOCK_H
|
||||
|
||||
|
@ -52,8 +52,7 @@ Data offsets
|
||||
// BIOS Parameter Block offsets
|
||||
enum BPB
|
||||
{
|
||||
BPB_jmpBoot = 0x00,
|
||||
BPB_OEMName = 0x03,
|
||||
BPB_jmpBoot = 0x00, BPB_OEMName = 0x03,
|
||||
// BIOS Parameter Block
|
||||
BPB_bytesPerSector = 0x0B,
|
||||
BPB_sectorsPerCluster = 0x0D,
|
||||
@ -98,7 +97,6 @@ enum BPB
|
||||
|
||||
static const char FAT_SIG[3] = { 'F', 'A', 'T' };
|
||||
|
||||
|
||||
sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
{
|
||||
uint8_t part_table[16 * 4];
|
||||
@ -120,8 +118,8 @@ sec_t FindFirstValidPartition( const DISC_INTERFACE* disc )
|
||||
{
|
||||
sec_t part_lba = u8array_to_u32(ptr, 0x8);
|
||||
|
||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer
|
||||
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
{
|
||||
return part_lba;
|
||||
}
|
||||
@ -143,8 +141,8 @@ sec_t FindFirstValidPartition( const DISC_INTERFACE* disc )
|
||||
|
||||
if (!_FAT_disc_readSectors(disc, part_lba2, 1, sectorBuffer)) return 0;
|
||||
|
||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer
|
||||
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
{
|
||||
return part_lba2;
|
||||
}
|
||||
@ -155,8 +153,8 @@ sec_t FindFirstValidPartition( const DISC_INTERFACE* disc )
|
||||
else
|
||||
{
|
||||
if (!_FAT_disc_readSectors(disc, part_lba, 1, sectorBuffer)) return 0;
|
||||
if ( !memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) ||
|
||||
!memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer
|
||||
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
{
|
||||
return part_lba;
|
||||
}
|
||||
@ -165,7 +163,8 @@ sec_t FindFirstValidPartition( const DISC_INTERFACE* disc )
|
||||
return 0;
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector )
|
||||
PARTITION* _FAT_partition_constructor(const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage,
|
||||
sec_t startSector)
|
||||
{
|
||||
PARTITION* partition;
|
||||
uint8_t sectorBuffer[BYTES_PER_READ] = { 0 };
|
||||
@ -206,15 +205,16 @@ PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cac
|
||||
}
|
||||
|
||||
// Now verify that this is indeed a FAT partition
|
||||
if ( memcmp( sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) &&
|
||||
memcmp( sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof( FAT_SIG ) ) )
|
||||
if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) && memcmp(sectorBuffer
|
||||
+ BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check again for the last two cases to make sure that we really have a FAT filesystem here
|
||||
// and won't corrupt any data
|
||||
if ( memcmp( sectorBuffer + BPB_FAT16_fileSysType, "FAT", 3 ) != 0 && memcmp( sectorBuffer + BPB_FAT32_fileSysType, "FAT32", 5 ) != 0 )
|
||||
if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, "FAT", 3) != 0 && memcmp(sectorBuffer + BPB_FAT32_fileSysType,
|
||||
"FAT32", 5) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -247,18 +247,21 @@ PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cac
|
||||
}
|
||||
|
||||
partition->bytesPerSector = BYTES_PER_READ; // Sector size is redefined to be 512 bytes
|
||||
partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster] * u8array_to_u16( sectorBuffer, BPB_bytesPerSector ) / BYTES_PER_READ;
|
||||
partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster] * u8array_to_u16(sectorBuffer,
|
||||
BPB_bytesPerSector) / BYTES_PER_READ;
|
||||
partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster;
|
||||
partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors);
|
||||
|
||||
partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat);
|
||||
partition->dataStart = partition->rootDirStart +
|
||||
( ( u8array_to_u16( sectorBuffer, BPB_rootEntries ) * DIR_ENTRY_DATA_SIZE ) / partition->bytesPerSector );
|
||||
partition->dataStart = partition->rootDirStart + ((u8array_to_u16(sectorBuffer, BPB_rootEntries)
|
||||
* DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector);
|
||||
|
||||
partition->totalSize = ( ( uint64_t )partition->numberOfSectors - ( partition->dataStart - startSector ) ) * ( uint64_t )partition->bytesPerSector;
|
||||
partition->totalSize = ((uint64_t) partition->numberOfSectors - (partition->dataStart - startSector))
|
||||
* (uint64_t) partition->bytesPerSector;
|
||||
|
||||
// Store info about FAT
|
||||
uint32_t clusterCount = ( partition->numberOfSectors - ( uint32_t )( partition->dataStart - startSector ) ) / partition->sectorsPerCluster;
|
||||
uint32_t clusterCount = (partition->numberOfSectors - (uint32_t) (partition->dataStart - startSector))
|
||||
/ partition->sectorsPerCluster;
|
||||
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
||||
partition->fat.firstFree = CLUSTER_FIRST;
|
||||
|
||||
@ -287,12 +290,14 @@ PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cac
|
||||
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80))
|
||||
{
|
||||
// Use the active FAT
|
||||
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * ( sectorBuffer[BPB_FAT32_extFlags] & 0x0F ) );
|
||||
partition->fat.fatStart = partition->fat.fatStart + (partition->fat.sectorsPerFat
|
||||
* (sectorBuffer[BPB_FAT32_extFlags] & 0x0F));
|
||||
}
|
||||
}
|
||||
|
||||
// Create a cache to use
|
||||
partition->cache = _FAT_cache_constructor ( cacheSize, sectorsPerPage, partition->disc, startSector + partition->numberOfSectors );
|
||||
partition->cache = _FAT_cache_constructor(cacheSize, sectorsPerPage, partition->disc, startSector
|
||||
+ partition->numberOfSectors);
|
||||
|
||||
// Set current directory to the root
|
||||
partition->cwdCluster = partition->rootDirCluster;
|
||||
|
@ -38,7 +38,10 @@
|
||||
extern const char* DEVICE_NAME;
|
||||
|
||||
// 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
|
||||
{
|
||||
@ -74,7 +77,8 @@ typedef struct
|
||||
/*
|
||||
Mount the supplied device and return a pointer to the struct necessary to use it
|
||||
*/
|
||||
PARTITION* _FAT_partition_constructor ( const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector );
|
||||
PARTITION* _FAT_partition_constructor(const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage,
|
||||
sec_t startSector);
|
||||
|
||||
/*
|
||||
Dismount the device and free all structures used.
|
||||
|
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_GROUP(map,gsid) ntfs_find_group(map,gsid)
|
||||
|
||||
|
||||
/*
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
@ -122,7 +121,8 @@ typedef char BIGSID[40];
|
||||
* (private to this module)
|
||||
*/
|
||||
|
||||
struct MAPLIST {
|
||||
struct MAPLIST
|
||||
{
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
@ -150,14 +150,11 @@ BOOL ntfs_same_sid(const SID *first, const SID *second);
|
||||
|
||||
BOOL ntfs_is_user_sid(const SID *usid);
|
||||
|
||||
|
||||
int ntfs_sid_size(const SID * sid);
|
||||
unsigned int ntfs_attr_size(const char *attr);
|
||||
|
||||
const SID *ntfs_find_usid(const struct MAPPING *usermapping,
|
||||
uid_t uid, SID *pdefsid);
|
||||
const SID *ntfs_find_gsid(const struct MAPPING *groupmapping,
|
||||
gid_t gid, SID *pdefsid);
|
||||
const SID *ntfs_find_usid(const struct MAPPING *usermapping, uid_t uid, SID *pdefsid);
|
||||
const SID *ntfs_find_gsid(const struct MAPPING *groupmapping, gid_t gid, SID *pdefsid);
|
||||
uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid);
|
||||
gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
||||
const SID *ntfs_acl_owner(const char *secattr);
|
||||
@ -184,12 +181,9 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
||||
|
||||
#endif /* POSIXACLS */
|
||||
|
||||
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
const SID *usid, const SID *gsid, BOOL fordir);
|
||||
int ntfs_build_permissions(const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
char *ntfs_build_descr(mode_t mode,
|
||||
int isdir, const SID * usid, const SID * gsid);
|
||||
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl, const SID *usid, const SID *gsid, BOOL fordir);
|
||||
int ntfs_build_permissions(const char *securattr, const SID *usid, const SID *gsid, BOOL isdir);
|
||||
char *ntfs_build_descr(mode_t mode, int isdir, const SID * usid, const SID * gsid);
|
||||
struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid);
|
||||
struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem);
|
||||
struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -49,12 +49,10 @@ extern ntfschar TXF_DATA[10];
|
||||
*
|
||||
* TODO: Describe them.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
LCN_EINVAL = -4,
|
||||
LCN_EIO = -5,
|
||||
LCN_RL_NOT_MAPPED = -2, LCN_ENOENT = -3, LCN_EINVAL = -4, LCN_EIO = -5,
|
||||
} ntfs_lcn_special_values;
|
||||
|
||||
/**
|
||||
@ -75,7 +73,8 @@ typedef enum {
|
||||
* any modification of the search context, to automagically get the next
|
||||
* matching attribute.
|
||||
*/
|
||||
struct _ntfs_attr_search_ctx {
|
||||
struct _ntfs_attr_search_ctx
|
||||
{
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
BOOL is_first;
|
||||
@ -87,19 +86,15 @@ struct _ntfs_attr_search_ctx {
|
||||
};
|
||||
|
||||
extern void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
|
||||
MFT_RECORD *mrec);
|
||||
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec);
|
||||
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const VCN lowest_vcn, const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, const ATTR_TYPES type);
|
||||
|
||||
/**
|
||||
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
||||
@ -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)
|
||||
{
|
||||
return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
|
||||
NULL, 0, ctx);
|
||||
return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,7 +168,8 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
|
||||
* @state contains NTFS attribute specific flags describing this attribute
|
||||
* structure. See ntfs_attr_state_bits above.
|
||||
*/
|
||||
struct _ntfs_attr {
|
||||
struct _ntfs_attr
|
||||
{
|
||||
runlist_element *rl;
|
||||
ntfs_inode *ni;
|
||||
ATTR_TYPES type;
|
||||
@ -196,12 +191,14 @@ struct _ntfs_attr {
|
||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
||||
* structure
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
NA_NonResident, /* 1: Attribute is not resident. */
|
||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
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;
|
||||
|
||||
#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.
|
||||
*/
|
||||
typedef union {
|
||||
typedef union
|
||||
{
|
||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||
a_val without specifying any of the below. */
|
||||
STANDARD_INFORMATION std_inf;
|
||||
@ -265,32 +263,23 @@ typedef union {
|
||||
EFS_ATTR_HEADER efs;
|
||||
} attr_val;
|
||||
|
||||
extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
|
||||
const ATTR_FLAGS data_flags, const BOOL encrypted,
|
||||
const BOOL sparse,
|
||||
const s64 allocated_size, const s64 data_size,
|
||||
const s64 initialized_size, const s64 compressed_size,
|
||||
const u8 compression_unit);
|
||||
extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident, const ATTR_FLAGS data_flags, const BOOL encrypted,
|
||||
const BOOL sparse, const s64 allocated_size, const s64 data_size, const s64 initialized_size,
|
||||
const s64 compressed_size, const u8 compression_unit);
|
||||
|
||||
/* warning : in the following "name" has to be freeable */
|
||||
/* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */
|
||||
extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len);
|
||||
extern void ntfs_attr_close(ntfs_attr *na);
|
||||
|
||||
extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count,
|
||||
const void *b);
|
||||
extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b);
|
||||
extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b);
|
||||
extern int ntfs_attr_pclose(ntfs_attr *na);
|
||||
|
||||
extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len, s64 *data_size);
|
||||
extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len, s64 *data_size);
|
||||
|
||||
extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos,
|
||||
const s64 bk_cnt, const u32 bk_size, void *dst);
|
||||
extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos,
|
||||
s64 bk_cnt, const u32 bk_size, void *src);
|
||||
extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, const u32 bk_size, void *dst);
|
||||
extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt, const u32 bk_size, void *src);
|
||||
|
||||
extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn);
|
||||
extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
||||
@ -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 runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
|
||||
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type, const s64 size);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, const s64 size);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type);
|
||||
int ntfs_attr_make_non_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx);
|
||||
int ntfs_attr_force_non_resident(ntfs_attr *na);
|
||||
extern int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
|
||||
|
||||
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
||||
ATTR_FLAGS flags);
|
||||
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
||||
ATTR_FLAGS flags);
|
||||
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, ntfschar *name, u8 name_len, u8 *val,
|
||||
u32 size, ATTR_FLAGS flags);
|
||||
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, ntfschar *name, u8 name_len,
|
||||
VCN lowest_vcn, int dataruns_size, ATTR_FLAGS flags);
|
||||
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, s64 size);
|
||||
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask);
|
||||
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, ntfschar *name, u8 name_len, u8 *val, s64 size);
|
||||
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, ntfschar *name, u8 name_len, ATTR_FLAGS flags,
|
||||
ATTR_FLAGS mask);
|
||||
extern int ntfs_attr_rm(ntfs_attr *na);
|
||||
|
||||
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
|
||||
|
||||
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 new_size);
|
||||
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, const u32 new_size);
|
||||
|
||||
extern int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni);
|
||||
extern int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra);
|
||||
@ -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
|
||||
* errno describes the error.
|
||||
*/
|
||||
extern s64 ntfs_get_attribute_value(const ntfs_volume *vol,
|
||||
const ATTR_RECORD *a, u8 *b);
|
||||
extern s64 ntfs_get_attribute_value(const ntfs_volume *vol, const ATTR_RECORD *a, u8 *b);
|
||||
|
||||
extern void ntfs_attr_name_free(char **name);
|
||||
extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len);
|
||||
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len);
|
||||
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len);
|
||||
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
|
||||
|
||||
#endif /* defined _NTFS_ATTRIB_H */
|
||||
|
@ -65,8 +65,10 @@
|
||||
|
||||
#define STANDARD_COMPRESSION_UNIT 4
|
||||
|
||||
ntfschar AT_UNNAMED[] = { const_cpu_to_le16( '\0' ) };
|
||||
ntfschar STREAM_SDS[] = { const_cpu_to_le16( '$' ),
|
||||
ntfschar AT_UNNAMED[] =
|
||||
{ const_cpu_to_le16( '\0' )};
|
||||
ntfschar STREAM_SDS[] =
|
||||
{ const_cpu_to_le16( '$' ),
|
||||
const_cpu_to_le16( 'S' ),
|
||||
const_cpu_to_le16( 'D' ),
|
||||
const_cpu_to_le16( 'S' ),
|
||||
@ -854,7 +856,6 @@ map_rl:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -899,8 +900,7 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
||||
return -32;
|
||||
}
|
||||
|
||||
if ( !count )
|
||||
return 0;
|
||||
if (!count) return 0;
|
||||
/*
|
||||
* Truncate reads beyond end of attribute,
|
||||
* but round to next 512 byte boundary for encrypted
|
||||
@ -908,9 +908,7 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
||||
*/
|
||||
max_read = na->data_size;
|
||||
max_init = na->initialized_size;
|
||||
if ( na->ni->vol->efs_raw
|
||||
&& ( na->data_flags & ATTR_IS_ENCRYPTED )
|
||||
&& NAttrNonResident( na ) )
|
||||
if (na->ni->vol->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) && NAttrNonResident( na ))
|
||||
{
|
||||
if (na->data_size != na->initialized_size)
|
||||
{
|
||||
@ -923,8 +921,7 @@ static s64 ntfs_attr_getfragments_i( ntfs_attr *na, const s64 pos, s64 count, u6
|
||||
}
|
||||
if (pos + count > max_read)
|
||||
{
|
||||
if ( pos >= max_read )
|
||||
return 0;
|
||||
if (pos >= max_read) return 0;
|
||||
count = max_read - pos;
|
||||
}
|
||||
/* If it is a resident attribute, get the value from the mft record. */
|
||||
@ -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
|
||||
* restored
|
||||
*/
|
||||
if ( na->ni->vol->efs_raw &&
|
||||
( na->data_flags & ATTR_IS_ENCRYPTED ) &&
|
||||
( ( pos + count ) > max_init - 2 ) )
|
||||
if (na->ni->vol->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) && ((pos + count) > max_init - 2))
|
||||
{
|
||||
return -35; //No encrypted files
|
||||
/*
|
||||
@ -1097,30 +1092,23 @@ retry:
|
||||
count -= br;
|
||||
b = b + br;
|
||||
}
|
||||
if ( br == to_read )
|
||||
continue;
|
||||
if (br == to_read) continue;
|
||||
/* If the syscall was interrupted, try again. */
|
||||
if ( br == ( s64 ) - 1 && errno == EINTR )
|
||||
goto retry;
|
||||
if ( total )
|
||||
return total;
|
||||
if ( !br )
|
||||
errno = EIO;
|
||||
if (br == (s64) -1 && errno == EINTR) goto retry;
|
||||
if (total) return total;
|
||||
if (!br) errno = EIO;
|
||||
ntfs_log_perror( "%s: ntfs_pread failed", __FUNCTION__ );
|
||||
//return -1;
|
||||
return -38;
|
||||
}
|
||||
/* Finally, return the number of bytes read. */
|
||||
return total + total2;
|
||||
rl_err_out:
|
||||
if ( total )
|
||||
return total;
|
||||
rl_err_out: if (total) return total;
|
||||
errno = EIO;
|
||||
//return -1;
|
||||
return -39;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure
|
||||
* @na: ntfs attribute to read from
|
||||
@ -1140,8 +1128,8 @@ rl_err_out:
|
||||
* to the return code of ntfs_pread(), or to EINVAL in case of invalid
|
||||
* arguments.
|
||||
*/
|
||||
s64 ntfs_attr_getfragments( ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
||||
_ntfs_frag_append_t append_fragment, void *callback_data )
|
||||
s64 ntfs_attr_getfragments(ntfs_attr *na, const s64 pos, s64 count, u64 offset, _ntfs_frag_append_t append_fragment,
|
||||
void *callback_data)
|
||||
{
|
||||
s64 ret;
|
||||
|
||||
@ -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);
|
||||
*/
|
||||
|
||||
ret = ntfs_attr_getfragments_i( na, pos, count, offset,
|
||||
append_fragment, callback_data );
|
||||
ret = ntfs_attr_getfragments_i(na, pos, count, offset, append_fragment, callback_data);
|
||||
|
||||
//ntfs_log_leave("\n");
|
||||
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_data_size : 1;
|
||||
} need_to = { 0, 0 };
|
||||
}need_to =
|
||||
{ 0, 0};
|
||||
BOOL makingnonresident = FALSE;
|
||||
BOOL wasnonresident = FALSE;
|
||||
BOOL compressed;
|
||||
@ -4090,7 +4078,6 @@ int ntfs_attr_set_flags( ntfs_inode *ni, ATTR_TYPES type,
|
||||
return ( res );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_attr_rm - remove attribute from ntfs inode
|
||||
* @na: opened ntfs attribute to delete
|
||||
@ -4647,7 +4634,6 @@ cluster_free_err_out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int ntfs_resident_attr_resize( ntfs_attr *na, const s64 newsize );
|
||||
|
||||
/**
|
||||
@ -5951,7 +5937,6 @@ put_err_out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int ntfs_non_resident_attr_expand( ntfs_attr *na, const s64 newsize )
|
||||
{
|
||||
int ret;
|
||||
@ -6214,8 +6199,6 @@ err_exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ntfs_attr_exist( ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
|
||||
u32 name_len )
|
||||
{
|
||||
|
@ -62,7 +62,8 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
|
||||
if (!ni) {
|
||||
if (!ni)
|
||||
{
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -70,13 +71,15 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
|
||||
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");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ni->attr_list) {
|
||||
if (!ni->attr_list)
|
||||
{
|
||||
ntfs_log_trace("Corrupt in-memory struct.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -84,9 +87,9 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
|
||||
errno = 0;
|
||||
ale = (ATTR_LIST_ENTRY *) ni->attr_list;
|
||||
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
||||
if (MREF_LE(ale->mft_reference) != ni->mft_no)
|
||||
return 1;
|
||||
while ((u8*) ale < ni->attr_list + ni->attr_list_size)
|
||||
{
|
||||
if (MREF_LE(ale->mft_reference) != ni->mft_no) return 1;
|
||||
ale = (ATTR_LIST_ENTRY *) ((u8*) ale + le16_to_cpu(ale->length));
|
||||
}
|
||||
return 0;
|
||||
@ -117,7 +120,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
(long long) ni->mft_no,
|
||||
(unsigned) le32_to_cpu(attr->type));
|
||||
|
||||
if (!ni || !attr) {
|
||||
if (!ni || !attr)
|
||||
{
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
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));
|
||||
|
||||
if (ni->nr_extents == -1)
|
||||
ni = ni->base_ni;
|
||||
if (ni->nr_extents == -1) ni = ni->base_ni;
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
if (!NInoAttrList(ni))
|
||||
{
|
||||
ntfs_log_trace("Attribute list isn't present.\n");
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Determine size and allocate memory for new attribute list. */
|
||||
entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
|
||||
attr->name_length + 7) & ~7;
|
||||
entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * attr->name_length + 7) & ~7;
|
||||
new_al = ntfs_calloc(ni->attr_list_size + entry_len);
|
||||
if (!new_al)
|
||||
return -1;
|
||||
if (!new_al) return -1;
|
||||
|
||||
/* Find place for the new entry. */
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
if (!ctx)
|
||||
{
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
|
||||
((u8*)attr + le16_to_cpu(attr->name_offset)) :
|
||||
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
|
||||
(attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) :
|
||||
0, (attr->non_resident) ? NULL : ((u8*)attr +
|
||||
le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
|
||||
0 : le32_to_cpu(attr->value_length), ctx)) {
|
||||
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*) ((u8*) attr + le16_to_cpu(attr->name_offset))
|
||||
: AT_UNNAMED, attr->name_length, CASE_SENSITIVE, (attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) : 0,
|
||||
(attr->non_resident) ? NULL : ((u8*) attr + le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
|
||||
0
|
||||
: le32_to_cpu(attr->value_length), ctx))
|
||||
{
|
||||
/* Found some extent, check it to be before new extent. */
|
||||
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) {
|
||||
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn)
|
||||
{
|
||||
err = EEXIST;
|
||||
ntfs_log_trace("Such attribute already present in the "
|
||||
"attribute list.\n");
|
||||
@ -163,11 +166,13 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
goto err_out;
|
||||
}
|
||||
/* Add new entry after this extent. */
|
||||
ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
|
||||
le16_to_cpu(ctx->al_entry->length));
|
||||
} else {
|
||||
ale = (ATTR_LIST_ENTRY*) ((u8*) ctx->al_entry + le16_to_cpu(ctx->al_entry->length));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for real errors. */
|
||||
if (errno != ENOENT) {
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
@ -192,21 +197,21 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
|
||||
if (attr->non_resident)
|
||||
ale->lowest_vcn = attr->lowest_vcn;
|
||||
else
|
||||
ale->lowest_vcn = 0;
|
||||
else ale->lowest_vcn = 0;
|
||||
ale->mft_reference = mref;
|
||||
ale->instance = attr->instance;
|
||||
memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
|
||||
attr->name_length * sizeof(ntfschar));
|
||||
memcpy(ale->name, (u8 *) attr + le16_to_cpu(attr->name_offset), attr->name_length * sizeof(ntfschar));
|
||||
|
||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
if (!na)
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
|
||||
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len))
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
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. */
|
||||
memcpy(new_al, ni->attr_list, entry_offset);
|
||||
memcpy(new_al + entry_offset + entry_len, ni->attr_list +
|
||||
entry_offset, ni->attr_list_size - entry_offset);
|
||||
memcpy(new_al + entry_offset + entry_len, ni->attr_list + entry_offset, ni->attr_list_size - entry_offset);
|
||||
|
||||
/* Set new runlist. */
|
||||
free(ni->attr_list);
|
||||
@ -225,9 +229,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
err_out: if (na) ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
errno = err;
|
||||
return -1;
|
||||
@ -250,7 +252,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
int err;
|
||||
|
||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry)
|
||||
{
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -258,8 +261,7 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
|
||||
if (ctx->base_ntfs_ino)
|
||||
base_ni = ctx->base_ntfs_ino;
|
||||
else
|
||||
base_ni = ctx->ntfs_ino;
|
||||
else base_ni = ctx->ntfs_ino;
|
||||
ale = ctx->al_entry;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
||||
@ -267,7 +269,8 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
(unsigned) le32_to_cpu(ctx->al_entry->type),
|
||||
(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");
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
@ -276,17 +279,18 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
/* Allocate memory for new attribute list. */
|
||||
new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
|
||||
new_al = ntfs_calloc(new_al_len);
|
||||
if (!new_al)
|
||||
return -1;
|
||||
if (!new_al) return -1;
|
||||
|
||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
if (!na)
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, new_al_len)) {
|
||||
if (ntfs_attr_truncate(na, new_al_len))
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
goto err_out;
|
||||
@ -305,9 +309,7 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
err_out: if (na) ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
errno = err;
|
||||
return -1;
|
||||
|
@ -44,8 +44,7 @@ static __inline__ void ntfs_attrlist_mark_dirty(ntfs_inode *ni)
|
||||
{
|
||||
if (ni->nr_extents == -1)
|
||||
NInoAttrListSetDirty(ni->base_ni);
|
||||
else
|
||||
NInoAttrListSetDirty(ni);
|
||||
else NInoAttrListSetDirty(ni);
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_ATTRLIST_H */
|
||||
|
@ -34,20 +34,24 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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 + 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 + 1] = (uint8_t) (value >> 8);
|
||||
item[offset + 2] = (uint8_t) (value >> 16);
|
||||
|
@ -55,12 +55,10 @@
|
||||
*/
|
||||
void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
{
|
||||
if (!bitmap || new_value > 1)
|
||||
return;
|
||||
if (!bitmap || new_value > 1) return;
|
||||
if (!new_value)
|
||||
bitmap[bit >> 3] &= ~(1 << (bit & 7));
|
||||
else
|
||||
bitmap[bit >> 3] |= (1 << (bit & 7));
|
||||
else 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)
|
||||
{
|
||||
if (!bitmap)
|
||||
return -1;
|
||||
if (!bitmap) return -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;
|
||||
|
||||
if (!bitmap || new_value > 1)
|
||||
return -1;
|
||||
if (!bitmap || new_value > 1) return -1;
|
||||
shift = bit & 7;
|
||||
old_bit = (bitmap[bit >> 3] >> shift) & 1;
|
||||
if (new_value != old_bit)
|
||||
bitmap[bit >> 3] ^= 1 << shift;
|
||||
if (new_value != old_bit) bitmap[bit >> 3] ^= 1 << shift;
|
||||
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.
|
||||
*/
|
||||
static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
s64 count, int value)
|
||||
static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, s64 count, int value)
|
||||
{
|
||||
s64 bufsize, br;
|
||||
u8 *buf, *lastbyte_buf;
|
||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
||||
|
||||
if (!na || start_bit < 0 || count < 0) {
|
||||
if (!na || start_bit < 0 || count < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
|
||||
__FUNCTION__, na, (long long)start_bit, (long long)count);
|
||||
@ -129,36 +124,34 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
bit = start_bit & 7;
|
||||
if (bit)
|
||||
firstbyte = 1;
|
||||
else
|
||||
firstbyte = 0;
|
||||
else firstbyte = 0;
|
||||
|
||||
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
||||
bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
|
||||
if (bufsize > 8192)
|
||||
bufsize = 8192;
|
||||
if (bufsize > 8192) bufsize = 8192;
|
||||
|
||||
buf = ntfs_malloc(bufsize);
|
||||
if (!buf)
|
||||
return -1;
|
||||
if (!buf) return -1;
|
||||
|
||||
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
||||
memset(buf, value ? 0xff : 0, bufsize);
|
||||
|
||||
/* If there is a first partial byte... */
|
||||
if (bit) {
|
||||
if (bit)
|
||||
{
|
||||
/* read it in... */
|
||||
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
||||
if (br != 1) {
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
if (br != 1)
|
||||
{
|
||||
if (br >= 0) errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set or clear the appropriate bits in it. */
|
||||
while ((bit & 7) && count--) {
|
||||
while ((bit & 7) && count--)
|
||||
{
|
||||
if (value)
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
*buf &= ~(1 << bit++);
|
||||
else *buf &= ~(1 << bit++);
|
||||
}
|
||||
/* Update @start_bit to the new position. */
|
||||
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_buf = NULL;
|
||||
bit = count & 7;
|
||||
do {
|
||||
do
|
||||
{
|
||||
/* If there is a last partial byte... */
|
||||
if (count > 0 && bit) {
|
||||
if (count > 0 && bit)
|
||||
{
|
||||
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||
if (!lastbyte_pos) {
|
||||
if (!lastbyte_pos)
|
||||
{
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error("Lastbyte is zero. Leaving "
|
||||
"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;
|
||||
}
|
||||
/* and it is in the currently loaded bitmap window... */
|
||||
if (lastbyte_pos <= bufsize) {
|
||||
if (lastbyte_pos <= bufsize)
|
||||
{
|
||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||
|
||||
/* read the byte in... */
|
||||
br = ntfs_attr_pread(na, (start_bit + count) >>
|
||||
3, 1, lastbyte_buf);
|
||||
if (br != 1) {
|
||||
br = ntfs_attr_pread(na, (start_bit + count) >> 3, 1, lastbyte_buf);
|
||||
if (br != 1)
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
if (br >= 0) errno = EIO;
|
||||
ntfs_log_perror("Reading of last byte "
|
||||
"failed (%lld). Leaving inconsistent "
|
||||
"metadata", (long long)br);
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set/clear the appropriate bits in it. */
|
||||
while (bit && count--) {
|
||||
while (bit && count--)
|
||||
{
|
||||
if (value)
|
||||
*lastbyte_buf |= 1 << --bit;
|
||||
else
|
||||
*lastbyte_buf &= ~(1 << --bit);
|
||||
else *lastbyte_buf &= ~(1 << --bit);
|
||||
}
|
||||
/* We don't want to come back here... */
|
||||
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. */
|
||||
tmp = (start_bit >> 3) - firstbyte;
|
||||
br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
|
||||
if (br != bufsize) {
|
||||
if (br != bufsize)
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
if (br >= 0) errno = EIO;
|
||||
ntfs_log_perror("Failed to write buffer to bitmap "
|
||||
"(%lld != %lld). Leaving inconsistent metadata",
|
||||
(long long)br, (long long)bufsize);
|
||||
@ -224,7 +220,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
|
||||
/* Update counters. */
|
||||
tmp = (bufsize - firstbyte - lastbyte) << 3;
|
||||
if (firstbyte) {
|
||||
if (firstbyte)
|
||||
{
|
||||
firstbyte = 0;
|
||||
/*
|
||||
* 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;
|
||||
count -= tmp;
|
||||
if (bufsize > (tmp = (count + 7) >> 3))
|
||||
bufsize = tmp;
|
||||
if (bufsize > (tmp = (count + 7) >> 3)) bufsize = tmp;
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
if (lastbyte && count != 0)
|
||||
{
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_error("Last buffer but count is not zero "
|
||||
"(%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;
|
||||
|
||||
free_err_out:
|
||||
free(buf);
|
||||
free_err_out: free(buf);
|
||||
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("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");
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking bytes per sector.\n");
|
||||
if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 ||
|
||||
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
|
||||
if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 || le16_to_cpu(b->bpb.bytes_per_sector) > 4096)
|
||||
{
|
||||
ntfs_log_error("Unexpected bytes per sector value (%d).\n",
|
||||
le16_to_cpu(b->bpb.bytes_per_sector));
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking sectors per cluster.\n");
|
||||
switch (b->bpb.sectors_per_cluster) {
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||
switch (b->bpb.sectors_per_cluster)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
|
||||
@ -89,20 +98,17 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking cluster size.\n");
|
||||
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) *
|
||||
b->bpb.sectors_per_cluster;
|
||||
if (i > 65536) {
|
||||
i = (u32) le16_to_cpu(b->bpb.bytes_per_sector) * b->bpb.sectors_per_cluster;
|
||||
if (i > 65536)
|
||||
{
|
||||
ntfs_log_error("Unexpected cluster size (%d).\n", i);
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking reserved fields are zero.\n");
|
||||
if (le16_to_cpu(b->bpb.reserved_sectors) ||
|
||||
le16_to_cpu(b->bpb.root_entries) ||
|
||||
le16_to_cpu(b->bpb.sectors) ||
|
||||
le16_to_cpu(b->bpb.sectors_per_fat) ||
|
||||
le32_to_cpu(b->bpb.large_sectors) ||
|
||||
b->bpb.fats) {
|
||||
if (le16_to_cpu(b->bpb.reserved_sectors) || le16_to_cpu(b->bpb.root_entries) || le16_to_cpu(b->bpb.sectors)
|
||||
|| le16_to_cpu(b->bpb.sectors_per_fat) || le32_to_cpu(b->bpb.large_sectors) || b->bpb.fats)
|
||||
{
|
||||
ntfs_log_error("Reserved fields aren't zero "
|
||||
"(%d, %d, %d, %d, %d, %d).\n",
|
||||
le16_to_cpu(b->bpb.reserved_sectors),
|
||||
@ -115,10 +121,17 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking clusters per mft record.\n");
|
||||
if ((u8)b->clusters_per_mft_record < 0xe1 ||
|
||||
(u8)b->clusters_per_mft_record > 0xf7) {
|
||||
switch (b->clusters_per_mft_record) {
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
if ((u8) b->clusters_per_mft_record < 0xe1 || (u8) b->clusters_per_mft_record > 0xf7)
|
||||
{
|
||||
switch (b->clusters_per_mft_record)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 0x10:
|
||||
case 0x20:
|
||||
case 0x40:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unexpected clusters per mft record "
|
||||
@ -128,10 +141,17 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
}
|
||||
|
||||
ntfs_log_debug("Checking clusters per index block.\n");
|
||||
if ((u8)b->clusters_per_index_record < 0xe1 ||
|
||||
(u8)b->clusters_per_index_record > 0xf7) {
|
||||
switch (b->clusters_per_index_record) {
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
if ((u8) b->clusters_per_index_record < 0xe1 || (u8) b->clusters_per_index_record > 0xf7)
|
||||
{
|
||||
switch (b->clusters_per_index_record)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 0x10:
|
||||
case 0x20:
|
||||
case 0x40:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unexpected clusters per index record "
|
||||
@ -147,12 +167,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
ntfs_log_debug("Bootsector check completed successfully.\n");
|
||||
|
||||
ret = TRUE;
|
||||
not_ntfs:
|
||||
return ret;
|
||||
not_ntfs: return ret;
|
||||
}
|
||||
|
||||
static const char *last_sector_error =
|
||||
"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n"
|
||||
static const char *last_sector_error = "HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n"
|
||||
" or it was not setup correctly (e.g. by not using mdadm --build ...),\n"
|
||||
" or a wrong device is tried to be mounted,\n"
|
||||
" or the partition table is corrupt (partition is smaller than NTFS),\n"
|
||||
@ -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;
|
||||
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."
|
||||
"\n", sectors_per_cluster);
|
||||
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);
|
||||
ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
|
||||
if (!sectors) {
|
||||
if (!sectors)
|
||||
{
|
||||
ntfs_log_error("Volume size is set to zero.\n");
|
||||
return -1;
|
||||
}
|
||||
if (vol->dev->d_ops->seek(vol->dev,
|
||||
(sectors - 1) << vol->sector_size_bits,
|
||||
SEEK_SET) == -1) {
|
||||
if (vol->dev->d_ops->seek(vol->dev, (sectors - 1) << vol->sector_size_bits, SEEK_SET) == -1)
|
||||
{
|
||||
ntfs_log_perror("Failed to read last sector (%lld)",
|
||||
(long long)sectors);
|
||||
ntfs_log_error("%s", last_sector_error);
|
||||
@ -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);
|
||||
ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
|
||||
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
||||
if (vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
||||
if (vol->mft_lcn > vol->nr_clusters || vol->mftmirr_lcn > vol->nr_clusters)
|
||||
{
|
||||
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||
"greater than the number of clusters (%lld).\n",
|
||||
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
|
||||
@ -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;
|
||||
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",
|
||||
vol->cluster_size);
|
||||
return -1;
|
||||
@ -248,9 +268,9 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
*/
|
||||
if (c < 0)
|
||||
vol->mft_record_size = 1 << -c;
|
||||
else
|
||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
||||
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
|
||||
else vol->mft_record_size = c << vol->cluster_size_bits;
|
||||
if (vol->mft_record_size & (vol->mft_record_size - 1))
|
||||
{
|
||||
ntfs_log_error("mft_record_size (%d) is not a power of 2.\n",
|
||||
vol->mft_record_size);
|
||||
return -1;
|
||||
@ -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);
|
||||
if (c < 0)
|
||||
vol->indx_record_size = 1 << -c;
|
||||
else
|
||||
vol->indx_record_size = c << vol->cluster_size_bits;
|
||||
else vol->indx_record_size = c << vol->cluster_size_bits;
|
||||
vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
|
||||
ntfs_log_debug("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
|
||||
ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
|
||||
@ -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)
|
||||
vol->mftmirr_size = 4;
|
||||
else
|
||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||
else vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -60,34 +60,39 @@
|
||||
* Do not call when a record has been modified (with no key change)
|
||||
*/
|
||||
|
||||
static void inserthashindex(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *current)
|
||||
static void inserthashindex(struct CACHE_HEADER *cache, struct CACHED_GENERIC *current)
|
||||
{
|
||||
int h;
|
||||
struct HASH_ENTRY *link;
|
||||
struct HASH_ENTRY *first;
|
||||
|
||||
if (cache->dohash) {
|
||||
if (cache->dohash)
|
||||
{
|
||||
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 */
|
||||
link = cache->free_hash;
|
||||
if (link) {
|
||||
if (link)
|
||||
{
|
||||
cache->free_hash = link->next;
|
||||
first = cache->first_hash[h];
|
||||
if (first)
|
||||
link->next = first;
|
||||
else
|
||||
link->next = NULL;
|
||||
else link->next = NULL;
|
||||
link->entry = current;
|
||||
cache->first_hash[h] = link;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error("No more hash entries,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
cache->dohash = (cache_hash) NULL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error("Illegal hash value,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
@ -100,35 +105,41 @@ static void inserthashindex(struct CACHE_HEADER *cache,
|
||||
* Drop a hash index when a record is about to be deleted
|
||||
*/
|
||||
|
||||
static void drophashindex(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *current, int hash)
|
||||
static void drophashindex(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *current, int hash)
|
||||
{
|
||||
struct HASH_ENTRY *link;
|
||||
struct HASH_ENTRY *previous;
|
||||
|
||||
if (cache->dohash) {
|
||||
if ((hash >= 0) && (hash < cache->max_hash)) {
|
||||
if (cache->dohash)
|
||||
{
|
||||
if ((hash >= 0) && (hash < cache->max_hash))
|
||||
{
|
||||
/* find the link and unlink */
|
||||
link = cache->first_hash[hash];
|
||||
previous = (struct HASH_ENTRY*) NULL;
|
||||
while (link && (link->entry != current)) {
|
||||
while (link && (link->entry != current))
|
||||
{
|
||||
previous = link;
|
||||
link = link->next;
|
||||
}
|
||||
if (link) {
|
||||
if (link)
|
||||
{
|
||||
if (previous)
|
||||
previous->next = link->next;
|
||||
else
|
||||
cache->first_hash[hash] = link->next;
|
||||
else cache->first_hash[hash] = link->next;
|
||||
link->next = cache->free_hash;
|
||||
cache->free_hash = link;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error("Bad hash list,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
cache->dohash = (cache_hash) NULL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error("Illegal hash value,"
|
||||
" cache %s hashing dropped\n",
|
||||
cache->name);
|
||||
@ -144,8 +155,8 @@ static void drophashindex(struct CACHE_HEADER *cache,
|
||||
* The returned entry may be modified, but not freed
|
||||
*/
|
||||
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted, cache_compare compare)
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *wanted,
|
||||
cache_compare compare)
|
||||
{
|
||||
struct CACHED_GENERIC *current;
|
||||
struct CACHED_GENERIC *previous;
|
||||
@ -153,8 +164,10 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
int h;
|
||||
|
||||
current = (struct CACHED_GENERIC*) NULL;
|
||||
if (cache) {
|
||||
if (cache->dohash) {
|
||||
if (cache)
|
||||
{
|
||||
if (cache->dohash)
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* locate the entry if present
|
||||
@ -163,38 +176,36 @@ struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
link = cache->first_hash[h];
|
||||
while (link && compare(link->entry, wanted))
|
||||
link = link->next;
|
||||
if (link)
|
||||
current = link->entry;
|
||||
if (link) current = link->entry;
|
||||
}
|
||||
if (!cache->dohash) {
|
||||
if (!cache->dohash)
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list if no hash table
|
||||
* or if hashing has just failed
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
while (current
|
||||
&& compare(current, wanted)) {
|
||||
while (current && compare(current, wanted))
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
if (current) {
|
||||
if (current)
|
||||
{
|
||||
previous = current->previous;
|
||||
cache->hits++;
|
||||
if (previous) {
|
||||
if (previous)
|
||||
{
|
||||
/*
|
||||
* found and not at head of list, unlink from current
|
||||
* position and relink as head of list
|
||||
*/
|
||||
previous->next = current->next;
|
||||
if (current->next)
|
||||
current->next->previous
|
||||
= current->previous;
|
||||
else
|
||||
cache->oldest_entry
|
||||
= current->previous;
|
||||
current->next->previous = current->previous;
|
||||
else cache->oldest_entry = current->previous;
|
||||
current->next = cache->most_recent_entry;
|
||||
current->previous
|
||||
= (struct CACHED_GENERIC*)NULL;
|
||||
current->previous = (struct CACHED_GENERIC*) NULL;
|
||||
cache->most_recent_entry->previous = 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
|
||||
*/
|
||||
|
||||
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *item,
|
||||
cache_compare compare)
|
||||
{
|
||||
struct CACHED_GENERIC *current;
|
||||
@ -219,8 +229,10 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
int h;
|
||||
|
||||
current = (struct CACHED_GENERIC*) NULL;
|
||||
if (cache) {
|
||||
if (cache->dohash) {
|
||||
if (cache)
|
||||
{
|
||||
if (cache->dohash)
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* 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];
|
||||
while (link && compare(link->entry, item))
|
||||
link = link->next;
|
||||
if (link) {
|
||||
if (link)
|
||||
{
|
||||
current = link->entry;
|
||||
}
|
||||
}
|
||||
if (!cache->dohash) {
|
||||
if (!cache->dohash)
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list to locate the end,
|
||||
* and find out whether the entry is already in list
|
||||
@ -241,13 +255,14 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
* kept.
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
while (current
|
||||
&& compare(current, item)) {
|
||||
while (current && compare(current, item))
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!current) {
|
||||
if (!current)
|
||||
{
|
||||
/*
|
||||
* Not in list, get a free entry or reuse the
|
||||
* last entry, and relink as head of list
|
||||
@ -256,54 +271,53 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
* an entry is reused.
|
||||
*/
|
||||
|
||||
if (cache->free_entry) {
|
||||
if (cache->free_entry)
|
||||
{
|
||||
current = cache->free_entry;
|
||||
cache->free_entry = cache->free_entry->next;
|
||||
if (item->varsize) {
|
||||
current->variable = ntfs_malloc(
|
||||
item->varsize);
|
||||
} else
|
||||
current->variable = (void*)NULL;
|
||||
if (item->varsize)
|
||||
{
|
||||
current->variable = ntfs_malloc(item->varsize);
|
||||
}
|
||||
else current->variable = (void*) NULL;
|
||||
current->varsize = item->varsize;
|
||||
if (!cache->oldest_entry)
|
||||
cache->oldest_entry = current;
|
||||
} else {
|
||||
if (!cache->oldest_entry) cache->oldest_entry = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reusing the oldest entry */
|
||||
current = cache->oldest_entry;
|
||||
before = current->previous;
|
||||
before->next = (struct CACHED_GENERIC*) NULL;
|
||||
if (cache->dohash)
|
||||
drophashindex(cache,current,
|
||||
cache->dohash(current));
|
||||
if (cache->dofree)
|
||||
cache->dofree(current);
|
||||
if (cache->dohash) drophashindex(cache, current, cache->dohash(current));
|
||||
if (cache->dofree) cache->dofree(current);
|
||||
cache->oldest_entry = current->previous;
|
||||
if (item->varsize) {
|
||||
if (item->varsize)
|
||||
{
|
||||
if (current->varsize)
|
||||
current->variable = realloc(
|
||||
current->variable,
|
||||
item->varsize);
|
||||
current->variable = realloc(current->variable, item->varsize);
|
||||
else current->variable = ntfs_malloc(item->varsize);
|
||||
}
|
||||
else
|
||||
current->variable = ntfs_malloc(
|
||||
item->varsize);
|
||||
} else {
|
||||
if (current->varsize)
|
||||
free(current->variable);
|
||||
{
|
||||
if (current->varsize) free(current->variable);
|
||||
current->variable = (void*) NULL;
|
||||
}
|
||||
current->varsize = item->varsize;
|
||||
}
|
||||
current->next = cache->most_recent_entry;
|
||||
current->previous = (struct CACHED_GENERIC*) NULL;
|
||||
if (cache->most_recent_entry)
|
||||
cache->most_recent_entry->previous = current;
|
||||
if (cache->most_recent_entry) cache->most_recent_entry->previous = current;
|
||||
cache->most_recent_entry = current;
|
||||
memcpy(current->fixed, item->fixed, cache->fixed_size);
|
||||
if (item->varsize) {
|
||||
if (current->variable) {
|
||||
memcpy(current->variable,
|
||||
item->variable, item->varsize);
|
||||
} else {
|
||||
if (item->varsize)
|
||||
{
|
||||
if (current->variable)
|
||||
{
|
||||
memcpy(current->variable, item->variable, item->varsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* no more memory for variable part
|
||||
* recycle entry in free list
|
||||
@ -314,12 +328,13 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
cache->free_entry = current;
|
||||
current = (struct CACHED_GENERIC*) NULL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
current->variable = (void*) NULL;
|
||||
current->varsize = 0;
|
||||
}
|
||||
if (cache->dohash && current)
|
||||
inserthashindex(cache,current);
|
||||
if (cache->dohash && current) inserthashindex(cache, current);
|
||||
}
|
||||
cache->writes++;
|
||||
}
|
||||
@ -332,33 +347,27 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
* A specific function may be called for entry deletion
|
||||
*/
|
||||
|
||||
static void do_invalidate(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *current, int flags)
|
||||
static void do_invalidate(struct CACHE_HEADER *cache, struct CACHED_GENERIC *current, int flags)
|
||||
{
|
||||
struct CACHED_GENERIC *previous;
|
||||
|
||||
previous = current->previous;
|
||||
if ((flags & CACHE_FREE) && cache->dofree)
|
||||
cache->dofree(current);
|
||||
if ((flags & CACHE_FREE) && cache->dofree) cache->dofree(current);
|
||||
/*
|
||||
* Relink into free list
|
||||
*/
|
||||
if (current->next)
|
||||
current->next->previous = current->previous;
|
||||
else
|
||||
cache->oldest_entry = current->previous;
|
||||
else cache->oldest_entry = current->previous;
|
||||
if (previous)
|
||||
previous->next = current->next;
|
||||
else
|
||||
cache->most_recent_entry = current->next;
|
||||
else cache->most_recent_entry = current->next;
|
||||
current->next = cache->free_entry;
|
||||
cache->free_entry = current;
|
||||
if (current->variable)
|
||||
free(current->variable);
|
||||
if (current->variable) free(current->variable);
|
||||
current->varsize = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Invalidate entries in cache
|
||||
*
|
||||
@ -371,8 +380,7 @@ static void do_invalidate(struct CACHE_HEADER *cache,
|
||||
* supposed to be found.
|
||||
*/
|
||||
|
||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item, cache_compare compare,
|
||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *item, cache_compare compare,
|
||||
int flags)
|
||||
{
|
||||
struct CACHED_GENERIC *current;
|
||||
@ -384,45 +392,52 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
|
||||
current = (struct CACHED_GENERIC*) NULL;
|
||||
count = 0;
|
||||
if (cache) {
|
||||
if (!(flags & CACHE_NOHASH) && cache->dohash) {
|
||||
if (cache)
|
||||
{
|
||||
if (!(flags & CACHE_NOHASH) && cache->dohash)
|
||||
{
|
||||
/*
|
||||
* When possible, use the hash table to
|
||||
* find out whether the entry if present
|
||||
*/
|
||||
h = cache->dohash(item);
|
||||
link = cache->first_hash[h];
|
||||
while (link) {
|
||||
while (link)
|
||||
{
|
||||
if (compare(link->entry, item))
|
||||
link = link->next;
|
||||
else {
|
||||
else
|
||||
{
|
||||
current = link->entry;
|
||||
link = link->next;
|
||||
if (current) {
|
||||
if (current)
|
||||
{
|
||||
drophashindex(cache, current, h);
|
||||
do_invalidate(cache,
|
||||
current,flags);
|
||||
do_invalidate(cache, current, flags);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & CACHE_NOHASH) || !cache->dohash) {
|
||||
if ((flags & CACHE_NOHASH) || !cache->dohash)
|
||||
{
|
||||
/*
|
||||
* Search sequentially in LRU list
|
||||
*/
|
||||
current = cache->most_recent_entry;
|
||||
previous = (struct CACHED_GENERIC*) NULL;
|
||||
while (current) {
|
||||
if (!compare(current, item)) {
|
||||
while (current)
|
||||
{
|
||||
if (!compare(current, item))
|
||||
{
|
||||
next = current->next;
|
||||
if (cache->dohash)
|
||||
drophashindex(cache,current,
|
||||
cache->dohash(current));
|
||||
if (cache->dohash) drophashindex(cache, current, cache->dohash(current));
|
||||
do_invalidate(cache, current, flags);
|
||||
current = next;
|
||||
count++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = current;
|
||||
current = current->next;
|
||||
}
|
||||
@ -432,15 +447,14 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
return (count);
|
||||
}
|
||||
|
||||
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags)
|
||||
int ntfs_remove_cache(struct CACHE_HEADER *cache, struct CACHED_GENERIC *item, int flags)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
if (cache) {
|
||||
if (cache->dohash)
|
||||
drophashindex(cache,item,cache->dohash(item));
|
||||
if (cache)
|
||||
{
|
||||
if (cache->dohash) drophashindex(cache, item, cache->dohash(item));
|
||||
do_invalidate(cache, item, flags);
|
||||
count++;
|
||||
}
|
||||
@ -455,12 +469,12 @@ static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
||||
{
|
||||
struct CACHED_GENERIC *entry;
|
||||
|
||||
if (cache) {
|
||||
for (entry=cache->most_recent_entry; entry; entry=entry->next) {
|
||||
if (cache->dofree)
|
||||
cache->dofree(entry);
|
||||
if (entry->variable)
|
||||
free(entry->variable);
|
||||
if (cache)
|
||||
{
|
||||
for (entry = cache->most_recent_entry; entry; entry = entry->next)
|
||||
{
|
||||
if (cache->dofree) cache->dofree(entry);
|
||||
if (entry->variable) free(entry->variable);
|
||||
}
|
||||
free(cache);
|
||||
}
|
||||
@ -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
|
||||
*/
|
||||
|
||||
static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
cache_free dofree, cache_hash dohash,
|
||||
int full_item_size,
|
||||
int item_count, int max_hash)
|
||||
static struct CACHE_HEADER *ntfs_create_cache(const char *name, cache_free dofree, cache_hash dohash,
|
||||
int full_item_size, int item_count, int max_hash)
|
||||
{
|
||||
struct CACHE_HEADER *cache;
|
||||
struct CACHED_GENERIC *pc;
|
||||
@ -487,18 +499,20 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
int i;
|
||||
|
||||
size = sizeof(struct CACHE_HEADER) + item_count * full_item_size;
|
||||
if (max_hash)
|
||||
size += item_count*sizeof(struct HASH_ENTRY)
|
||||
+ max_hash*sizeof(struct HASH_ENTRY*);
|
||||
if (max_hash) size += item_count * sizeof(struct HASH_ENTRY) + max_hash * sizeof(struct HASH_ENTRY*);
|
||||
cache = (struct CACHE_HEADER*) ntfs_malloc(size);
|
||||
if (cache) {
|
||||
if (cache)
|
||||
{
|
||||
/* header */
|
||||
cache->name = name;
|
||||
cache->dofree = dofree;
|
||||
if (dohash && max_hash) {
|
||||
if (dohash && max_hash)
|
||||
{
|
||||
cache->dohash = dohash;
|
||||
cache->max_hash = max_hash;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->dohash = (cache_hash) NULL;
|
||||
cache->max_hash = 0;
|
||||
}
|
||||
@ -511,9 +525,9 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
cache->oldest_entry = (struct CACHED_GENERIC*) NULL;
|
||||
cache->free_entry = &cache->entry[0];
|
||||
pc = &cache->entry[0];
|
||||
for (i=0; i<(item_count - 1); i++) {
|
||||
qc = (struct CACHED_GENERIC*)((char*)pc
|
||||
+ full_item_size);
|
||||
for (i = 0; i < (item_count - 1); i++)
|
||||
{
|
||||
qc = (struct CACHED_GENERIC*) ((char*) pc + full_item_size);
|
||||
pc->next = qc;
|
||||
pc->variable = (void*) NULL;
|
||||
pc->varsize = 0;
|
||||
@ -524,17 +538,20 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
pc->variable = (void*) NULL;
|
||||
pc->varsize = 0;
|
||||
|
||||
if (max_hash) {
|
||||
if (max_hash)
|
||||
{
|
||||
/* chain the hash entries */
|
||||
ph = (struct HASH_ENTRY*) (((char*) pc) + full_item_size);
|
||||
cache->free_hash = ph;
|
||||
for (i=0; i<(item_count - 1); i++) {
|
||||
for (i = 0; i < (item_count - 1); i++)
|
||||
{
|
||||
qh = &ph[1];
|
||||
ph->next = qh;
|
||||
ph = qh;
|
||||
}
|
||||
/* special for the last entry */
|
||||
if (item_count) {
|
||||
if (item_count)
|
||||
{
|
||||
ph->next = (struct HASH_ENTRY*) NULL;
|
||||
}
|
||||
/* create and initialize the hash indexes */
|
||||
@ -542,7 +559,9 @@ static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||
cache->first_hash = px;
|
||||
for (i = 0; i < max_hash; i++)
|
||||
px[i] = (struct HASH_ENTRY*) NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->free_hash = (struct HASH_ENTRY*) NULL;
|
||||
cache->first_hash = (struct HASH_ENTRY**) NULL;
|
||||
}
|
||||
@ -561,29 +580,24 @@ void ntfs_create_lru_caches(ntfs_volume *vol)
|
||||
{
|
||||
#if CACHE_INODE_SIZE
|
||||
/* inode cache */
|
||||
vol->xinode_cache = ntfs_create_cache("inode",(cache_free)NULL,
|
||||
ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
|
||||
vol->xinode_cache = ntfs_create_cache("inode", (cache_free) NULL, ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
|
||||
CACHE_INODE_SIZE, 2 * CACHE_INODE_SIZE);
|
||||
#endif
|
||||
#if CACHE_NIDATA_SIZE
|
||||
/* idata cache */
|
||||
vol->nidata_cache = ntfs_create_cache("nidata",
|
||||
ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
|
||||
sizeof(struct CACHED_NIDATA),
|
||||
CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE);
|
||||
vol->nidata_cache = ntfs_create_cache("nidata", ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
|
||||
sizeof(struct CACHED_NIDATA), CACHE_NIDATA_SIZE, 2 * CACHE_NIDATA_SIZE);
|
||||
#endif
|
||||
#if CACHE_LOOKUP_SIZE
|
||||
/* lookup cache */
|
||||
vol->lookup_cache = ntfs_create_cache("lookup",
|
||||
(cache_free)NULL, ntfs_dir_lookup_hash,
|
||||
sizeof(struct CACHED_LOOKUP),
|
||||
CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE);
|
||||
vol->lookup_cache = ntfs_create_cache("lookup", (cache_free) NULL, ntfs_dir_lookup_hash,
|
||||
sizeof(struct CACHED_LOOKUP), CACHE_LOOKUP_SIZE, 2 * CACHE_LOOKUP_SIZE);
|
||||
#endif
|
||||
vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL,
|
||||
(cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
|
||||
vol->securid_cache = ntfs_create_cache("securid", (cache_free) NULL, (cache_hash) NULL,
|
||||
sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
|
||||
#if CACHE_LEGACY_SIZE
|
||||
vol->legacy_cache = ntfs_create_cache("legacy",(cache_free)NULL,
|
||||
(cache_hash)NULL, sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0);
|
||||
vol->legacy_cache = ntfs_create_cache("legacy", (cache_free) NULL, (cache_hash) NULL,
|
||||
sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -24,19 +24,22 @@
|
||||
|
||||
#include "volume.h"
|
||||
|
||||
struct CACHED_GENERIC {
|
||||
struct CACHED_GENERIC
|
||||
{
|
||||
struct CACHED_GENERIC *next;
|
||||
struct CACHED_GENERIC *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
union {
|
||||
union
|
||||
{
|
||||
/* force alignment for pointers and u64 */
|
||||
u64 u64align;
|
||||
void *ptralign;
|
||||
} fixed[0];
|
||||
};
|
||||
|
||||
struct CACHED_INODE {
|
||||
struct CACHED_INODE
|
||||
{
|
||||
struct CACHED_INODE *next;
|
||||
struct CACHED_INODE *previous;
|
||||
const char *pathname;
|
||||
@ -45,7 +48,8 @@ struct CACHED_INODE {
|
||||
u64 inum;
|
||||
};
|
||||
|
||||
struct CACHED_NIDATA {
|
||||
struct CACHED_NIDATA
|
||||
{
|
||||
struct CACHED_NIDATA *next;
|
||||
struct CACHED_NIDATA *previous;
|
||||
const char *pathname; /* not used */
|
||||
@ -55,7 +59,8 @@ struct CACHED_NIDATA {
|
||||
ntfs_inode *ni;
|
||||
};
|
||||
|
||||
struct CACHED_LOOKUP {
|
||||
struct CACHED_LOOKUP
|
||||
{
|
||||
struct CACHED_LOOKUP *next;
|
||||
struct CACHED_LOOKUP *previous;
|
||||
const char *name;
|
||||
@ -65,22 +70,23 @@ struct CACHED_LOOKUP {
|
||||
u64 inum;
|
||||
};
|
||||
|
||||
enum {
|
||||
CACHE_FREE = 1,
|
||||
CACHE_NOHASH = 2
|
||||
enum
|
||||
{
|
||||
CACHE_FREE = 1, CACHE_NOHASH = 2
|
||||
};
|
||||
|
||||
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
|
||||
const struct CACHED_GENERIC *item);
|
||||
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached, const struct CACHED_GENERIC *item);
|
||||
typedef void (*cache_free)(const struct CACHED_GENERIC *cached);
|
||||
typedef int (*cache_hash)(const struct CACHED_GENERIC *cached);
|
||||
|
||||
struct HASH_ENTRY {
|
||||
struct HASH_ENTRY
|
||||
{
|
||||
struct HASH_ENTRY *next;
|
||||
struct CACHED_GENERIC *entry;
|
||||
};
|
||||
|
||||
struct CACHE_HEADER {
|
||||
struct CACHE_HEADER
|
||||
{
|
||||
const char *name;
|
||||
struct CACHED_GENERIC *most_recent_entry;
|
||||
struct CACHED_GENERIC *oldest_entry;
|
||||
@ -100,17 +106,13 @@ struct CACHE_HEADER {
|
||||
/* cast to generic, avoiding gcc warnings */
|
||||
#define GENERIC(pstr) ((const struct CACHED_GENERIC*)(const void*)(pstr))
|
||||
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted,
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *wanted,
|
||||
cache_compare compare);
|
||||
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *item,
|
||||
cache_compare compare);
|
||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare, int flags);
|
||||
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags);
|
||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *item, cache_compare compare,
|
||||
int flags);
|
||||
int ntfs_remove_cache(struct CACHE_HEADER *cache, struct CACHED_GENERIC *item, int flags);
|
||||
|
||||
void ntfs_create_lru_caches(ntfs_volume *vol);
|
||||
void ntfs_free_lru_caches(ntfs_volume *vol);
|
||||
|
@ -45,23 +45,28 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize) {
|
||||
NTFS_CACHE* _NTFS_cache_constructor(unsigned int numberOfPages, unsigned int sectorsPerPage,
|
||||
const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize)
|
||||
{
|
||||
NTFS_CACHE* cache;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if (numberOfPages == 0 || sectorsPerPage == 0) return NULL;
|
||||
|
||||
if (numberOfPages < 4) {
|
||||
if (numberOfPages < 4)
|
||||
{
|
||||
numberOfPages = 4;
|
||||
}
|
||||
|
||||
if (sectorsPerPage < 32) {
|
||||
if (sectorsPerPage < 32)
|
||||
{
|
||||
sectorsPerPage = 32;
|
||||
}
|
||||
|
||||
cache = (NTFS_CACHE*) ntfs_alloc(sizeof(NTFS_CACHE));
|
||||
if (cache == NULL) {
|
||||
if (cache == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -71,14 +76,15 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
cache->sectorSize = sectorSize;
|
||||
|
||||
|
||||
cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc(sizeof(NTFS_CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL) {
|
||||
if (cacheEntries == NULL)
|
||||
{
|
||||
ntfs_free(cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numberOfPages; i++) {
|
||||
for (i = 0; i < numberOfPages; i++)
|
||||
{
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
@ -91,7 +97,8 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
void _NTFS_cache_destructor(NTFS_CACHE* cache)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (cache == NULL) return;
|
||||
@ -100,7 +107,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
_NTFS_cache_flush(cache);
|
||||
|
||||
// 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);
|
||||
@ -109,7 +117,8 @@ void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
static u32 accessTime()
|
||||
{
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
@ -125,21 +134,26 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
||||
for (i = 0; i < numberOfPages; i++)
|
||||
{
|
||||
if (sector >= cacheEntries[i].sector && sector < (cacheEntries[i].sector + cacheEntries[i].count))
|
||||
{
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &(cacheEntries[i]);
|
||||
}
|
||||
|
||||
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;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||
if(!cache->disc->writeSectors(cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||
if (foundFree == false && cacheEntries[oldUsed].dirty == true)
|
||||
{
|
||||
if (!cache->disc->writeSectors(cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count,
|
||||
cacheEntries[oldUsed].cache)) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
sector = (sector / sectorsPerPage) * sectorsPerPage; // align base sector to page size
|
||||
@ -155,7 +169,8 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
return &(cacheEntries[oldUsed]);
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count)
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
@ -163,16 +178,22 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, s
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
for (i = 0; i < numberOfPages; i++)
|
||||
{
|
||||
if (cacheEntries[i].sector != CACHE_FREE)
|
||||
{
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
if (sector > cacheEntries[i].sector)
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
if (intersect && (cacheEntries[i].sector < lowest))
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
@ -189,7 +210,8 @@ bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,voi
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
|
||||
while(numSectors>0) {
|
||||
while (numSectors > 0)
|
||||
{
|
||||
entry = _NTFS_cache_getPage(cache, sector);
|
||||
if (entry == NULL) return false;
|
||||
|
||||
@ -227,15 +249,25 @@ bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t secto
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
bool _NTFS_cache_readLittleEndianValue(NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset,
|
||||
int num_bytes)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if (!_NTFS_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||
|
||||
switch(num_bytes) {
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16(buf,0); break;
|
||||
case 4: *value = u8array_to_u32(buf,0); break;
|
||||
default: return false;
|
||||
switch (num_bytes)
|
||||
{
|
||||
case 1:
|
||||
*value = buf[0];
|
||||
break;
|
||||
case 2:
|
||||
*value = u8array_to_u16(buf, 0);
|
||||
break;
|
||||
case 4:
|
||||
*value = u8array_to_u32(buf, 0);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -244,7 +276,8 @@ bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_
|
||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _NTFS_cache_writePartialSector(NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset,
|
||||
size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
@ -261,14 +294,24 @@ bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
bool _NTFS_cache_writeLittleEndianValue(NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset,
|
||||
int size)
|
||||
{
|
||||
uint8_t buf[4] = { 0, 0, 0, 0 };
|
||||
|
||||
switch(size) {
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array(buf, 0, value); break;
|
||||
case 4: u32_to_u8array(buf, 0, value); break;
|
||||
default: return false;
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
buf[0] = value;
|
||||
break;
|
||||
case 2:
|
||||
u16_to_u8array(buf, 0, value);
|
||||
break;
|
||||
case 4:
|
||||
u32_to_u8array(buf, 0, value);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return _NTFS_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
@ -278,7 +321,8 @@ bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value
|
||||
Writes some data to a cache page, zeroing out the page first
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
bool _NTFS_cache_eraseWritePartialSector(NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset,
|
||||
size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
@ -307,9 +351,11 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t 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;
|
||||
|
||||
@ -332,7 +378,9 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->disc->writeSectors(sector, numSectors, src);
|
||||
numSectors = 0;
|
||||
}
|
||||
@ -343,13 +391,18 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
bool _NTFS_cache_flush(NTFS_CACHE* cache)
|
||||
{
|
||||
unsigned int i;
|
||||
if (cache == NULL) return true;
|
||||
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
if (cache->cacheEntries[i].dirty) {
|
||||
if (!cache->disc->writeSectors (cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||
for (i = 0; i < cache->numberOfPages; i++)
|
||||
{
|
||||
if (cache->cacheEntries[i].dirty)
|
||||
{
|
||||
if (!cache->disc->writeSectors(cache->cacheEntries[i].sector, cache->cacheEntries[i].count,
|
||||
cache->cacheEntries[i].cache))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -359,13 +412,14 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
||||
void _NTFS_cache_invalidate(NTFS_CACHE* cache)
|
||||
{
|
||||
unsigned int i;
|
||||
if(cache==NULL)
|
||||
return;
|
||||
if (cache == NULL) return;
|
||||
|
||||
_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].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
|
@ -46,7 +46,8 @@
|
||||
#include <ogc/disc_io.h>
|
||||
#include <gccore.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
u64 last_access;
|
||||
@ -54,7 +55,8 @@ typedef struct {
|
||||
u8* cache;
|
||||
} NTFS_CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
@ -127,9 +129,9 @@ Clear out the contents of the NTFS_CACHE without writing any dirty sectors first
|
||||
*/
|
||||
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);
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
||||
|
@ -52,19 +52,18 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)), const void *data1, const int data1_len, const void *data2,
|
||||
const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
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)
|
||||
rc = -1;
|
||||
else
|
||||
rc = 1;
|
||||
else rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
@ -82,15 +81,15 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)), const void *data1, const int data1_len, const void *data2,
|
||||
const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
|
||||
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");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
@ -98,11 +97,11 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
d2 = le32_to_cpup(data2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if (d1 == d2)
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
else rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", 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
|
||||
*/
|
||||
|
||||
static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)), const void *data1, const int data1_len, const void *data2,
|
||||
const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
int len;
|
||||
@ -124,14 +122,16 @@ static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
||||
u32 d1, d2;
|
||||
|
||||
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");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = (const le32*) data1;
|
||||
p2 = (const le32*) data2;
|
||||
len = data1_len;
|
||||
do {
|
||||
do
|
||||
{
|
||||
d1 = le32_to_cpup(p1);
|
||||
p1++;
|
||||
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));
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if (d1 == d2)
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
else rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", 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
|
||||
*/
|
||||
static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unused)), const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
@ -171,7 +170,8 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
||||
const le32 *p1, *p2;
|
||||
|
||||
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");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
@ -181,21 +181,23 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
||||
d2 = le32_to_cpup(p2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if (d1 > d2)
|
||||
rc = 1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
p1++;
|
||||
p2++;
|
||||
d1 = le32_to_cpup(p1);
|
||||
d2 = le32_to_cpup(p2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
else
|
||||
{
|
||||
if (d1 > d2)
|
||||
rc = 1;
|
||||
else
|
||||
rc = 0;
|
||||
else rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -215,9 +217,8 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_file_name(ntfs_volume *vol,
|
||||
const void *data1, const int data1_len __attribute__((unused)),
|
||||
const void *data2, const int data2_len __attribute__((unused)))
|
||||
static int ntfs_collate_file_name(ntfs_volume *vol, const void *data1, const int data1_len __attribute__((unused)), const void *data2,
|
||||
const int data2_len __attribute__((unused)))
|
||||
{
|
||||
const FILE_NAME_ATTR *file_name_attr1;
|
||||
const FILE_NAME_ATTR *file_name_attr2;
|
||||
@ -226,12 +227,9 @@ static int ntfs_collate_file_name(ntfs_volume *vol,
|
||||
ntfs_log_trace("Entering.\n");
|
||||
file_name_attr1 = (const FILE_NAME_ATTR*) data1;
|
||||
file_name_attr2 = (const FILE_NAME_ATTR*) data2;
|
||||
rc = ntfs_names_full_collate(
|
||||
(ntfschar*)&file_name_attr1->file_name,
|
||||
file_name_attr1->file_name_length,
|
||||
(ntfschar*)&file_name_attr2->file_name,
|
||||
file_name_attr2->file_name_length,
|
||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len);
|
||||
rc = ntfs_names_full_collate((ntfschar*) &file_name_attr1->file_name, file_name_attr1->file_name_length,
|
||||
(ntfschar*) &file_name_attr2->file_name, file_name_attr2->file_name_length, CASE_SENSITIVE, vol->upcase,
|
||||
vol->upcase_len);
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
}
|
||||
@ -246,7 +244,8 @@ COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
|
||||
{
|
||||
COLLATE collate;
|
||||
|
||||
switch (cr) {
|
||||
switch (cr)
|
||||
{
|
||||
case COLLATION_BINARY:
|
||||
collate = ntfs_collate_binary;
|
||||
break;
|
||||
|
@ -39,25 +39,29 @@ int ffs(int x)
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff)) {
|
||||
if (!x) return 0;
|
||||
if (!(x & 0xffff))
|
||||
{
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (!(x & 0xff)) {
|
||||
if (!(x & 0xff))
|
||||
{
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (!(x & 0xf)) {
|
||||
if (!(x & 0xf))
|
||||
{
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (!(x & 3)) {
|
||||
if (!(x & 3))
|
||||
{
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
if (!(x & 1))
|
||||
{
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
@ -120,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>
|
||||
#endif
|
||||
|
||||
int daemon(int nochdir, int noclose) {
|
||||
int daemon(int nochdir, int noclose)
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (fork()) {
|
||||
switch (fork())
|
||||
{
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0:
|
||||
@ -132,18 +138,16 @@ int daemon(int nochdir, int noclose) {
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (setsid() == -1)
|
||||
return (-1);
|
||||
if (setsid() == -1) return (-1);
|
||||
|
||||
if (!nochdir)
|
||||
(void)chdir("/");
|
||||
if (!nochdir) (void) chdir("/");
|
||||
|
||||
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1)
|
||||
{
|
||||
(void) dup2(fd, 0);
|
||||
(void) dup2(fd, 1);
|
||||
(void) dup2(fd, 2);
|
||||
if (fd > 2)
|
||||
(void)close (fd);
|
||||
if (fd > 2) (void) close(fd);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
char *strsep(char **stringp, const char *delim) {
|
||||
char *strsep(char **stringp, const char *delim)
|
||||
{
|
||||
char *s;
|
||||
const char *spanp;
|
||||
int c, sc;
|
||||
char *tok;
|
||||
|
||||
if ((s = *stringp) == NULL)
|
||||
return (NULL);
|
||||
for (tok = s;;) {
|
||||
if ((s = *stringp) == NULL) return (NULL);
|
||||
for (tok = s;;)
|
||||
{
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
do
|
||||
{
|
||||
if ((sc = *spanp++) == c)
|
||||
{
|
||||
if (c == 0)
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
else s[-1] = 0;
|
||||
*stringp = s;
|
||||
return (tok);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,16 +26,12 @@
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
|
||||
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b);
|
||||
|
||||
extern s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *brl, s64 wpos,
|
||||
s64 offs, s64 to_write, s64 rounded,
|
||||
const void *b, int compressed_part,
|
||||
VCN *update_from);
|
||||
extern s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *brl, s64 wpos, s64 offs, s64 to_write, s64 rounded,
|
||||
const void *b, int compressed_part, VCN *update_from);
|
||||
|
||||
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl,
|
||||
s64 offs, VCN *update_from);
|
||||
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl, s64 offs, VCN *update_from);
|
||||
|
||||
#endif /* defined _NTFS_COMPRESS_H */
|
||||
|
||||
|
@ -45,20 +45,24 @@
|
||||
void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||
{
|
||||
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_unknown "};
|
||||
|
||||
ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
|
||||
if (!rl) {
|
||||
if (!rl)
|
||||
{
|
||||
ntfs_log_debug("Run list not present.\n");
|
||||
return;
|
||||
}
|
||||
ntfs_log_debug("VCN LCN Run length\n");
|
||||
do {
|
||||
do
|
||||
{
|
||||
LCN lcn = (rl + i)->lcn;
|
||||
|
||||
if (lcn < (LCN)0) {
|
||||
if (lcn < (LCN)0)
|
||||
{
|
||||
int idx = -lcn - 1;
|
||||
|
||||
if (idx > -LCN_EINVAL - 1)
|
||||
@ -67,7 +71,8 @@ void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||
(long long)rl[i].vcn, lcn_str[idx],
|
||||
(long long)rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)");
|
||||
} else
|
||||
}
|
||||
else
|
||||
ntfs_log_debug("%-16lld %-16lld %-16lld%s\n",
|
||||
(long long)rl[i].vcn, (long long)rl[i].lcn,
|
||||
(long long)rl[i].length,
|
||||
|
@ -33,7 +33,9 @@ struct _runlist_element;
|
||||
#ifdef DEBUG
|
||||
extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl);
|
||||
#else
|
||||
static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {}
|
||||
static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused)))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NTFS_BUG(msg) \
|
||||
|
@ -103,19 +103,22 @@
|
||||
* On success return a pointer to the allocated ntfs device structure and on
|
||||
* error return NULL with errno set to the error code returned by ntfs_malloc().
|
||||
*/
|
||||
struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
struct ntfs_device_operations *dops, void *priv_data)
|
||||
struct ntfs_device *ntfs_device_alloc(const char *name, const long state, struct ntfs_device_operations *dops,
|
||||
void *priv_data)
|
||||
{
|
||||
struct ntfs_device *dev;
|
||||
|
||||
if (!name) {
|
||||
if (!name)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = ntfs_malloc(sizeof(struct ntfs_device));
|
||||
if (dev) {
|
||||
if (!(dev->d_name = strdup(name))) {
|
||||
if (dev)
|
||||
{
|
||||
if (!(dev->d_name = strdup(name)))
|
||||
{
|
||||
int eo = errno;
|
||||
free(dev);
|
||||
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)
|
||||
{
|
||||
if (!dev) {
|
||||
if (!dev)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (NDevOpen(dev)) {
|
||||
if (NDevOpen(dev))
|
||||
{
|
||||
errno = EBUSY;
|
||||
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);
|
||||
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
if (!b || count < 0 || pos < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
if (!count) return 0;
|
||||
|
||||
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);
|
||||
/* If everything ok, continue. */
|
||||
if (br > 0)
|
||||
continue;
|
||||
if (br > 0) continue;
|
||||
/* If EOF or error return number of bytes read. */
|
||||
if (!br || total)
|
||||
return total;
|
||||
if (!br || total) return total;
|
||||
/* Nothing read and error, return error status. */
|
||||
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
|
||||
* to EINVAL in case of invalid arguments.
|
||||
*/
|
||||
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b)
|
||||
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const void *b)
|
||||
{
|
||||
s64 written, total, ret = -1;
|
||||
struct ntfs_device_operations *dops;
|
||||
|
||||
ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
|
||||
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
if (!b || count < 0 || pos < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
if (NDevReadOnly(dev)) {
|
||||
if (!count) return 0;
|
||||
if (NDevReadOnly(dev))
|
||||
{
|
||||
errno = EROFS;
|
||||
goto out;
|
||||
}
|
||||
@ -245,24 +249,21 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
dops = dev->d_ops;
|
||||
|
||||
NDevSetDirty(dev);
|
||||
for (total = 0; count; count -= written, total += written) {
|
||||
written = dops->pwrite(dev, (const char*)b + total, count,
|
||||
pos + total);
|
||||
for (total = 0; count; count -= written, total += written)
|
||||
{
|
||||
written = dops->pwrite(dev, (const char*) b + total, count, pos + total);
|
||||
/* If everything ok, continue. */
|
||||
if (written > 0)
|
||||
continue;
|
||||
if (written > 0) continue;
|
||||
/*
|
||||
* If nothing written or error return number of bytes written.
|
||||
*/
|
||||
if (!written || total)
|
||||
break;
|
||||
if (!written || total) break;
|
||||
/* Nothing written and error, return error status. */
|
||||
total = written;
|
||||
break;
|
||||
}
|
||||
ret = total;
|
||||
out:
|
||||
return ret;
|
||||
out: return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,19 +295,18 @@ out:
|
||||
* sector transfer error. This should be detected by the caller by checking for
|
||||
* the magic being "BAAD".
|
||||
*/
|
||||
s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b)
|
||||
s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b)
|
||||
{
|
||||
s64 br, i;
|
||||
|
||||
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
|
||||
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Do the read. */
|
||||
br = ntfs_pread(dev, pos, count * bksize, b);
|
||||
if (br < 0)
|
||||
return br;
|
||||
if (br < 0) return br;
|
||||
/*
|
||||
* Apply fixups to successfully read data, disregarding any errors
|
||||
* 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;
|
||||
for (i = 0; i < count; ++i)
|
||||
ntfs_mst_post_read_fixup((NTFS_RECORD*)
|
||||
((u8*)b + i * bksize), bksize);
|
||||
ntfs_mst_post_read_fixup((NTFS_RECORD*) ((u8*) b + i * bksize), bksize);
|
||||
/* Finally, return the number of complete blocks read. */
|
||||
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
|
||||
* achieved.
|
||||
*/
|
||||
s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b)
|
||||
s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b)
|
||||
{
|
||||
s64 written, i;
|
||||
|
||||
if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
|
||||
if (count < 0 || bksize % NTFS_BLOCK_SIZE)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
if (!count) return 0;
|
||||
/* Prepare data for writing. */
|
||||
for (i = 0; i < count; ++i) {
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
|
||||
((u8*)b + i * bksize), bksize);
|
||||
if (err < 0) {
|
||||
err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) ((u8*) b + i * bksize), bksize);
|
||||
if (err < 0)
|
||||
{
|
||||
/* Abort write at this position. */
|
||||
if (!i)
|
||||
return err;
|
||||
if (!i) return err;
|
||||
count = i;
|
||||
break;
|
||||
}
|
||||
@ -381,8 +379,7 @@ s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
/* Quickly deprotect the data again. */
|
||||
for (i = 0; i < count; ++i)
|
||||
ntfs_mst_post_write_fixup((NTFS_RECORD*) ((u8*) b + i * bksize));
|
||||
if (written <= 0)
|
||||
return written;
|
||||
if (written <= 0) return written;
|
||||
/* Finally, return the number of complete blocks written. */
|
||||
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,
|
||||
* with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
||||
void *b)
|
||||
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count, void *b)
|
||||
{
|
||||
s64 br;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
if (!vol || lcn < 0 || count < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
if (vol->nr_clusters < lcn + count)
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror("Trying to read outside of volume "
|
||||
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||
(long long)lcn + count);
|
||||
return -1;
|
||||
}
|
||||
br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b);
|
||||
if (br < 0) {
|
||||
br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits, count << vol->cluster_size_bits, b);
|
||||
if (br < 0)
|
||||
{
|
||||
ntfs_log_perror("Error reading cluster(s)");
|
||||
return br;
|
||||
}
|
||||
@ -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
|
||||
* error, with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b)
|
||||
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, const s64 count, const void *b)
|
||||
{
|
||||
s64 bw;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
if (!vol || lcn < 0 || count < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
if (vol->nr_clusters < lcn + count)
|
||||
{
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror("Trying to write outside of volume "
|
||||
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||
@ -451,11 +450,10 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
return -1;
|
||||
}
|
||||
if (!NVolReadOnly(vol))
|
||||
bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b);
|
||||
else
|
||||
bw = count << vol->cluster_size_bits;
|
||||
if (bw < 0) {
|
||||
bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits, count << vol->cluster_size_bits, b);
|
||||
else bw = count << vol->cluster_size_bits;
|
||||
if (bw < 0)
|
||||
{
|
||||
ntfs_log_perror("Error writing cluster(s)");
|
||||
return bw;
|
||||
}
|
||||
@ -476,9 +474,7 @@ static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
|
||||
{
|
||||
char ch;
|
||||
|
||||
if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
|
||||
dev->d_ops->read(dev, &ch, 1) == 1)
|
||||
return 0;
|
||||
if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 && dev->d_ops->read(dev, &ch, 1) == 1) return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -498,14 +494,16 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
{
|
||||
s64 high, low;
|
||||
|
||||
if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
|
||||
if (!dev || block_size <= 0 || (block_size - 1) & block_size)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKGETSIZE64
|
||||
{ u64 size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0)
|
||||
{
|
||||
ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||
(unsigned long long)size,
|
||||
(unsigned long long)size);
|
||||
@ -516,7 +514,8 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
#ifdef BLKGETSIZE
|
||||
{ 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",
|
||||
size, 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
|
||||
{ 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",
|
||||
(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;
|
||||
for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
|
||||
low = high;
|
||||
while (low < high - 1LL) {
|
||||
while (low < high - 1LL)
|
||||
{
|
||||
const s64 mid = (low + high) / 2;
|
||||
|
||||
if (!ntfs_device_offset_valid(dev, mid))
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
else high = mid;
|
||||
}
|
||||
dev->d_ops->seek(dev, 0LL, SEEK_SET);
|
||||
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)
|
||||
{
|
||||
if (!dev) {
|
||||
if (!dev)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ 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",
|
||||
geo.start, 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)
|
||||
{
|
||||
if (!dev) {
|
||||
if (!dev)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ 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",
|
||||
(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)
|
||||
{
|
||||
if (!dev) {
|
||||
if (!dev)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef HDIO_GETGEO
|
||||
{ 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",
|
||||
(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)
|
||||
{
|
||||
if (!dev) {
|
||||
if (!dev)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -676,7 +683,8 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
||||
{
|
||||
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",
|
||||
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
|
||||
* ENOTTY @dev is a file or a device not supporting BLKBSZSET
|
||||
*/
|
||||
int ntfs_device_block_size_set(struct ntfs_device *dev,
|
||||
int block_size __attribute__((unused)))
|
||||
int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size __attribute__((unused)))
|
||||
{
|
||||
if (!dev)
|
||||
{
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKBSZSET
|
||||
{
|
||||
size_t s_block_size = block_size;
|
||||
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
|
||||
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size))
|
||||
{
|
||||
ntfs_log_debug("Used BLKBSZSET to set block size to "
|
||||
"%d bytes.\n", block_size);
|
||||
return 0;
|
||||
@ -722,8 +731,7 @@ int ntfs_device_block_size_set(struct ntfs_device *dev,
|
||||
}
|
||||
#else
|
||||
/* If not a block device, pretend it was successful. */
|
||||
if (!NDevBlock(dev))
|
||||
return 0;
|
||||
if (!NDevBlock(dev)) return 0;
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
return -1;
|
||||
|
@ -36,11 +36,13 @@
|
||||
*
|
||||
* Defined bits for the state field in the ntfs_device structure.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ND_Open, /* 1: Device is open. */
|
||||
ND_ReadOnly, /* 1: Device is read-only. */
|
||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||
ND_Block, /* 1: Device is a block device. */
|
||||
ND_Block,
|
||||
/* 1: Device is a block device. */
|
||||
} ntfs_device_state_bits;
|
||||
|
||||
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
|
||||
@ -69,7 +71,8 @@ typedef enum {
|
||||
* The ntfs device structure defining all operations needed to access the low
|
||||
* level device underlying the ntfs volume.
|
||||
*/
|
||||
struct ntfs_device {
|
||||
struct ntfs_device
|
||||
{
|
||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||
unsigned long d_state; /* State of the device. */
|
||||
char *d_name; /* Name of device. */
|
||||
@ -85,38 +88,32 @@ struct stat;
|
||||
* The ntfs device operations defining all operations that can be performed on
|
||||
* the low level device described by an ntfs device structure.
|
||||
*/
|
||||
struct ntfs_device_operations {
|
||||
struct ntfs_device_operations
|
||||
{
|
||||
int (*open)(struct ntfs_device *dev, int flags);
|
||||
int (*close)(struct ntfs_device *dev);
|
||||
s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence);
|
||||
s64 (*read)(struct ntfs_device *dev, void *buf, s64 count);
|
||||
s64 (*write)(struct ntfs_device *dev, const void *buf, s64 count);
|
||||
s64 (*pread)(struct ntfs_device *dev, void *buf, s64 count, s64 offset);
|
||||
s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count,
|
||||
s64 offset);
|
||||
s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count, s64 offset);
|
||||
int (*sync)(struct ntfs_device *dev);
|
||||
int (*stat)(struct ntfs_device *dev, struct stat *buf);
|
||||
int (*ioctl)(struct ntfs_device *dev, int request, void *argp);
|
||||
};
|
||||
|
||||
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
struct ntfs_device_operations *dops, void *priv_data);
|
||||
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state, struct ntfs_device_operations *dops,
|
||||
void *priv_data);
|
||||
extern int ntfs_device_free(struct ntfs_device *dev);
|
||||
|
||||
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b);
|
||||
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b);
|
||||
extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const void *b);
|
||||
|
||||
extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b);
|
||||
extern s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b);
|
||||
extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b);
|
||||
extern s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b);
|
||||
|
||||
extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, void *b);
|
||||
extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b);
|
||||
extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count, void *b);
|
||||
extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, const s64 count, const void *b);
|
||||
|
||||
extern s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size);
|
||||
extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev);
|
||||
|
@ -45,7 +45,8 @@
|
||||
/**
|
||||
* struct hd_geometry -
|
||||
*/
|
||||
struct hd_geometry {
|
||||
struct hd_geometry
|
||||
{
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
@ -70,7 +71,6 @@ struct hd_geometry {
|
||||
|
||||
#endif /* __CYGWIN32__ */
|
||||
|
||||
|
||||
/* Forward declaration. */
|
||||
struct ntfs_device_operations;
|
||||
|
||||
|
1195
source/libntfs/dir.c
1195
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_R[3];
|
||||
|
||||
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
|
||||
const ntfschar *uname, const int uname_len);
|
||||
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname, const int uname_len);
|
||||
extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name);
|
||||
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name,
|
||||
u64 inum);
|
||||
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, u64 inum);
|
||||
|
||||
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
const char *pathname);
|
||||
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type);
|
||||
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev);
|
||||
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len);
|
||||
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, const char *pathname);
|
||||
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, ntfschar *name, u8 name_len, mode_t type);
|
||||
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid, ntfschar *name, u8 name_len, mode_t type,
|
||||
dev_t dev);
|
||||
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid, ntfschar *name, u8 name_len, ntfschar *target,
|
||||
int target_len);
|
||||
extern int ntfs_check_empty_dir(ntfs_inode *ni);
|
||||
extern int ntfs_delete(ntfs_volume *vol, const char *path,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
extern int ntfs_delete(ntfs_volume *vol, const char *path, ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
|
||||
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len);
|
||||
|
||||
/*
|
||||
* File types (adapted from include <linux/fs.h>)
|
||||
@ -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
|
||||
* to have different dirent layouts depending on the binary type.
|
||||
*/
|
||||
typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name,
|
||||
const int name_len, const int name_type, const s64 pos,
|
||||
const MFT_REF mref, const unsigned dt_type);
|
||||
typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name, const int name_len, const int name_type,
|
||||
const s64 pos, const MFT_REF mref, const unsigned dt_type);
|
||||
|
||||
extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
void *dirent, ntfs_filldir_t filldir);
|
||||
extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir);
|
||||
|
||||
ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni);
|
||||
|
||||
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size);
|
||||
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
const char *value, size_t size, int flags);
|
||||
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, char *value, size_t size);
|
||||
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, const char *value, size_t size, int flags);
|
||||
int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||
|
||||
#if CACHE_INODE_SIZE
|
||||
|
@ -60,7 +60,8 @@
|
||||
|
||||
#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('E'),
|
||||
const_cpu_to_le16('F'),
|
||||
@ -68,7 +69,6 @@ static ntfschar logged_utility_stream_name[] = {
|
||||
const_cpu_to_le16(0)
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
s64 attr_size = 0;
|
||||
|
||||
if (ni) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
if (ni)
|
||||
{
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED)
|
||||
{
|
||||
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
|
||||
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
|
||||
&attr_size);
|
||||
if (efs_info
|
||||
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
||||
if (attr_size <= (s64)size) {
|
||||
&& (le32_to_cpu(efs_info->length) == attr_size))
|
||||
{
|
||||
if (attr_size <= (s64)size)
|
||||
{
|
||||
if (value)
|
||||
memcpy(value,efs_info,attr_size);
|
||||
else {
|
||||
else
|
||||
{
|
||||
errno = EFAULT;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else
|
||||
if (size) {
|
||||
}
|
||||
else
|
||||
if (size)
|
||||
{
|
||||
errno = ERANGE;
|
||||
attr_size = 0;
|
||||
}
|
||||
free (efs_info);
|
||||
} else {
|
||||
if (efs_info) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (efs_info)
|
||||
{
|
||||
free(efs_info);
|
||||
ntfs_log_error("Bad efs_info for inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error("Could not get efsinfo"
|
||||
" for inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
@ -111,7 +123,9 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
ntfs_log_trace("Inode %lld is not encrypted\n",
|
||||
(long long)ni->mft_no);
|
||||
@ -145,45 +159,57 @@ static int fixup_loop(ntfs_inode *ni)
|
||||
int res = 0;
|
||||
|
||||
maxcnt = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
restart = FALSE;
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
if (!ctx)
|
||||
{
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
res = -1;
|
||||
}
|
||||
cnt = 0;
|
||||
while (!restart && !res
|
||||
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx))
|
||||
{
|
||||
cnt++;
|
||||
a = ctx->attr;
|
||||
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
|
||||
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length);
|
||||
if (!na) {
|
||||
if (!na)
|
||||
{
|
||||
ntfs_log_error("can't open DATA Attribute\n");
|
||||
res = -1;
|
||||
}
|
||||
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
|
||||
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED))
|
||||
{
|
||||
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
|
||||
* is not enough space in the MFT record.
|
||||
* When this happens, force making non-resident
|
||||
* so that some other attribute is expelled.
|
||||
*/
|
||||
if (ntfs_attr_force_non_resident(na)) {
|
||||
if (ntfs_attr_force_non_resident(na))
|
||||
{
|
||||
res = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* make sure there is some progress */
|
||||
if (cnt <= maxcnt) {
|
||||
if (cnt <= maxcnt)
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_error("Multiple failure"
|
||||
" making non resident\n");
|
||||
res = -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||
restart = TRUE;
|
||||
@ -192,7 +218,8 @@ static int fixup_loop(ntfs_inode *ni)
|
||||
}
|
||||
}
|
||||
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");
|
||||
res = -1;
|
||||
}
|
||||
@ -223,13 +250,18 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
const EFS_ATTR_HEADER *info_header;
|
||||
|
||||
res = 0;
|
||||
if (ni && value && size) {
|
||||
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
if (ni && value && size)
|
||||
{
|
||||
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED))
|
||||
{
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED)
|
||||
{
|
||||
ntfs_log_trace("Inode %lld already encrypted\n",
|
||||
(long long)ni->mft_no);
|
||||
errno = EEXIST;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Possible problem : if encrypted file was
|
||||
* restored in a compressed directory, it was
|
||||
@ -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;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if (le32_to_cpu(info_header->length) != size) {
|
||||
if (le32_to_cpu(info_header->length) != size)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
(ntfschar*)NULL,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
(ntfschar*)NULL,0))
|
||||
{
|
||||
if (!(flags & XATTR_REPLACE))
|
||||
{
|
||||
/*
|
||||
* no logged_utility_stream attribute : add one,
|
||||
* 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,
|
||||
logged_utility_stream_name,4,
|
||||
(u8*)NULL,(s64)size);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
if (!res)
|
||||
{
|
||||
/*
|
||||
* open and update the existing efs data
|
||||
*/
|
||||
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4);
|
||||
if (na) {
|
||||
if (na)
|
||||
{
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate(na, (s64)size);
|
||||
/* overwrite value if any */
|
||||
if (!res && value) {
|
||||
if (!res && value)
|
||||
{
|
||||
written = (int)ntfs_attr_pwrite(na,
|
||||
(s64)0, (s64)size, value);
|
||||
if (written != (s64)size) {
|
||||
if (written != (s64)size)
|
||||
{
|
||||
ntfs_log_error("Failed to "
|
||||
"update efs data\n");
|
||||
errno = EIO;
|
||||
@ -287,12 +330,15 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
}
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
}
|
||||
else
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
if (!res)
|
||||
{
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))
|
||||
{
|
||||
/* iterate over AT_DATA attributes */
|
||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||
|
||||
@ -303,7 +349,9 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
@ -330,24 +378,31 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
ntfs_inode *ni;
|
||||
BOOL close_ctx = FALSE;
|
||||
|
||||
if (!na) {
|
||||
if (!na)
|
||||
{
|
||||
ntfs_log_error("no na specified for efs_fixup_attribute\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (!ctx) {
|
||||
if (!ctx)
|
||||
{
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx) {
|
||||
if (!ctx)
|
||||
{
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
goto err_out;
|
||||
}
|
||||
close_ctx = TRUE;
|
||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx))
|
||||
{
|
||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
if (!NAttrNonResident(na)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!NAttrNonResident(na))
|
||||
{
|
||||
ntfs_log_error("Cannot make non resident"
|
||||
" when a context has been allocated\n");
|
||||
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 */
|
||||
oldsize = na->data_size;
|
||||
if (oldsize) {
|
||||
if (oldsize)
|
||||
{
|
||||
/* 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");
|
||||
goto err_out;
|
||||
}
|
||||
/* 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");
|
||||
goto err_out;
|
||||
}
|
||||
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;
|
||||
ntfs_log_error("invalid padding length %d for data_size %lld\n",
|
||||
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
|
||||
* 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");
|
||||
goto err_out;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
newsize = 0;
|
||||
|
||||
/*
|
||||
@ -394,12 +455,16 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
* resident.
|
||||
*/
|
||||
if (!NAttrNonResident(na)
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
&& ntfs_attr_make_non_resident(na, 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");
|
||||
goto err_out;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* must reinitialize context after forcing
|
||||
* 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);
|
||||
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");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
ni = na->ni;
|
||||
if (!na->name_len) {
|
||||
if (!na->name_len)
|
||||
{
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
|
@ -23,8 +23,7 @@
|
||||
|
||||
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
int ntfs_set_efs_info(ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags);
|
||||
int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size, int flags);
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na);
|
||||
|
||||
#endif /* EFS_H */
|
||||
|
@ -69,7 +69,8 @@
|
||||
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf);
|
||||
static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer);
|
||||
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf);
|
||||
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
static 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
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if (!interface)
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Start the device interface and ensure that it is inserted
|
||||
if (!interface->startup()) {
|
||||
if (!interface->startup())
|
||||
{
|
||||
ntfs_log_perror("device failed to start\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (!interface->isInserted()) {
|
||||
if (!interface->isInserted())
|
||||
{
|
||||
ntfs_log_perror("device media is not inserted\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device isn't already open (used by another volume?)
|
||||
if (NDevOpen(dev)) {
|
||||
if (NDevOpen(dev))
|
||||
{
|
||||
ntfs_log_perror("device is busy (already open)\n");
|
||||
errno = EBUSY;
|
||||
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
|
||||
NTFS_BOOT_SECTOR boot;
|
||||
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
||||
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
||||
if (interface->readSectors(fd->startSector, 1, &boot))
|
||||
{
|
||||
if (!ntfs_boot_sector_is_ntfs(&boot))
|
||||
{
|
||||
errno = EINVALPART;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_perror("read failure @ sector %d\n", fd->startSector);
|
||||
errno = EIO;
|
||||
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);
|
||||
|
||||
// Mark the device as read-only (if required)
|
||||
if (flags & O_RDONLY) {
|
||||
if (flags & O_RDONLY)
|
||||
{
|
||||
NDevSetReadOnly(dev);
|
||||
}
|
||||
|
||||
// Create the cache
|
||||
fd->cache = _NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize);
|
||||
fd->cache = _NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector
|
||||
+ fd->sectorCount, fd->sectorSize);
|
||||
|
||||
// Mark the device as open
|
||||
NDevSetBlock(dev);
|
||||
@ -156,13 +168,15 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device is actually open
|
||||
if (!NDevOpen(dev)) {
|
||||
if (!NDevOpen(dev))
|
||||
{
|
||||
ntfs_log_perror("device is not open\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@ -173,7 +187,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
NDevClearBlock(dev);
|
||||
|
||||
// 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");
|
||||
|
||||
// ...?
|
||||
@ -184,7 +199,8 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
}
|
||||
|
||||
// Flush and destroy the cache (if required)
|
||||
if (fd->cache) {
|
||||
if (fd->cache)
|
||||
{
|
||||
_NTFS_cache_flush(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
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the current position on the device (in bytes)
|
||||
switch(whence) {
|
||||
case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
|
||||
case SEEK_CUR: fd->pos = MIN(MAX(fd->pos + offset, 0), fd->len); break;
|
||||
case SEEK_END: fd->pos = MIN(MAX(fd->len + offset, 0), fd->len); break;
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
fd->pos = MIN(MAX(offset, 0), fd->len);
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
fd->pos = MIN(MAX(fd->pos + offset, 0), fd->len);
|
||||
break;
|
||||
case SEEK_END:
|
||||
fd->pos = MIN(MAX(fd->len + offset, 0), fd->len);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -267,14 +291,16 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if (!interface)
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -285,8 +311,7 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!count)
|
||||
return 0;
|
||||
if (!count) return 0;
|
||||
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
if (buffer_offset+count > fd->sectorSize) {
|
||||
if (buffer_offset + count > fd->sectorSize)
|
||||
{
|
||||
sec_count = (sec_t) ceil((f64) (buffer_offset + count) / (f64) fd->sectorSize);
|
||||
}
|
||||
|
||||
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
||||
|
||||
if((buffer_offset == 0) && (count % fd->sectorSize == 0)) {
|
||||
if ((buffer_offset == 0) && (count % fd->sectorSize == 0))
|
||||
{
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf))
|
||||
{
|
||||
ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@ -320,7 +349,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
|
||||
// Allocate a buffer to hold the read data
|
||||
buffer = (u8*) ntfs_alloc(sec_count * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
if (!buffer)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
@ -328,7 +358,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
// Read from the device
|
||||
ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer))
|
||||
{
|
||||
ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
@ -353,31 +384,34 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
if (!interface)
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
if (NDevReadOnly(dev))
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(count < 0 || offset < 0) {
|
||||
if (count < 0 || offset < 0)
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(count == 0)
|
||||
return 0;
|
||||
if (count == 0) return 0;
|
||||
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
sec_t sec_count = 1;
|
||||
@ -385,10 +419,12 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// 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);
|
||||
}
|
||||
if ((buffer_offset+count) > fd->sectorSize) {
|
||||
if ((buffer_offset + count) > fd->sectorSize)
|
||||
{
|
||||
sec_count = (sec_t) ceil((f64) (buffer_offset + count) / (f64) fd->sectorSize);
|
||||
}
|
||||
|
||||
@ -397,7 +433,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
{
|
||||
// Write to the device
|
||||
ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf))
|
||||
{
|
||||
ntfs_log_perror("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@ -408,7 +445,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
{
|
||||
// Allocate a buffer to hold the write data
|
||||
buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
if (!buffer)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
@ -417,7 +455,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
// we just read in the buffer edges where the data overlaps with the rest of the disc
|
||||
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_free(buffer);
|
||||
errno = EIO;
|
||||
@ -426,7 +465,9 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
}
|
||||
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_free(buffer);
|
||||
errno = EIO;
|
||||
@ -439,7 +480,8 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
|
||||
// Write to the device
|
||||
ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer))
|
||||
{
|
||||
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
@ -460,24 +502,26 @@ static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sect
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
// Read the sectors from disc (or cache, if enabled)
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
||||
else
|
||||
return fd->interface->readSectors(sector, numSectors, buffer);
|
||||
else return fd->interface->readSectors(sector, numSectors, buffer);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors,
|
||||
const void* buffer)
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
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)
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
||||
else
|
||||
return fd->interface->writeSectors(sector, numSectors, buffer);
|
||||
else return fd->interface->writeSectors(sector, numSectors, buffer);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -500,7 +543,8 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
ntfs_log_trace("dev %p\n", dev);
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
if (NDevReadOnly(dev))
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
@ -509,8 +553,10 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
NDevClearDirty(dev);
|
||||
|
||||
// Flush any sectors in the disc cache (if required)
|
||||
if (fd->cache) {
|
||||
if (!_NTFS_cache_flush(fd->cache)) {
|
||||
if (fd->cache)
|
||||
{
|
||||
if (!_NTFS_cache_flush(fd->cache))
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
@ -528,19 +574,18 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!buf)
|
||||
return 0;
|
||||
if (!buf) return 0;
|
||||
|
||||
// Build the device mode
|
||||
mode_t mode = (S_IFBLK) |
|
||||
(S_IRUSR | S_IRGRP | S_IROTH) |
|
||||
((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
||||
mode_t mode = (S_IFBLK) | (S_IRUSR | S_IRGRP | S_IROTH)
|
||||
| ((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
||||
|
||||
// Zero out the stat buffer
|
||||
memset(buf, 0, sizeof(struct stat));
|
||||
@ -565,17 +610,20 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Figure out which i/o control was requested
|
||||
switch (request) {
|
||||
switch (request)
|
||||
{
|
||||
|
||||
// Get block device size (sectors)
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE: {
|
||||
case BLKGETSIZE:
|
||||
{
|
||||
*(u32*)argp = fd->sectorCount;
|
||||
return 0;
|
||||
}
|
||||
@ -583,7 +631,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64: {
|
||||
case BLKGETSIZE64:
|
||||
{
|
||||
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
||||
return 0;
|
||||
}
|
||||
@ -591,7 +640,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO: {
|
||||
case HDIO_GETGEO:
|
||||
{
|
||||
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
||||
geo->sectors = 0;
|
||||
geo->heads = 0;
|
||||
@ -603,7 +653,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET: {
|
||||
case BLKSSZGET:
|
||||
{
|
||||
*(int*)argp = fd->sectorSize;
|
||||
return 0;
|
||||
}
|
||||
@ -611,7 +662,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET: {
|
||||
case BLKBSZSET:
|
||||
{
|
||||
int sectorSize = *(int*)argp;
|
||||
fd->sectorSize = sectorSize;
|
||||
return 0;
|
||||
@ -619,7 +671,8 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
#endif
|
||||
|
||||
// Unimplemented ioctrl
|
||||
default: {
|
||||
default:
|
||||
{
|
||||
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||
errno = EOPNOTSUPP;
|
||||
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.
|
||||
*/
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops = {
|
||||
.open = ntfs_device_gekko_io_open,
|
||||
.close = ntfs_device_gekko_io_close,
|
||||
.seek = ntfs_device_gekko_io_seek,
|
||||
.read = ntfs_device_gekko_io_read,
|
||||
.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,
|
||||
};
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops = { .open = ntfs_device_gekko_io_open,
|
||||
.close = ntfs_device_gekko_io_close, .seek = ntfs_device_gekko_io_seek, .read = ntfs_device_gekko_io_read,
|
||||
.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, };
|
||||
|
@ -33,7 +33,8 @@
|
||||
/**
|
||||
* gekko_fd - Gekko device driver descriptor
|
||||
*/
|
||||
typedef struct _gekko_fd {
|
||||
typedef struct _gekko_fd
|
||||
{
|
||||
const DISC_INTERFACE* interface; /* Device disc interface */
|
||||
sec_t startSector; /* LBA of partition start */
|
||||
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -63,8 +63,7 @@
|
||||
|
||||
#define MAX_PARENT_VCN 32
|
||||
|
||||
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
||||
const void *data2, int len2);
|
||||
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1, const void *data2, int len2);
|
||||
|
||||
/**
|
||||
* struct ntfs_index_context -
|
||||
@ -112,7 +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
|
||||
* to disk.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
@ -133,21 +133,16 @@ typedef struct {
|
||||
u8 vcn_size_bits;
|
||||
} ntfs_index_context;
|
||||
|
||||
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, ntfschar *name, u32 name_len);
|
||||
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
|
||||
extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx);
|
||||
|
||||
extern int ntfs_index_lookup(const void *key, const int key_len,
|
||||
ntfs_index_context *ictx) __attribute_warn_unused_result__;
|
||||
extern int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ictx) __attribute_warn_unused_result__;
|
||||
|
||||
extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie,
|
||||
ntfs_index_context *ictx);
|
||||
extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx);
|
||||
|
||||
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
||||
MFT_REF mref);
|
||||
extern int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
const void *key, const int keylen);
|
||||
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref);
|
||||
extern int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni, const void *key, const int keylen);
|
||||
|
||||
extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr);
|
||||
|
||||
|
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.
|
||||
* (f) = files only, (d) = directories only
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||
|
||||
/* The NI_AttrList* tests only make sense for base inodes. */
|
||||
@ -51,7 +52,8 @@ typedef enum {
|
||||
in the index. */
|
||||
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
|
||||
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;
|
||||
|
||||
#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 NInoClearAttrList(ni) clear_nino_flag(ni, AttrList)
|
||||
|
||||
|
||||
#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 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
|
||||
* inode.
|
||||
*/
|
||||
struct _ntfs_inode {
|
||||
struct _ntfs_inode
|
||||
{
|
||||
u64 mft_no; /* Inode / mft record number. */
|
||||
MFT_RECORD *mrec; /* The actual mft record of the 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
|
||||
attached extent inodes (0 if none), for
|
||||
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 inodes of the extent mft
|
||||
records belonging to this base
|
||||
@ -166,10 +169,9 @@ struct _ntfs_inode {
|
||||
le64 usn;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
NTFS_UPDATE_ATIME = 1 << 0,
|
||||
NTFS_UPDATE_MTIME = 1 << 1,
|
||||
NTFS_UPDATE_CTIME = 1 << 2,
|
||||
typedef enum
|
||||
{
|
||||
NTFS_UPDATE_ATIME = 1 << 0, NTFS_UPDATE_MTIME = 1 << 1, NTFS_UPDATE_CTIME = 1 << 2,
|
||||
} ntfs_time_update_flags;
|
||||
|
||||
#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
|
||||
|
||||
|
||||
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);
|
||||
|
||||
@ -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_set_times(ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags);
|
||||
extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, int flags);
|
||||
|
||||
/* debugging */
|
||||
#define debug_double_inode(num, type)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -55,10 +55,9 @@
|
||||
#define NTFS_LCNALLOC_BSIZE 4096
|
||||
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
|
||||
|
||||
enum {
|
||||
ZONE_MFT = 1,
|
||||
ZONE_DATA1 = 2,
|
||||
ZONE_DATA2 = 4
|
||||
enum
|
||||
{
|
||||
ZONE_MFT = 1, ZONE_DATA1 = 2, ZONE_DATA2 = 4
|
||||
};
|
||||
|
||||
static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc)
|
||||
@ -67,8 +66,7 @@ static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc)
|
||||
|
||||
if (tc >= end)
|
||||
*pos = start;
|
||||
else if (tc >= start)
|
||||
*pos = tc;
|
||||
else if (tc >= start) *pos = tc;
|
||||
}
|
||||
|
||||
static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
|
||||
@ -76,14 +74,11 @@ static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
|
||||
ntfs_log_trace("tc = %lld, zone = %d\n", (long long)tc, zone);
|
||||
|
||||
if (zone == ZONE_MFT)
|
||||
ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end,
|
||||
&vol->mft_zone_pos, tc);
|
||||
ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end, &vol->mft_zone_pos, tc);
|
||||
else if (zone == ZONE_DATA1)
|
||||
ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters,
|
||||
&vol->data1_zone_pos, tc);
|
||||
ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters, &vol->data1_zone_pos, tc);
|
||||
else /* zone == ZONE_DATA2 */
|
||||
ntfs_cluster_set_zone_pos(0, vol->mft_zone_start,
|
||||
&vol->data2_zone_pos, tc);
|
||||
ntfs_cluster_set_zone_pos(0, vol->mft_zone_start, &vol->data2_zone_pos, tc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -94,19 +89,26 @@ static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
|
||||
|
||||
static void update_full_status(ntfs_volume *vol, LCN lcn)
|
||||
{
|
||||
if (lcn >= vol->mft_zone_end) {
|
||||
if (vol->full_zones & ZONE_DATA1) {
|
||||
if (lcn >= vol->mft_zone_end)
|
||||
{
|
||||
if (vol->full_zones & ZONE_DATA1)
|
||||
{
|
||||
ntfs_cluster_update_zone_pos(vol, ZONE_DATA1, lcn);
|
||||
vol->full_zones &= ~ZONE_DATA1;
|
||||
}
|
||||
} else
|
||||
if (lcn < vol->mft_zone_start) {
|
||||
if (vol->full_zones & ZONE_DATA2) {
|
||||
}
|
||||
else if (lcn < vol->mft_zone_start)
|
||||
{
|
||||
if (vol->full_zones & ZONE_DATA2)
|
||||
{
|
||||
ntfs_cluster_update_zone_pos(vol, ZONE_DATA2, lcn);
|
||||
vol->full_zones &= ~ZONE_DATA2;
|
||||
}
|
||||
} else {
|
||||
if (vol->full_zones & ZONE_MFT) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vol->full_zones & ZONE_MFT)
|
||||
{
|
||||
ntfs_cluster_update_zone_pos(vol, ZONE_MFT, lcn);
|
||||
vol->full_zones &= ~ZONE_MFT;
|
||||
}
|
||||
@ -122,39 +124,47 @@ static s64 max_empty_bit_range(unsigned char *buf, int size)
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
i = 0;
|
||||
while (i < size) {
|
||||
switch (*buf) {
|
||||
while (i < size)
|
||||
{
|
||||
switch (*buf)
|
||||
{
|
||||
case 0:
|
||||
do {
|
||||
do
|
||||
{
|
||||
buf++;
|
||||
run += 8;
|
||||
i++;
|
||||
} while ((i < size) && !*buf);
|
||||
break;
|
||||
case 255:
|
||||
if (run > max_range) {
|
||||
if (run > max_range)
|
||||
{
|
||||
max_range = run;
|
||||
start_pos = (s64) i * 8 - run;
|
||||
}
|
||||
run = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
buf++;
|
||||
i++;
|
||||
} while ((i < size) && (*buf == 255));
|
||||
break;
|
||||
default:
|
||||
for (j = 0; j < 8; j++) {
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
|
||||
int bit = *buf & (1 << j);
|
||||
|
||||
if (bit) {
|
||||
if (run > max_range) {
|
||||
if (bit)
|
||||
{
|
||||
if (run > max_range)
|
||||
{
|
||||
max_range = run;
|
||||
start_pos = (s64) i * 8 + (j - run);
|
||||
}
|
||||
run = 0;
|
||||
} else
|
||||
run++;
|
||||
}
|
||||
else run++;
|
||||
}
|
||||
i++;
|
||||
buf++;
|
||||
@ -162,28 +172,25 @@ static s64 max_empty_bit_range(unsigned char *buf, int size)
|
||||
}
|
||||
}
|
||||
|
||||
if (run > max_range)
|
||||
start_pos = (s64)i * 8 - run;
|
||||
if (run > max_range) start_pos = (s64) i * 8 - run;
|
||||
|
||||
return start_pos;
|
||||
}
|
||||
|
||||
static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
|
||||
u8 *writeback)
|
||||
static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b, u8 *writeback)
|
||||
{
|
||||
s64 written;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
if (!*writeback)
|
||||
return 0;
|
||||
if (!*writeback) return 0;
|
||||
|
||||
*writeback = 0;
|
||||
|
||||
written = ntfs_attr_pwrite(vol->lcnbmp_na, pos, size, b);
|
||||
if (written != size) {
|
||||
if (!written)
|
||||
errno = EIO;
|
||||
if (written != size)
|
||||
{
|
||||
if (!written) errno = EIO;
|
||||
ntfs_log_perror("Bitmap write error (%lld, %lld)",
|
||||
(long long)pos, (long long)size);
|
||||
return -1;
|
||||
@ -232,8 +239,8 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
|
||||
* 2) causes reduction in fragmentation.
|
||||
* The code is not optimized for speed.
|
||||
*/
|
||||
runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone)
|
||||
runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, LCN start_lcn,
|
||||
const NTFS_CLUSTER_ALLOCATION_ZONES zone)
|
||||
{
|
||||
LCN zone_start, zone_end; /* current search range */
|
||||
LCN last_read_pos, lcn;
|
||||
@ -252,8 +259,8 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
"zone = %s_ZONE.\n", (long long)count, (long long)
|
||||
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA");
|
||||
|
||||
if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
|
||||
(s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
|
||||
if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na || (s8) zone < FIRST_ZONE || zone > LAST_ZONE)
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld",
|
||||
__FUNCTION__, (long long)start_vcn,
|
||||
@ -262,9 +269,11 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
}
|
||||
|
||||
/* Return empty runlist if @count == 0 */
|
||||
if (!count) {
|
||||
if (!count)
|
||||
{
|
||||
rl = ntfs_malloc(0x1000);
|
||||
if (rl) {
|
||||
if (rl)
|
||||
{
|
||||
rl[0].vcn = start_vcn;
|
||||
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[0].length = 0;
|
||||
@ -273,8 +282,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
}
|
||||
|
||||
buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE);
|
||||
if (!buf)
|
||||
goto out;
|
||||
if (!buf) goto out;
|
||||
/*
|
||||
* If no @start_lcn was requested, use the current zone
|
||||
* position otherwise use the requested @start_lcn.
|
||||
@ -282,27 +290,30 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
has_guess = 1;
|
||||
zone_start = start_lcn;
|
||||
|
||||
if (zone_start < 0) {
|
||||
if (zone_start < 0)
|
||||
{
|
||||
if (zone == DATA_ZONE)
|
||||
zone_start = vol->data1_zone_pos;
|
||||
else
|
||||
zone_start = vol->mft_zone_pos;
|
||||
else zone_start = vol->mft_zone_pos;
|
||||
has_guess = 0;
|
||||
}
|
||||
|
||||
used_zone_pos = has_guess ? 0 : 1;
|
||||
|
||||
if (!zone_start || zone_start == vol->mft_zone_start ||
|
||||
zone_start == vol->mft_zone_end)
|
||||
pass = 2;
|
||||
if (!zone_start || zone_start == vol->mft_zone_start || zone_start == vol->mft_zone_end) pass = 2;
|
||||
|
||||
if (zone_start < vol->mft_zone_start) {
|
||||
if (zone_start < vol->mft_zone_start)
|
||||
{
|
||||
zone_end = vol->mft_zone_start;
|
||||
search_zone = ZONE_DATA2;
|
||||
} else if (zone_start < vol->mft_zone_end) {
|
||||
}
|
||||
else if (zone_start < vol->mft_zone_end)
|
||||
{
|
||||
zone_end = vol->mft_zone_end;
|
||||
search_zone = ZONE_MFT;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
zone_end = vol->nr_clusters;
|
||||
search_zone = ZONE_DATA1;
|
||||
}
|
||||
@ -312,16 +323,15 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
/* Loop until all clusters are allocated. */
|
||||
clusters = count;
|
||||
rlpos = rlsize = 0;
|
||||
while (1) {
|
||||
while (1)
|
||||
{
|
||||
/* check whether we have exhausted the current zone */
|
||||
if (search_zone & vol->full_zones)
|
||||
goto zone_pass_done;
|
||||
if (search_zone & vol->full_zones) goto zone_pass_done;
|
||||
last_read_pos = bmp_pos >> 3;
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos,
|
||||
NTFS_LCNALLOC_BSIZE, buf);
|
||||
if (br <= 0) {
|
||||
if (!br)
|
||||
goto zone_pass_done;
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos, NTFS_LCNALLOC_BSIZE, buf);
|
||||
if (br <= 0)
|
||||
{
|
||||
if (!br) goto zone_pass_done;
|
||||
err = errno;
|
||||
ntfs_log_perror("Reading $BITMAP failed");
|
||||
goto err_ret;
|
||||
@ -335,18 +345,22 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
bmp_pos &= ~7;
|
||||
writeback = 0;
|
||||
|
||||
while (lcn < buf_size) {
|
||||
while (lcn < buf_size)
|
||||
{
|
||||
byte = buf + (lcn >> 3);
|
||||
bit = 1 << (lcn & 7);
|
||||
if (has_guess) {
|
||||
if (*byte & bit) {
|
||||
if (has_guess)
|
||||
{
|
||||
if (*byte & bit)
|
||||
{
|
||||
has_guess = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
lcn = max_empty_bit_range(buf, br);
|
||||
if (lcn < 0)
|
||||
break;
|
||||
if (lcn < 0) break;
|
||||
has_guess = 1;
|
||||
continue;
|
||||
}
|
||||
@ -354,10 +368,12 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
/* First free bit is at lcn + bmp_pos. */
|
||||
|
||||
/* Reallocate memory if necessary. */
|
||||
if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
|
||||
if ((rlpos + 2) * (int) sizeof(runlist) >= rlsize)
|
||||
{
|
||||
rlsize += 4096;
|
||||
trl = realloc(rl, rlsize);
|
||||
if (!trl) {
|
||||
if (!trl)
|
||||
{
|
||||
err = ENOMEM;
|
||||
ntfs_log_perror("realloc() failed");
|
||||
goto wb_err_ret;
|
||||
@ -372,14 +388,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
ntfs_log_error("Non-positive free clusters "
|
||||
"(%lld)!\n",
|
||||
(long long)vol->free_clusters);
|
||||
else
|
||||
vol->free_clusters--;
|
||||
else vol->free_clusters--;
|
||||
|
||||
/*
|
||||
* Coalesce with previous run if adjacent LCNs.
|
||||
* Otherwise, append a new run.
|
||||
*/
|
||||
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
|
||||
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos)
|
||||
{
|
||||
ntfs_log_debug("Cluster coalesce: prev_lcn: "
|
||||
"%lld lcn: %lld bmp_pos: %lld "
|
||||
"prev_run_len: %lld\n",
|
||||
@ -387,11 +403,13 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
(long long)lcn, (long long)bmp_pos,
|
||||
(long long)prev_run_len);
|
||||
rl[rlpos - 1].length = ++prev_run_len;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rlpos)
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
||||
prev_run_len;
|
||||
else {
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + prev_run_len;
|
||||
else
|
||||
{
|
||||
rl[rlpos].vcn = start_vcn;
|
||||
ntfs_log_debug("Start_vcn: %lld\n",
|
||||
(long long)start_vcn);
|
||||
@ -407,23 +425,24 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
(long long)rl[rlpos - 1].lcn,
|
||||
(long long)rl[rlpos - 1].length);
|
||||
/* Done? */
|
||||
if (!--clusters) {
|
||||
if (used_zone_pos)
|
||||
ntfs_cluster_update_zone_pos(vol,
|
||||
search_zone, lcn + bmp_pos + 1 +
|
||||
NTFS_LCNALLOC_SKIP);
|
||||
if (!--clusters)
|
||||
{
|
||||
if (used_zone_pos) ntfs_cluster_update_zone_pos(vol, search_zone, lcn + bmp_pos + 1
|
||||
+ NTFS_LCNALLOC_SKIP);
|
||||
goto done_ret;
|
||||
}
|
||||
|
||||
lcn++;
|
||||
}
|
||||
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback))
|
||||
{
|
||||
err = errno;
|
||||
goto err_ret;
|
||||
}
|
||||
|
||||
if (!used_zone_pos) {
|
||||
if (!used_zone_pos)
|
||||
{
|
||||
|
||||
used_zone_pos = 1;
|
||||
|
||||
@ -431,22 +450,19 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
zone_start = vol->mft_zone_pos;
|
||||
else if (search_zone == ZONE_DATA1)
|
||||
zone_start = vol->data1_zone_pos;
|
||||
else
|
||||
zone_start = vol->data2_zone_pos;
|
||||
else zone_start = vol->data2_zone_pos;
|
||||
|
||||
if (!zone_start || zone_start == vol->mft_zone_start ||
|
||||
zone_start == vol->mft_zone_end)
|
||||
pass = 2;
|
||||
if (!zone_start || zone_start == vol->mft_zone_start || zone_start == vol->mft_zone_end) pass = 2;
|
||||
bmp_pos = zone_start;
|
||||
} else
|
||||
bmp_pos += buf_size;
|
||||
}
|
||||
else bmp_pos += buf_size;
|
||||
|
||||
if (bmp_pos < zone_end)
|
||||
continue;
|
||||
if (bmp_pos < zone_end) continue;
|
||||
|
||||
zone_pass_done:
|
||||
ntfs_log_trace("Finished current zone pass(%i).\n", pass);
|
||||
if (pass == 1) {
|
||||
if (pass == 1)
|
||||
{
|
||||
pass = 2;
|
||||
zone_end = zone_start;
|
||||
|
||||
@ -454,52 +470,48 @@ zone_pass_done:
|
||||
zone_start = vol->mft_zone_start;
|
||||
else if (search_zone == ZONE_DATA1)
|
||||
zone_start = vol->mft_zone_end;
|
||||
else
|
||||
zone_start = 0;
|
||||
else zone_start = 0;
|
||||
|
||||
/* Sanity check. */
|
||||
if (zone_end < zone_start)
|
||||
zone_end = zone_start;
|
||||
if (zone_end < zone_start) zone_end = zone_start;
|
||||
|
||||
bmp_pos = zone_start;
|
||||
|
||||
continue;
|
||||
}
|
||||
/* pass == 2 */
|
||||
done_zones_check:
|
||||
done_zones |= search_zone;
|
||||
done_zones_check: done_zones |= search_zone;
|
||||
vol->full_zones |= search_zone;
|
||||
if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2)) {
|
||||
if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2))
|
||||
{
|
||||
ntfs_log_trace("Switching zone.\n");
|
||||
pass = 1;
|
||||
if (rlpos) {
|
||||
LCN tc = rl[rlpos - 1].lcn +
|
||||
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
||||
if (rlpos)
|
||||
{
|
||||
LCN tc = rl[rlpos - 1].lcn + rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
||||
|
||||
if (used_zone_pos)
|
||||
ntfs_cluster_update_zone_pos(vol,
|
||||
search_zone, tc);
|
||||
if (used_zone_pos) ntfs_cluster_update_zone_pos(vol, search_zone, tc);
|
||||
}
|
||||
|
||||
switch (search_zone) {
|
||||
switch (search_zone)
|
||||
{
|
||||
case ZONE_MFT:
|
||||
ntfs_log_trace("Zone switch: mft -> data1\n");
|
||||
switch_to_data1_zone: search_zone = ZONE_DATA1;
|
||||
zone_start = vol->data1_zone_pos;
|
||||
zone_end = vol->nr_clusters;
|
||||
if (zone_start == vol->mft_zone_end)
|
||||
pass = 2;
|
||||
if (zone_start == vol->mft_zone_end) pass = 2;
|
||||
break;
|
||||
case ZONE_DATA1:
|
||||
ntfs_log_trace("Zone switch: data1 -> data2\n");
|
||||
search_zone = ZONE_DATA2;
|
||||
zone_start = vol->data2_zone_pos;
|
||||
zone_end = vol->mft_zone_start;
|
||||
if (!zone_start)
|
||||
pass = 2;
|
||||
if (!zone_start) pass = 2;
|
||||
break;
|
||||
case ZONE_DATA2:
|
||||
if (!(done_zones & ZONE_DATA1)) {
|
||||
if (!(done_zones & ZONE_DATA1))
|
||||
{
|
||||
ntfs_log_trace("data2 -> data1\n");
|
||||
goto switch_to_data1_zone;
|
||||
}
|
||||
@ -507,14 +519,14 @@ switch_to_data1_zone: search_zone = ZONE_DATA1;
|
||||
search_zone = ZONE_MFT;
|
||||
zone_start = vol->mft_zone_pos;
|
||||
zone_end = vol->mft_zone_end;
|
||||
if (zone_start == vol->mft_zone_start)
|
||||
pass = 2;
|
||||
if (zone_start == vol->mft_zone_start) pass = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
bmp_pos = zone_start;
|
||||
|
||||
if (zone_start == zone_end) {
|
||||
if (zone_start == zone_end)
|
||||
{
|
||||
ntfs_log_trace("Empty zone, skipped.\n");
|
||||
goto done_zones_check;
|
||||
}
|
||||
@ -532,13 +544,14 @@ done_ret:
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[rlpos].length = 0;
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback))
|
||||
{
|
||||
err = errno;
|
||||
goto err_ret;
|
||||
}
|
||||
done_err_ret:
|
||||
free(buf);
|
||||
if (err) {
|
||||
done_err_ret: free(buf);
|
||||
if (err)
|
||||
{
|
||||
errno = err;
|
||||
ntfs_log_perror("Failed to allocate clusters");
|
||||
rl = NULL;
|
||||
@ -549,11 +562,11 @@ out:
|
||||
|
||||
wb_err_ret:
|
||||
ntfs_log_trace("At wb_err_ret.\n");
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback))
|
||||
err = errno;
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) err = errno;
|
||||
err_ret:
|
||||
ntfs_log_trace("At err_ret.\n");
|
||||
if (rl) {
|
||||
if (rl)
|
||||
{
|
||||
/* Add runlist terminator element. */
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
@ -580,15 +593,17 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
for (; rl->length; rl++) {
|
||||
for (; rl->length; rl++)
|
||||
{
|
||||
|
||||
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||
(long long)rl->lcn, (long long)rl->length);
|
||||
|
||||
if (rl->lcn >= 0) {
|
||||
if (rl->lcn >= 0)
|
||||
{
|
||||
update_full_status(vol, rl->lcn);
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
|
||||
rl->length)) {
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, rl->length))
|
||||
{
|
||||
ntfs_log_perror("Cluster deallocation failed "
|
||||
"(%lld, %lld)",
|
||||
(long long)rl->lcn,
|
||||
@ -600,10 +615,8 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
vol->free_clusters += nr_freed;
|
||||
if (vol->free_clusters > vol->nr_clusters)
|
||||
ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||
out: vol->free_clusters += nr_freed;
|
||||
if (vol->free_clusters > vol->nr_clusters) ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||
(long long)vol->free_clusters,
|
||||
(long long)vol->nr_clusters);
|
||||
return ret;
|
||||
@ -623,10 +636,11 @@ int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count)
|
||||
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||
(long long)lcn, (long long)count);
|
||||
|
||||
if (lcn >= 0) {
|
||||
if (lcn >= 0)
|
||||
{
|
||||
update_full_status(vol, lcn);
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, lcn,
|
||||
count)) {
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, lcn, count))
|
||||
{
|
||||
ntfs_log_perror("Cluster deallocation failed "
|
||||
"(%lld, %lld)",
|
||||
(long long)lcn,
|
||||
@ -636,10 +650,8 @@ int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count)
|
||||
nr_freed += count;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
vol->free_clusters += nr_freed;
|
||||
if (vol->free_clusters > vol->nr_clusters)
|
||||
ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||
out: vol->free_clusters += nr_freed;
|
||||
if (vol->free_clusters > vol->nr_clusters) ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||
(long long)vol->free_clusters,
|
||||
(long long)vol->nr_clusters);
|
||||
return ret;
|
||||
@ -667,8 +679,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
s64 delta, to_free, nr_freed = 0;
|
||||
int ret = -1;
|
||||
|
||||
if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
|
||||
(count < 0 && count != -1)) {
|
||||
if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 || (count < 0 && count != -1))
|
||||
{
|
||||
ntfs_log_trace("Invalid arguments!\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -679,13 +691,14 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
na->type, (long long)count, (long long)start_vcn);
|
||||
|
||||
rl = ntfs_attr_find_vcn(na, start_vcn);
|
||||
if (!rl) {
|
||||
if (errno == ENOENT)
|
||||
ret = 0;
|
||||
if (!rl)
|
||||
{
|
||||
if (errno == ENOENT) ret = 0;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE)
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__,
|
||||
(long long)rl->lcn);
|
||||
@ -697,31 +710,30 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
|
||||
/* The number of clusters in this run that need freeing. */
|
||||
to_free = rl->length - delta;
|
||||
if (count >= 0 && to_free > count)
|
||||
to_free = count;
|
||||
if (count >= 0 && to_free > count) to_free = count;
|
||||
|
||||
if (rl->lcn != LCN_HOLE) {
|
||||
if (rl->lcn != LCN_HOLE)
|
||||
{
|
||||
/* Do the actual freeing of the clusters in this run. */
|
||||
update_full_status(vol, rl->lcn + delta);
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
|
||||
to_free))
|
||||
goto leave;
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta, to_free)) goto leave;
|
||||
nr_freed = to_free;
|
||||
}
|
||||
|
||||
/* Go to the next run and adjust the number of clusters left to free. */
|
||||
++rl;
|
||||
if (count >= 0)
|
||||
count -= to_free;
|
||||
if (count >= 0) count -= to_free;
|
||||
|
||||
/*
|
||||
* Loop over the remaining runs, using @count as a capping value, and
|
||||
* free them.
|
||||
*/
|
||||
for (; rl->length && count != 0; ++rl) {
|
||||
for (; rl->length && count != 0; ++rl)
|
||||
{
|
||||
// FIXME: Need to try ntfs_attr_map_runlist() for attribute
|
||||
// list support! (AIA)
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE)
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
errno = EIO;
|
||||
ntfs_log_perror("%s: Invalid lcn (%lli)",
|
||||
@ -731,13 +743,13 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
|
||||
/* The number of clusters in this run that need freeing. */
|
||||
to_free = rl->length;
|
||||
if (count >= 0 && to_free > count)
|
||||
to_free = count;
|
||||
if (count >= 0 && to_free > count) to_free = count;
|
||||
|
||||
if (rl->lcn != LCN_HOLE) {
|
||||
if (rl->lcn != LCN_HOLE)
|
||||
{
|
||||
update_full_status(vol, rl->lcn);
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
|
||||
to_free)) {
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, to_free))
|
||||
{
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_perror("%s: Clearing bitmap run failed",
|
||||
__FUNCTION__);
|
||||
@ -746,11 +758,11 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
nr_freed += to_free;
|
||||
}
|
||||
|
||||
if (count >= 0)
|
||||
count -= to_free;
|
||||
if (count >= 0) count -= to_free;
|
||||
}
|
||||
|
||||
if (count != -1 && count != 0) {
|
||||
if (count != -1 && count != 0)
|
||||
{
|
||||
// FIXME: Eeek! BUG()
|
||||
errno = EIO;
|
||||
ntfs_log_perror("%s: count still not zero (%lld)", __FUNCTION__,
|
||||
@ -759,10 +771,8 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
}
|
||||
|
||||
ret = nr_freed;
|
||||
out:
|
||||
vol->free_clusters += nr_freed ;
|
||||
if (vol->free_clusters > vol->nr_clusters)
|
||||
ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||
out: vol->free_clusters += nr_freed;
|
||||
if (vol->free_clusters > vol->nr_clusters) ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||
(long long)vol->free_clusters,
|
||||
(long long)vol->nr_clusters);
|
||||
leave:
|
||||
|
@ -31,21 +31,22 @@
|
||||
/**
|
||||
* enum NTFS_CLUSTER_ALLOCATION_ZONES -
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
FIRST_ZONE = 0, /* For sanity checking. */
|
||||
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
||||
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
||||
LAST_ZONE = 1, /* For sanity checking. */
|
||||
LAST_ZONE = 1,
|
||||
/* For sanity checking. */
|
||||
} NTFS_CLUSTER_ALLOCATION_ZONES;
|
||||
|
||||
extern runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone);
|
||||
extern runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, LCN start_lcn,
|
||||
const NTFS_CLUSTER_ALLOCATION_ZONES zone);
|
||||
|
||||
extern int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl);
|
||||
extern int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count);
|
||||
|
||||
extern int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
|
||||
s64 count);
|
||||
extern int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count);
|
||||
|
||||
#endif /* defined _NTFS_LCNALLOC_H */
|
||||
|
||||
|
@ -67,11 +67,10 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
*/
|
||||
logfile_system_page_size = le32_to_cpu(rp->system_page_size);
|
||||
logfile_log_page_size = le32_to_cpu(rp->log_page_size);
|
||||
if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
|
||||
logfile_log_page_size < NTFS_BLOCK_SIZE ||
|
||||
logfile_system_page_size &
|
||||
(logfile_system_page_size - 1) ||
|
||||
logfile_log_page_size & (logfile_log_page_size - 1)) {
|
||||
if (logfile_system_page_size < NTFS_BLOCK_SIZE || logfile_log_page_size < NTFS_BLOCK_SIZE
|
||||
|| logfile_system_page_size & (logfile_system_page_size - 1) || logfile_log_page_size
|
||||
& (logfile_log_page_size - 1))
|
||||
{
|
||||
ntfs_log_error("$LogFile uses unsupported page size.\n");
|
||||
return FALSE;
|
||||
}
|
||||
@ -79,14 +78,15 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
* We must be either at !pos (1st restart page) or at pos = system page
|
||||
* size (2nd restart page).
|
||||
*/
|
||||
if (pos && pos != logfile_system_page_size) {
|
||||
if (pos && pos != logfile_system_page_size)
|
||||
{
|
||||
ntfs_log_error("Found restart area in incorrect "
|
||||
"position in $LogFile.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* We only know how to handle version 1.1. */
|
||||
if (sle16_to_cpu(rp->major_ver) != 1 ||
|
||||
sle16_to_cpu(rp->minor_ver) != 1) {
|
||||
if (sle16_to_cpu(rp->major_ver) != 1 || sle16_to_cpu(rp->minor_ver) != 1)
|
||||
{
|
||||
ntfs_log_error("$LogFile version %i.%i is not "
|
||||
"supported. (This driver supports version "
|
||||
"1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver),
|
||||
@ -97,13 +97,15 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
* If chkdsk has been run the restart page may not be protected by an
|
||||
* update sequence array.
|
||||
*/
|
||||
if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
|
||||
if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count))
|
||||
{
|
||||
have_usa = FALSE;
|
||||
goto skip_usa_checks;
|
||||
}
|
||||
/* Verify the size of the update sequence array. */
|
||||
usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
|
||||
if (usa_count != le16_to_cpu(rp->usa_count)) {
|
||||
if (usa_count != le16_to_cpu(rp->usa_count))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent update sequence array count.\n");
|
||||
return FALSE;
|
||||
@ -111,8 +113,8 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
/* Verify the position of the update sequence array. */
|
||||
usa_ofs = le16_to_cpu(rp->usa_ofs);
|
||||
usa_end = usa_ofs + usa_count * sizeof(u16);
|
||||
if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
|
||||
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||
if (usa_ofs < sizeof(RESTART_PAGE_HEADER) || usa_end > NTFS_BLOCK_SIZE - sizeof(u16))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent update sequence array offset.\n");
|
||||
return FALSE;
|
||||
@ -125,9 +127,9 @@ skip_usa_checks:
|
||||
* - within the system page size.
|
||||
*/
|
||||
ra_ofs = le16_to_cpu(rp->restart_area_offset);
|
||||
if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
|
||||
ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
|
||||
ra_ofs > logfile_system_page_size) {
|
||||
if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end : ra_ofs < sizeof(RESTART_PAGE_HEADER)) || ra_ofs
|
||||
> logfile_system_page_size)
|
||||
{
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent restart area offset.\n");
|
||||
return FALSE;
|
||||
@ -136,7 +138,8 @@ skip_usa_checks:
|
||||
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
|
||||
* set.
|
||||
*/
|
||||
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
|
||||
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart page is not modified "
|
||||
"by chkdsk but a chkdsk LSN is specified.\n");
|
||||
return FALSE;
|
||||
@ -173,8 +176,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
* protected by an update sequence number. This ensures that it is
|
||||
* safe to access ra->client_array_offset.
|
||||
*/
|
||||
if (ra_ofs + offsetof(RESTART_AREA, file_size) >
|
||||
NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||
if (ra_ofs + offsetof(RESTART_AREA, file_size) > NTFS_BLOCK_SIZE - sizeof(u16))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent file offset.\n");
|
||||
return FALSE;
|
||||
@ -187,9 +190,8 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
* aligned to an 8-byte boundary.
|
||||
*/
|
||||
ca_ofs = le16_to_cpu(ra->client_array_offset);
|
||||
if (((ca_ofs + 7) & ~7) != ca_ofs ||
|
||||
ra_ofs + ca_ofs > (u16)(NTFS_BLOCK_SIZE -
|
||||
sizeof(u16))) {
|
||||
if (((ca_ofs + 7) & ~7) != ca_ofs || ra_ofs + ca_ofs > (u16) (NTFS_BLOCK_SIZE - sizeof(u16)))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent client array offset.\n");
|
||||
return FALSE;
|
||||
@ -199,12 +201,11 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
* calculated manually and as specified by ra->restart_area_length.
|
||||
* Also, the calculated length must not exceed the specified length.
|
||||
*/
|
||||
ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
|
||||
sizeof(LOG_CLIENT_RECORD);
|
||||
if ((u32)(ra_ofs + ra_len) > le32_to_cpu(rp->system_page_size) ||
|
||||
(u32)(ra_ofs + le16_to_cpu(ra->restart_area_length)) >
|
||||
le32_to_cpu(rp->system_page_size) ||
|
||||
ra_len > le16_to_cpu(ra->restart_area_length)) {
|
||||
ra_len = ca_ofs + le16_to_cpu(ra->log_clients) * sizeof(LOG_CLIENT_RECORD);
|
||||
if ((u32) (ra_ofs + ra_len) > le32_to_cpu(rp->system_page_size) || (u32) (ra_ofs
|
||||
+ le16_to_cpu(ra->restart_area_length)) > le32_to_cpu(rp->system_page_size) || ra_len
|
||||
> le16_to_cpu(ra->restart_area_length))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart area is out of bounds "
|
||||
"of the system page size specified by the "
|
||||
"restart page header and/or the specified "
|
||||
@ -216,12 +217,10 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
* LOGFILE_NO_CLIENT or less than ra->log_clients or they are
|
||||
* overflowing the client array.
|
||||
*/
|
||||
if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
|
||||
le16_to_cpu(ra->client_free_list) >=
|
||||
le16_to_cpu(ra->log_clients)) ||
|
||||
(ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||
le16_to_cpu(ra->client_in_use_list) >=
|
||||
le16_to_cpu(ra->log_clients))) {
|
||||
if ((ra->client_free_list != LOGFILE_NO_CLIENT && le16_to_cpu(ra->client_free_list) >= le16_to_cpu(ra->log_clients))
|
||||
|| (ra->client_in_use_list != LOGFILE_NO_CLIENT && le16_to_cpu(ra->client_in_use_list)
|
||||
>= le16_to_cpu(ra->log_clients)))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"overflowing client free and/or in use lists.\n");
|
||||
return FALSE;
|
||||
@ -232,25 +231,27 @@ static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
*/
|
||||
file_size = (u64) sle64_to_cpu(ra->file_size);
|
||||
fs_bits = 0;
|
||||
while (file_size) {
|
||||
while (file_size)
|
||||
{
|
||||
file_size >>= 1;
|
||||
fs_bits++;
|
||||
}
|
||||
if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) {
|
||||
if (le32_to_cpu(ra->seq_number_bits) != (u32) (67 - fs_bits))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent sequence number bits.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* The log record header length must be a multiple of 8. */
|
||||
if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
|
||||
le16_to_cpu(ra->log_record_header_length)) {
|
||||
if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) != le16_to_cpu(ra->log_record_header_length))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent log record header length.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* Ditto for the log page data offset. */
|
||||
if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
|
||||
le16_to_cpu(ra->log_page_data_offset)) {
|
||||
if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) != le16_to_cpu(ra->log_page_data_offset))
|
||||
{
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent log page data offset.\n");
|
||||
return FALSE;
|
||||
@ -282,8 +283,7 @@ static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
ra = (RESTART_AREA*) ((u8*) rp + le16_to_cpu(rp->restart_area_offset));
|
||||
ca = (LOG_CLIENT_RECORD*)((u8*)ra +
|
||||
le16_to_cpu(ra->client_array_offset));
|
||||
ca = (LOG_CLIENT_RECORD*) ((u8*) ra + le16_to_cpu(ra->client_array_offset));
|
||||
/*
|
||||
* Check the ra->client_free_list first and then check the
|
||||
* ra->client_in_use_list. Check each of the log client records in
|
||||
@ -295,30 +295,29 @@ static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
|
||||
nr_clients = le16_to_cpu(ra->log_clients);
|
||||
idx = le16_to_cpu(ra->client_free_list);
|
||||
in_free_list = TRUE;
|
||||
check_list:
|
||||
for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
|
||||
idx = le16_to_cpu(cr->next_client)) {
|
||||
if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
|
||||
goto err_out;
|
||||
check_list: for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--, idx
|
||||
= le16_to_cpu(cr->next_client))
|
||||
{
|
||||
if (!nr_clients || idx >= le16_to_cpu(ra->log_clients)) goto err_out;
|
||||
/* Set @cr to the current log client record. */
|
||||
cr = ca + idx;
|
||||
/* The first log client record must not have a prev_client. */
|
||||
if (idx_is_first) {
|
||||
if (cr->prev_client != LOGFILE_NO_CLIENT)
|
||||
goto err_out;
|
||||
if (idx_is_first)
|
||||
{
|
||||
if (cr->prev_client != LOGFILE_NO_CLIENT) goto err_out;
|
||||
idx_is_first = FALSE;
|
||||
}
|
||||
}
|
||||
/* Switch to and check the in use list if we just did the free list. */
|
||||
if (in_free_list) {
|
||||
if (in_free_list)
|
||||
{
|
||||
in_free_list = FALSE;
|
||||
idx = le16_to_cpu(ra->client_in_use_list);
|
||||
goto check_list;
|
||||
}
|
||||
ntfs_log_trace("Done.\n");
|
||||
return TRUE;
|
||||
err_out:
|
||||
ntfs_log_error("$LogFile log client array is corrupt.\n");
|
||||
err_out: ntfs_log_error("$LogFile log client array is corrupt.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -349,9 +348,8 @@ err_out:
|
||||
* ENOMEM - Not enough memory to load the restart page.
|
||||
* EIO - Failed to reading from $LogFile.
|
||||
*/
|
||||
static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
|
||||
LSN *lsn)
|
||||
static int ntfs_check_and_load_restart_page(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp, s64 pos,
|
||||
RESTART_PAGE_HEADER **wrp, LSN *lsn)
|
||||
{
|
||||
RESTART_AREA *ra;
|
||||
RESTART_PAGE_HEADER *trp;
|
||||
@ -359,12 +357,14 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
/* Check the restart page header for consistency. */
|
||||
if (!ntfs_check_restart_page_header(rp, pos)) {
|
||||
if (!ntfs_check_restart_page_header(rp, pos))
|
||||
{
|
||||
/* Error output already done inside the function. */
|
||||
return EINVAL;
|
||||
}
|
||||
/* Check the restart area for consistency. */
|
||||
if (!ntfs_check_restart_area(rp)) {
|
||||
if (!ntfs_check_restart_area(rp))
|
||||
{
|
||||
/* Error output already done inside the function. */
|
||||
return EINVAL;
|
||||
}
|
||||
@ -374,8 +374,7 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
* sector transfer deprotect it.
|
||||
*/
|
||||
trp = ntfs_malloc(le32_to_cpu(rp->system_page_size));
|
||||
if (!trp)
|
||||
return errno;
|
||||
if (!trp) return errno;
|
||||
/*
|
||||
* Read the whole of the restart page into the buffer. If it fits
|
||||
* completely inside @rp, just copy it from there. Otherwise read it
|
||||
@ -383,31 +382,29 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
*/
|
||||
if (le32_to_cpu(rp->system_page_size) <= NTFS_BLOCK_SIZE)
|
||||
memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
|
||||
else if (ntfs_attr_pread(log_na, pos,
|
||||
le32_to_cpu(rp->system_page_size), trp) !=
|
||||
le32_to_cpu(rp->system_page_size)) {
|
||||
else if (ntfs_attr_pread(log_na, pos, le32_to_cpu(rp->system_page_size), trp) != le32_to_cpu(rp->system_page_size))
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to read whole restart page into the "
|
||||
"buffer.\n");
|
||||
if (err != ENOMEM)
|
||||
err = EIO;
|
||||
if (err != ENOMEM) err = EIO;
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* Perform the multi sector transfer deprotection on the buffer if the
|
||||
* restart page is protected.
|
||||
*/
|
||||
if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
|
||||
&& ntfs_mst_post_read_fixup((NTFS_RECORD*)trp,
|
||||
le32_to_cpu(rp->system_page_size))) {
|
||||
if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count)) && ntfs_mst_post_read_fixup(
|
||||
(NTFS_RECORD*) trp, le32_to_cpu(rp->system_page_size)))
|
||||
{
|
||||
/*
|
||||
* A multi sector tranfer error was detected. We only need to
|
||||
* abort if the restart page contents exceed the multi sector
|
||||
* transfer fixup of the first sector.
|
||||
*/
|
||||
if (le16_to_cpu(rp->restart_area_offset) +
|
||||
le16_to_cpu(ra->restart_area_length) >
|
||||
NTFS_BLOCK_SIZE - (int)sizeof(u16)) {
|
||||
if (le16_to_cpu(rp->restart_area_offset) + le16_to_cpu(ra->restart_area_length) > NTFS_BLOCK_SIZE
|
||||
- (int) sizeof(u16))
|
||||
{
|
||||
ntfs_log_error("Multi sector transfer error "
|
||||
"detected in $LogFile restart page.\n");
|
||||
err = EINVAL;
|
||||
@ -420,14 +417,16 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
* check the log client records for consistency, too.
|
||||
*/
|
||||
err = 0;
|
||||
if (ntfs_is_rstr_record(rp->magic) &&
|
||||
ra->client_in_use_list != LOGFILE_NO_CLIENT) {
|
||||
if (!ntfs_check_log_client_array(trp)) {
|
||||
if (ntfs_is_rstr_record(rp->magic) && ra->client_in_use_list != LOGFILE_NO_CLIENT)
|
||||
{
|
||||
if (!ntfs_check_log_client_array(trp))
|
||||
{
|
||||
err = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
if (lsn) {
|
||||
if (lsn)
|
||||
{
|
||||
if (ntfs_is_rstr_record(rp->magic))
|
||||
*lsn = sle64_to_cpu(ra->current_lsn);
|
||||
else /* if (ntfs_is_chkd_record(rp->magic)) */
|
||||
@ -436,9 +435,9 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
ntfs_log_trace("Done.\n");
|
||||
if (wrp)
|
||||
*wrp = trp;
|
||||
else {
|
||||
err_out:
|
||||
free(trp);
|
||||
else
|
||||
{
|
||||
err_out: free(trp);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -474,12 +473,10 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
/* An empty $LogFile must have been clean before it got emptied. */
|
||||
if (NVolLogFileEmpty(vol))
|
||||
goto is_empty;
|
||||
if (NVolLogFileEmpty(vol)) goto is_empty;
|
||||
size = log_na->data_size;
|
||||
/* Make sure the file doesn't exceed the maximum allowed size. */
|
||||
if (size > (s64)MaxLogFileSize)
|
||||
size = MaxLogFileSize;
|
||||
if (size > (s64) MaxLogFileSize) size = MaxLogFileSize;
|
||||
log_page_size = DefaultLogPageSize;
|
||||
log_page_mask = log_page_size - 1;
|
||||
/*
|
||||
@ -493,15 +490,14 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
* Ensure the log file is big enough to store at least the two restart
|
||||
* pages and the minimum number of log record pages.
|
||||
*/
|
||||
if (size < log_page_size * 2 || (size - log_page_size * 2) >>
|
||||
log_page_bits < MinLogRecordPages) {
|
||||
if (size < log_page_size * 2 || (size - log_page_size * 2) >> log_page_bits < MinLogRecordPages)
|
||||
{
|
||||
ntfs_log_error("$LogFile is too small.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* Allocate memory for restart page. */
|
||||
kaddr = ntfs_malloc(NTFS_BLOCK_SIZE);
|
||||
if (!kaddr)
|
||||
return FALSE;
|
||||
if (!kaddr) return FALSE;
|
||||
/*
|
||||
* Read through the file looking for a restart page. Since the restart
|
||||
* page header is at the beginning of a page we only need to search at
|
||||
@ -510,12 +506,13 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
* contain empty and uninitialized records, the log file can be assumed
|
||||
* to be empty.
|
||||
*/
|
||||
for (pos = 0; pos < size; pos <<= 1) {
|
||||
for (pos = 0; pos < size; pos <<= 1)
|
||||
{
|
||||
/*
|
||||
* Read first NTFS_BLOCK_SIZE bytes of potential restart page.
|
||||
*/
|
||||
if (ntfs_attr_pread(log_na, pos, NTFS_BLOCK_SIZE, kaddr) !=
|
||||
NTFS_BLOCK_SIZE) {
|
||||
if (ntfs_attr_pread(log_na, pos, NTFS_BLOCK_SIZE, kaddr) != NTFS_BLOCK_SIZE)
|
||||
{
|
||||
ntfs_log_error("Failed to read first NTFS_BLOCK_SIZE "
|
||||
"bytes of potential restart page.\n");
|
||||
goto err_out;
|
||||
@ -528,19 +525,16 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
*/
|
||||
if (!ntfs_is_empty_recordp((le32*)kaddr))
|
||||
logfile_is_empty = FALSE;
|
||||
else if (!logfile_is_empty)
|
||||
break;
|
||||
else if (!logfile_is_empty) break;
|
||||
/*
|
||||
* A log record page means there cannot be a restart page after
|
||||
* this so no need to continue searching.
|
||||
*/
|
||||
if (ntfs_is_rcrd_recordp((le32*)kaddr))
|
||||
break;
|
||||
if (ntfs_is_rcrd_recordp((le32*)kaddr)) break;
|
||||
/* If not a (modified by chkdsk) restart page, continue. */
|
||||
if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
|
||||
!ntfs_is_chkd_recordp((le32*)kaddr)) {
|
||||
if (!pos)
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
if (!ntfs_is_rstr_recordp((le32*)kaddr) && !ntfs_is_chkd_recordp((le32*)kaddr))
|
||||
{
|
||||
if (!pos) pos = NTFS_BLOCK_SIZE >> 1;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
@ -548,16 +542,16 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
* and get a copy of the complete multi sector transfer
|
||||
* deprotected restart page.
|
||||
*/
|
||||
err = ntfs_check_and_load_restart_page(log_na,
|
||||
(RESTART_PAGE_HEADER*)kaddr, pos,
|
||||
!rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
||||
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
|
||||
if (!err) {
|
||||
err = ntfs_check_and_load_restart_page(log_na, (RESTART_PAGE_HEADER*) kaddr, pos, !rstr1_ph ? &rstr1_ph
|
||||
: &rstr2_ph, !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
|
||||
if (!err)
|
||||
{
|
||||
/*
|
||||
* If we have now found the first (modified by chkdsk)
|
||||
* restart page, continue looking for the second one.
|
||||
*/
|
||||
if (!pos) {
|
||||
if (!pos)
|
||||
{
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
continue;
|
||||
}
|
||||
@ -572,42 +566,46 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
* not abort if the restart page was invalid as we might still
|
||||
* find a valid one further in the file.
|
||||
*/
|
||||
if (err != EINVAL)
|
||||
goto err_out;
|
||||
if (err != EINVAL) goto err_out;
|
||||
/* Continue looking. */
|
||||
if (!pos)
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
if (!pos) pos = NTFS_BLOCK_SIZE >> 1;
|
||||
}
|
||||
if (kaddr) {
|
||||
if (kaddr)
|
||||
{
|
||||
free(kaddr);
|
||||
kaddr = NULL;
|
||||
}
|
||||
if (logfile_is_empty) {
|
||||
if (logfile_is_empty)
|
||||
{
|
||||
NVolSetLogFileEmpty(vol);
|
||||
is_empty:
|
||||
ntfs_log_trace("Done. ($LogFile is empty.)\n");
|
||||
return TRUE;
|
||||
}
|
||||
if (!rstr1_ph) {
|
||||
if (rstr2_ph)
|
||||
ntfs_log_error("BUG: rstr2_ph isn't NULL!\n");
|
||||
if (!rstr1_ph)
|
||||
{
|
||||
if (rstr2_ph) ntfs_log_error("BUG: rstr2_ph isn't NULL!\n");
|
||||
ntfs_log_error("Did not find any restart pages in "
|
||||
"$LogFile and it was not empty.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* If both restart pages were found, use the more recent one. */
|
||||
if (rstr2_ph) {
|
||||
if (rstr2_ph)
|
||||
{
|
||||
/*
|
||||
* If the second restart area is more recent, switch to it.
|
||||
* Otherwise just throw it away.
|
||||
*/
|
||||
if (rstr2_lsn > rstr1_lsn) {
|
||||
if (rstr2_lsn > rstr1_lsn)
|
||||
{
|
||||
ntfs_log_debug("Using second restart page as it is more "
|
||||
"recent.\n");
|
||||
free(rstr1_ph);
|
||||
rstr1_ph = rstr2_ph;
|
||||
/* rstr1_lsn = rstr2_lsn; */
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug("Using first restart page as it is more "
|
||||
"recent.\n");
|
||||
free(rstr2_ph);
|
||||
@ -617,12 +615,10 @@ is_empty:
|
||||
/* All consistency checks passed. */
|
||||
if (rp)
|
||||
*rp = rstr1_ph;
|
||||
else
|
||||
free(rstr1_ph);
|
||||
else free(rstr1_ph);
|
||||
ntfs_log_trace("Done.\n");
|
||||
return TRUE;
|
||||
err_out:
|
||||
free(kaddr);
|
||||
err_out: free(kaddr);
|
||||
free(rstr1_ph);
|
||||
free(rstr2_ph);
|
||||
return FALSE;
|
||||
@ -654,16 +650,18 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
/* An empty $LogFile must have been clean before it got emptied. */
|
||||
if (NVolLogFileEmpty(log_na->ni->vol)) {
|
||||
if (NVolLogFileEmpty(log_na->ni->vol))
|
||||
{
|
||||
ntfs_log_trace("$LogFile is empty\n");
|
||||
return TRUE;
|
||||
}
|
||||
if (!rp) {
|
||||
if (!rp)
|
||||
{
|
||||
ntfs_log_error("Restart page header is NULL\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!ntfs_is_rstr_record(rp->magic) &&
|
||||
!ntfs_is_chkd_record(rp->magic)) {
|
||||
if (!ntfs_is_rstr_record(rp->magic) && !ntfs_is_chkd_record(rp->magic))
|
||||
{
|
||||
ntfs_log_error("Restart page buffer is invalid\n");
|
||||
return FALSE;
|
||||
}
|
||||
@ -674,8 +672,8 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
||||
* have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
|
||||
* we assume there was an unclean shutdown.
|
||||
*/
|
||||
if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
|
||||
if (ra->client_in_use_list != LOGFILE_NO_CLIENT && !(ra->flags & RESTART_VOLUME_IS_CLEAN))
|
||||
{
|
||||
ntfs_log_error("The disk contains an unclean file system (%d, "
|
||||
"%d).\n", le16_to_cpu(ra->client_in_use_list),
|
||||
le16_to_cpu(ra->flags));
|
||||
@ -704,10 +702,10 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
if (NVolLogFileEmpty(na->ni->vol))
|
||||
return 0;
|
||||
if (NVolLogFileEmpty(na->ni->vol)) return 0;
|
||||
|
||||
if (!NAttrNonResident(na)) {
|
||||
if (!NAttrNonResident(na))
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Resident $LogFile $DATA attribute");
|
||||
return -1;
|
||||
@ -716,16 +714,16 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
||||
memset(buf, -1, NTFS_BUF_SIZE);
|
||||
|
||||
pos = 0;
|
||||
while ((count = na->data_size - pos) > 0) {
|
||||
while ((count = na->data_size - pos) > 0)
|
||||
{
|
||||
|
||||
if (count > NTFS_BUF_SIZE)
|
||||
count = NTFS_BUF_SIZE;
|
||||
if (count > NTFS_BUF_SIZE) count = NTFS_BUF_SIZE;
|
||||
|
||||
count = ntfs_attr_pwrite(na, pos, count, buf);
|
||||
if (count <= 0) {
|
||||
if (count <= 0)
|
||||
{
|
||||
ntfs_log_perror("Failed to reset $LogFile");
|
||||
if (count != -1)
|
||||
errno = EIO;
|
||||
if (count != -1) errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
pos += count;
|
||||
|
@ -61,37 +61,47 @@
|
||||
*
|
||||
* Begins the restart area.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
||||
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
/* 0*/
|
||||
NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
||||
/* 4*/
|
||||
le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
When creating, set this to be immediately
|
||||
after this header structure (without any
|
||||
alignment). */
|
||||
/* 6*/ le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
/* 6*/
|
||||
le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
|
||||
/* 8*/ leLSN chkdsk_lsn; /* The last log file sequence number found by
|
||||
/* 8*/
|
||||
leLSN chkdsk_lsn; /* The last log file sequence number found by
|
||||
chkdsk. Only used when the magic is changed
|
||||
to "CHKD". Otherwise this is zero. */
|
||||
/* 16*/ le32 system_page_size; /* Byte size of system pages when the log file
|
||||
/* 16*/
|
||||
le32 system_page_size; /* Byte size of system pages when the log file
|
||||
was created, has to be >= 512 and a power of
|
||||
2. Use this to calculate the required size
|
||||
of the usa (usa_count) and add it to usa_ofs.
|
||||
Then verify that the result is less than the
|
||||
value of the restart_area_offset. */
|
||||
/* 20*/ le32 log_page_size; /* Byte size of log file pages, has to be >=
|
||||
/* 20*/
|
||||
le32 log_page_size; /* Byte size of log file pages, has to be >=
|
||||
512 and a power of 2. The default is 4096
|
||||
and is used when the system page size is
|
||||
between 4096 and 8192. Otherwise this is
|
||||
set to the system page size instead. */
|
||||
/* 24*/ le16 restart_area_offset;/* Byte offset from the start of this header to
|
||||
/* 24*/
|
||||
le16 restart_area_offset;/* Byte offset from the start of this header to
|
||||
the RESTART_AREA. Value has to be aligned
|
||||
to 8-byte boundary. When creating, set this
|
||||
to be after the usa. */
|
||||
/* 26*/ sle16 minor_ver; /* Log file minor version. Only check if major
|
||||
/* 26*/
|
||||
sle16 minor_ver; /* Log file minor version. Only check if major
|
||||
version is 1. */
|
||||
/* 28*/ sle16 major_ver; /* Log file major version. We only support
|
||||
/* 28*/
|
||||
sle16 major_ver; /* Log file major version. We only support
|
||||
version 1.1. */
|
||||
/* sizeof() = 30 (0x1e) bytes */
|
||||
}__attribute__((__packed__)) RESTART_PAGE_HEADER;
|
||||
@ -108,9 +118,10 @@ typedef struct {
|
||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||
* information about the log file in which they are present.
|
||||
*/
|
||||
enum {
|
||||
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002),
|
||||
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
|
||||
enum
|
||||
{
|
||||
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002), RESTART_SPACE_FILLER = 0xffff,
|
||||
/* gcc: Force enum bit width to 16. */
|
||||
}__attribute__((__packed__));
|
||||
|
||||
typedef le16 RESTART_AREA_FLAGS;
|
||||
@ -122,18 +133,22 @@ typedef le16 RESTART_AREA_FLAGS;
|
||||
* RESTART_PAGE_HEADER to the restart_area_offset value found in it.
|
||||
* See notes at restart_area_offset above.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||
/* 0*/
|
||||
leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||
when the restart area was last written.
|
||||
This happens often but what is the interval?
|
||||
Is it just fixed time or is it every time a
|
||||
check point is written or something else?
|
||||
On create set to 0. */
|
||||
/* 8*/ le16 log_clients; /* Number of log client records in the array of
|
||||
/* 8*/
|
||||
le16 log_clients; /* Number of log client records in the array of
|
||||
log client records which follows this
|
||||
restart area. Must be 1. */
|
||||
/* 10*/ le16 client_free_list; /* The index of the first free log client record
|
||||
/* 10*/
|
||||
le16 client_free_list; /* The index of the first free log client record
|
||||
in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means that there are no
|
||||
free log client records in the array.
|
||||
@ -149,7 +164,8 @@ typedef struct {
|
||||
and presumably later, the logfile is always
|
||||
open, even on clean shutdown so this should
|
||||
always be LOGFILE_NO_CLIENT. */
|
||||
/* 12*/ le16 client_in_use_list;/* The index of the first in-use log client
|
||||
/* 12*/
|
||||
le16 client_in_use_list;/* The index of the first in-use log client
|
||||
record in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means that there are no
|
||||
in-use log client records in the array. If
|
||||
@ -166,7 +182,8 @@ typedef struct {
|
||||
presumably later, the logfile is always
|
||||
open, even on clean shutdown so this should
|
||||
always be 0. */
|
||||
/* 14*/ RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k
|
||||
/* 14*/
|
||||
RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k
|
||||
and presumably earlier this is always 0. On
|
||||
WinXP and presumably later, if the logfile
|
||||
was shutdown cleanly, the second bit,
|
||||
@ -182,13 +199,15 @@ typedef struct {
|
||||
clean. If on the other hand the logfile is
|
||||
open and this bit is clear, we can be almost
|
||||
certain that the logfile is dirty. */
|
||||
/* 16*/ le32 seq_number_bits; /* How many bits to use for the sequence
|
||||
/* 16*/
|
||||
le32 seq_number_bits; /* How many bits to use for the sequence
|
||||
number. This is calculated as 67 - the
|
||||
number of bits required to store the logfile
|
||||
size in bytes and this can be used in with
|
||||
the specified file_size as a consistency
|
||||
check. */
|
||||
/* 20*/ le16 restart_area_length;/* Length of the restart area including the
|
||||
/* 20*/
|
||||
le16 restart_area_length;/* Length of the restart area including the
|
||||
client array. Following checks required if
|
||||
version matches. Otherwise, skip them.
|
||||
restart_area_offset + restart_area_length
|
||||
@ -196,7 +215,8 @@ typedef struct {
|
||||
restart_area_length has to be >=
|
||||
client_array_offset + (log_clients *
|
||||
sizeof(log client record)). */
|
||||
/* 22*/ le16 client_array_offset;/* Offset from the start of this record to
|
||||
/* 22*/
|
||||
le16 client_array_offset;/* Offset from the start of this record to
|
||||
the first log client record if versions are
|
||||
matched. When creating, set this to be
|
||||
after this restart area structure, aligned
|
||||
@ -218,7 +238,8 @@ typedef struct {
|
||||
the client array. This probably means that
|
||||
the RESTART_AREA record is actually bigger
|
||||
in WinXP and later. */
|
||||
/* 24*/ sle64 file_size; /* Usable byte size of the log file. If the
|
||||
/* 24*/
|
||||
sle64 file_size; /* Usable byte size of the log file. If the
|
||||
restart_area_offset + the offset of the
|
||||
file_size are > 510 then corruption has
|
||||
occurred. This is the very first check when
|
||||
@ -231,10 +252,12 @@ typedef struct {
|
||||
then it has to be at least big enough to
|
||||
store the two restart pages and 48 (0x30)
|
||||
log record pages. */
|
||||
/* 32*/ le32 last_lsn_data_length;/* Length of data of last LSN, not including
|
||||
/* 32*/
|
||||
le32 last_lsn_data_length;/* Length of data of last LSN, not including
|
||||
the log record header. On create set to
|
||||
0. */
|
||||
/* 36*/ le16 log_record_header_length;/* Byte size of the log record header.
|
||||
/* 36*/
|
||||
le16 log_record_header_length;/* Byte size of the log record header.
|
||||
If the version matches then check that the
|
||||
value of log_record_header_length is a
|
||||
multiple of 8, i.e.
|
||||
@ -242,17 +265,20 @@ typedef struct {
|
||||
log_record_header_length. When creating set
|
||||
it to sizeof(LOG_RECORD_HEADER), aligned to
|
||||
8 bytes. */
|
||||
/* 38*/ le16 log_page_data_offset;/* Offset to the start of data in a log record
|
||||
/* 38*/
|
||||
le16 log_page_data_offset;/* Offset to the start of data in a log record
|
||||
page. Must be a multiple of 8. On create
|
||||
set it to immediately after the update
|
||||
sequence array of the log record page. */
|
||||
/* 40*/ le32 restart_log_open_count;/* A counter that gets incremented every
|
||||
/* 40*/
|
||||
le32 restart_log_open_count;/* A counter that gets incremented every
|
||||
time the logfile is restarted which happens
|
||||
at mount time when the logfile is opened.
|
||||
When creating set to a random value. Win2k
|
||||
sets it to the low 32 bits of the current
|
||||
system time in NTFS format (see time.h). */
|
||||
/* 44*/ le32 reserved; /* Reserved/alignment to 8-byte boundary. */
|
||||
/* 44*/
|
||||
le32 reserved; /* Reserved/alignment to 8-byte boundary. */
|
||||
/* sizeof() = 48 (0x30) bytes */
|
||||
}__attribute__((__packed__)) RESTART_AREA;
|
||||
|
||||
@ -262,36 +288,45 @@ typedef struct {
|
||||
* The offset of this record is found by adding the offset of the
|
||||
* RESTART_AREA to the client_array_offset value found in it.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||
/* 0*/
|
||||
leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||
set to 0. */
|
||||
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||
/* 8*/
|
||||
leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||
the volume, i.e. the current position within
|
||||
the log file. At present, if clean this
|
||||
should = current_lsn in restart area but it
|
||||
probably also = current_lsn when dirty most
|
||||
of the time. At create set to 0. */
|
||||
/* 16*/ le16 prev_client; /* The offset to the previous log client record
|
||||
/* 16*/
|
||||
le16 prev_client; /* The offset to the previous log client record
|
||||
in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there is no previous
|
||||
client record, i.e. this is the first one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 18*/ le16 next_client; /* The offset to the next log client record in
|
||||
/* 18*/
|
||||
le16 next_client; /* The offset to the next log client record in
|
||||
the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there are no next
|
||||
client records, i.e. this is the last one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
|
||||
/* 20*/
|
||||
le16 seq_number; /* On Win2k and presumably earlier, this is set
|
||||
to zero every time the logfile is restarted
|
||||
and it is incremented when the logfile is
|
||||
closed at dismount time. Thus it is 0 when
|
||||
dirty and 1 when clean. On WinXP and
|
||||
presumably later, this is always 0. */
|
||||
/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
|
||||
/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
|
||||
/* 22*/
|
||||
u8 reserved[6]; /* Reserved/alignment. */
|
||||
/* 28*/
|
||||
le32 client_name_length;/* Length of client name in bytes. Should
|
||||
always be 8. */
|
||||
/* 32*/ ntfschar client_name[64];/* Name of the client in Unicode. Should
|
||||
/* 32*/
|
||||
ntfschar client_name[64];/* Name of the client in Unicode. Should
|
||||
always be "NTFS" with the remaining bytes
|
||||
set to 0. */
|
||||
/* sizeof() = 160 (0xa0) bytes */
|
||||
@ -305,7 +340,8 @@ typedef struct {
|
||||
* following update sequence array and then aligned to 8 byte boundary, but is
|
||||
* this specified anywhere?).
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
||||
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
@ -314,15 +350,18 @@ typedef struct {
|
||||
alignment). */
|
||||
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
|
||||
union {
|
||||
union
|
||||
{
|
||||
LSN last_lsn;
|
||||
s64 file_offset;
|
||||
}__attribute__((__packed__)) copy;
|
||||
u32 flags;
|
||||
u16 page_count;
|
||||
u16 page_position;
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 next_record_offset;
|
||||
u8 reserved[6];
|
||||
LSN last_end_lsn;
|
||||
@ -335,7 +374,8 @@ typedef struct {
|
||||
*
|
||||
* (Or is it log record pages?)
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */
|
||||
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
||||
/* This has nothing to do with the log record. It is only so
|
||||
@ -345,7 +385,8 @@ typedef enum {
|
||||
/**
|
||||
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
u16 seq_number;
|
||||
u16 client_index;
|
||||
}__attribute__((__packed__)) LOG_CLIENT_ID;
|
||||
@ -355,7 +396,8 @@ typedef struct {
|
||||
*
|
||||
* Each log record seems to have a constant size of 0x70 bytes.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
LSN this_lsn;
|
||||
LSN client_previous_lsn;
|
||||
LSN client_undo_next_lsn;
|
||||
@ -381,7 +423,8 @@ typedef struct {
|
||||
u32 alignment_or_reserved;
|
||||
VCN target_vcn;
|
||||
/* Now at ofs 0x50. */
|
||||
struct { /* Only present if lcns_to_follow
|
||||
struct
|
||||
{ /* Only present if lcns_to_follow
|
||||
is not 0. */
|
||||
LCN lcn;
|
||||
}__attribute__((__packed__)) lcn_list[0];
|
||||
|
@ -67,7 +67,8 @@ static int tab;
|
||||
* @flags: Flags which affect the output style
|
||||
* @handler: Function to perform the actual logging
|
||||
*/
|
||||
struct ntfs_logging {
|
||||
struct ntfs_logging
|
||||
{
|
||||
u32 levels;
|
||||
u32 flags;
|
||||
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
|
||||
@ -82,10 +83,8 @@ static struct ntfs_logging ntfs_log = {
|
||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
||||
NTFS_LOG_LEVEL_LEAVE |
|
||||
#endif
|
||||
NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING |
|
||||
NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL |
|
||||
NTFS_LOG_LEVEL_PROGRESS,
|
||||
NTFS_LOG_FLAG_ONLYNAME,
|
||||
NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING | NTFS_LOG_LEVEL_ERROR
|
||||
| NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | NTFS_LOG_LEVEL_PROGRESS, NTFS_LOG_FLAG_ONLYNAME,
|
||||
#ifdef DEBUG
|
||||
ntfs_log_handler_outerr
|
||||
#else
|
||||
@ -93,7 +92,6 @@ static struct ntfs_logging ntfs_log = {
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_get_levels - Get a list of the current logging levels
|
||||
*
|
||||
@ -140,7 +138,6 @@ u32 ntfs_log_clear_levels(u32 levels)
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_get_flags - Get a list of logging style flags
|
||||
*
|
||||
@ -187,7 +184,6 @@ u32 ntfs_log_clear_flags(u32 flags)
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_get_stream - Default output streams for logging levels
|
||||
* @level: Log level
|
||||
@ -201,7 +197,8 @@ static FILE * ntfs_log_get_stream(u32 level)
|
||||
{
|
||||
FILE *stream;
|
||||
|
||||
switch (level) {
|
||||
switch (level)
|
||||
{
|
||||
case NTFS_LOG_LEVEL_INFO:
|
||||
case NTFS_LOG_LEVEL_QUIET:
|
||||
case NTFS_LOG_LEVEL_PROGRESS:
|
||||
@ -237,7 +234,8 @@ static const char * ntfs_log_get_prefix(u32 level)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
switch (level) {
|
||||
switch (level)
|
||||
{
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
prefix = "DEBUG: ";
|
||||
break;
|
||||
@ -276,7 +274,6 @@ static const char * ntfs_log_get_prefix(u32 level)
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_set_handler - Provide an alternate logging handler
|
||||
* @handler: function to perform the logging
|
||||
@ -286,14 +283,15 @@ static const char * ntfs_log_get_prefix(u32 level)
|
||||
*/
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler)
|
||||
{
|
||||
if (handler) {
|
||||
if (handler)
|
||||
{
|
||||
ntfs_log.handler = handler;
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
if (handler == ntfs_log_handler_syslog)
|
||||
openlog("ntfs-3g", LOG_PID, LOG_USER);
|
||||
#endif
|
||||
} else
|
||||
ntfs_log.handler = ntfs_log_handler_null;
|
||||
}
|
||||
else ntfs_log.handler = ntfs_log_handler_null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,8 +311,7 @@ void ntfs_log_set_handler(ntfs_log_handler *handler)
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_redirect(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, ...)
|
||||
int ntfs_log_redirect(const char *function, const char *file, int line, u32 level, void *data, const char *format, ...)
|
||||
{
|
||||
int olderr = errno;
|
||||
int ret;
|
||||
@ -332,7 +329,6 @@ int ntfs_log_redirect(const char *function, const char *file,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_syslog - syslog logging handler
|
||||
* @function: Function in which the log line occurred
|
||||
@ -350,7 +346,6 @@ int ntfs_log_redirect(const char *function, const char *file,
|
||||
* num Number of output characters
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
|
||||
#define LOG_LINE_LEN 512
|
||||
@ -369,13 +364,15 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
return 1;
|
||||
#endif
|
||||
ret = vsnprintf(logbuf, LOG_LINE_LEN, format, args);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
{
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR))
|
||||
{
|
||||
strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1);
|
||||
strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3));
|
||||
ret = strlen(logbuf);
|
||||
@ -409,8 +406,8 @@ out:
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
int ntfs_log_handler_fprintf(const char *function, const char *file, int line, u32 level, void *data,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
@ -424,7 +421,8 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
stream = (FILE*) data;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (level == NTFS_LOG_LEVEL_LEAVE) {
|
||||
if (level == NTFS_LOG_LEVEL_LEAVE)
|
||||
{
|
||||
if (tab)
|
||||
tab--;
|
||||
return 0;
|
||||
@ -433,8 +431,7 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
for (i = 0; i < tab; i++)
|
||||
ret += fprintf(stream, " ");
|
||||
#endif
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) && (strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
file = strrchr(file, PATH_SEP) + 1;
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */
|
||||
@ -447,13 +444,11 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
ret += fprintf(stream, "(%d) ", line);
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
|
||||
(level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER))
|
||||
ret += fprintf(stream, "%s(): ", function);
|
||||
(level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER)) ret += fprintf(stream, "%s(): ", function);
|
||||
|
||||
ret += vfprintf(stream, format, args);
|
||||
|
||||
if (level & NTFS_LOG_LEVEL_PERROR)
|
||||
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
if (level & NTFS_LOG_LEVEL_PERROR) ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
|
||||
#ifdef DEBUG
|
||||
if (level == NTFS_LOG_LEVEL_ENTER)
|
||||
@ -479,9 +474,8 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
*
|
||||
* Returns: 0 Message wasn't logged
|
||||
*/
|
||||
int ntfs_log_handler_null(const char *function __attribute__((unused)), const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), u32 level __attribute__((unused)), void *data __attribute__((unused)),
|
||||
const char *format __attribute__((unused)), va_list args __attribute__((unused)))
|
||||
int ntfs_log_handler_null(const char *function __attribute__((unused)), const char *file __attribute__((unused)), int line __attribute__((unused)), u32 level __attribute__((unused)), void *data __attribute__((unused)), const char *format __attribute__((unused)),
|
||||
va_list args __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -507,11 +501,10 @@ int ntfs_log_handler_null(const char *function __attribute__((unused)), const ch
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_stdout(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
int ntfs_log_handler_stdout(const char *function, const char *file, int line, u32 level, void *data,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
if (!data)
|
||||
data = stdout;
|
||||
if (!data) data = stdout;
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
@ -538,11 +531,10 @@ int ntfs_log_handler_stdout(const char *function, const char *file,
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_outerr(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
int ntfs_log_handler_outerr(const char *function, const char *file, int line, u32 level, void *data,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
if (!data)
|
||||
data = ntfs_log_get_stream(level);
|
||||
if (!data) data = ntfs_log_get_stream(level);
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
@ -568,16 +560,14 @@ int ntfs_log_handler_outerr(const char *function, const char *file,
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
int ntfs_log_handler_stderr(const char *function, const char *file, int line, u32 level, void *data,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
if (!data)
|
||||
data = stderr;
|
||||
if (!data) data = stderr;
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_parse_option - Act upon command line options
|
||||
* @option: Option flag
|
||||
@ -593,16 +583,23 @@ int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||
*/
|
||||
BOOL ntfs_log_parse_option(const char *option)
|
||||
{
|
||||
if (strcmp(option, "--log-debug") == 0) {
|
||||
if (strcmp(option, "--log-debug") == 0)
|
||||
{
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-verbose") == 0) {
|
||||
}
|
||||
else if (strcmp(option, "--log-verbose") == 0)
|
||||
{
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-quiet") == 0) {
|
||||
}
|
||||
else if (strcmp(option, "--log-quiet") == 0)
|
||||
{
|
||||
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-trace") == 0) {
|
||||
}
|
||||
else if (strcmp(option, "--log-trace") == 0)
|
||||
{
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -34,8 +34,8 @@
|
||||
#include "types.h"
|
||||
|
||||
/* Function prototype for the logging handlers */
|
||||
typedef int (ntfs_log_handler)(const char *function, const char *file, int line,
|
||||
u32 level, void *data, const char *format, va_list args);
|
||||
typedef int ( ntfs_log_handler)(const char *function, const char *file, int line, u32 level, void *data,
|
||||
const char *format, va_list args);
|
||||
|
||||
/* Set the logging handler from one of the functions, below. */
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler
|
||||
@ -62,8 +62,7 @@ u32 ntfs_log_get_flags(void);
|
||||
/* Turn command-line options into logging flags */
|
||||
BOOL ntfs_log_parse_option(const char *option);
|
||||
|
||||
int ntfs_log_redirect(const char *function, const char *file, int line,
|
||||
u32 level, void *data, const char *format, ...)
|
||||
int ntfs_log_redirect(const char *function, const char *file, int line, u32 level, void *data, const char *format, ...)
|
||||
__attribute__((format(printf, 6, 7)));
|
||||
|
||||
/* Logging levels - Determine what gets logged */
|
||||
|
@ -24,11 +24,13 @@
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static inline void* ntfs_alloc (size_t size) {
|
||||
static inline void* ntfs_alloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static inline void* ntfs_align (size_t size) {
|
||||
static inline void* ntfs_align(size_t size)
|
||||
{
|
||||
#ifdef __wii__
|
||||
return memalign(32, size);
|
||||
#else
|
||||
@ -36,7 +38,8 @@ static inline void* ntfs_align (size_t size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ntfs_free (void* mem) {
|
||||
static inline void ntfs_free(void* mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,8 +29,7 @@
|
||||
#include "layout.h"
|
||||
#include "logging.h"
|
||||
|
||||
extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||
const s64 count, MFT_RECORD *b);
|
||||
extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, const s64 count, MFT_RECORD *b);
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_read - read a record from the mft
|
||||
@ -47,8 +46,7 @@ extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||
*
|
||||
* NOTE: @b has to be at least of size vol->mft_record_size.
|
||||
*/
|
||||
static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol,
|
||||
const MFT_REF mref, MFT_RECORD *b)
|
||||
static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol, const MFT_REF mref, MFT_RECORD *b)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -58,14 +56,11 @@ static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol,
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD *m);
|
||||
extern int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref, MFT_RECORD *m);
|
||||
|
||||
extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD **mrec, ATTR_RECORD **attr);
|
||||
extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, MFT_RECORD **mrec, ATTR_RECORD **attr);
|
||||
|
||||
extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
||||
const s64 count, MFT_RECORD *b);
|
||||
extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, const s64 count, MFT_RECORD *b);
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_write - write an mft record to disk
|
||||
@ -82,8 +77,7 @@ extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
||||
*
|
||||
* NOTE: @b has to be at least of size vol->mft_record_size.
|
||||
*/
|
||||
static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol,
|
||||
const MFT_REF mref, MFT_RECORD *b)
|
||||
static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol, const MFT_REF mref, MFT_RECORD *b)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -111,14 +105,12 @@ static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol,
|
||||
*/
|
||||
static __inline__ u32 ntfs_mft_record_get_data_size(const MFT_RECORD *m)
|
||||
{
|
||||
if (!m || !ntfs_is_mft_record(m->magic))
|
||||
return 0;
|
||||
if (!m || !ntfs_is_mft_record(m->magic)) return 0;
|
||||
/* Get the number of used bytes and return it. */
|
||||
return le32_to_cpu(m->bytes_in_use);
|
||||
}
|
||||
|
||||
extern int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD *mrec);
|
||||
extern int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref, MFT_RECORD *mrec);
|
||||
|
||||
extern int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref);
|
||||
|
||||
|
@ -45,8 +45,7 @@ void *ntfs_calloc(size_t size)
|
||||
void *p;
|
||||
|
||||
p = calloc(1, size);
|
||||
if (!p)
|
||||
ntfs_log_perror("Failed to calloc %lld bytes", (long long)size);
|
||||
if (!p) ntfs_log_perror("Failed to calloc %lld bytes", (long long)size);
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -55,7 +54,6 @@ void *ntfs_malloc(size_t size)
|
||||
void *p;
|
||||
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
ntfs_log_perror("Failed to malloc %lld bytes", (long long)size);
|
||||
if (!p) ntfs_log_perror("Failed to malloc %lld bytes", (long long)size);
|
||||
return p;
|
||||
}
|
||||
|
@ -59,9 +59,9 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 || (u32) (usa_ofs + (usa_count * 2)) > size || (size
|
||||
>> NTFS_BLOCK_SIZE_BITS) != usa_count)
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d "
|
||||
"usa_count: %d", __FUNCTION__, *(le32 *)b,
|
||||
@ -85,8 +85,10 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
/*
|
||||
* Check for incomplete multi sector transfer(s).
|
||||
*/
|
||||
while (usa_count--) {
|
||||
if (*data_pos != usn) {
|
||||
while (usa_count--)
|
||||
{
|
||||
if (*data_pos != usn)
|
||||
{
|
||||
/*
|
||||
* Incomplete multi sector transfer detected! )-:
|
||||
* Set the magic to "BAAD" and return failure.
|
||||
@ -106,7 +108,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
data_pos = (u16*) b + NTFS_BLOCK_SIZE / sizeof(u16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (usa_count--)
|
||||
{
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
@ -146,8 +149,8 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* Sanity check + only fixup if it makes sense. */
|
||||
if (!b || ntfs_is_baad_record(b->magic) ||
|
||||
ntfs_is_hole_record(b->magic)) {
|
||||
if (!b || ntfs_is_baad_record(b->magic) || ntfs_is_hole_record(b->magic))
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: bad argument", __FUNCTION__);
|
||||
return -1;
|
||||
@ -157,9 +160,9 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 || (u32) (usa_ofs + (usa_count * 2)) > size || (size
|
||||
>> NTFS_BLOCK_SIZE_BITS) != usa_count)
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
return -1;
|
||||
@ -171,14 +174,14 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
* (skipping 0 and -1, i.e. 0xffff).
|
||||
*/
|
||||
usn = le16_to_cpup(usa_pos) + 1;
|
||||
if (usn == 0xffff || !usn)
|
||||
usn = 1;
|
||||
if (usn == 0xffff || !usn) usn = 1;
|
||||
usn = cpu_to_le16(usn);
|
||||
*usa_pos = usn;
|
||||
/* Position in data of first u16 that needs fixing up. */
|
||||
data_pos = (u16*) b + NTFS_BLOCK_SIZE / sizeof(u16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (usa_count--)
|
||||
{
|
||||
/*
|
||||
* Increment the position in the usa and save the
|
||||
* original data from the data buffer into the usa.
|
||||
@ -217,7 +220,8 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
||||
data_pos = (u16*) b + NTFS_BLOCK_SIZE / sizeof(u16) - 1;
|
||||
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (usa_count--)
|
||||
{
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
|
@ -41,30 +41,10 @@
|
||||
#include "cache.h"
|
||||
|
||||
// NTFS device driver devoptab
|
||||
static const devoptab_t devops_ntfs = {
|
||||
NULL, /* Device name */
|
||||
sizeof (ntfs_file_state),
|
||||
ntfs_open_r,
|
||||
ntfs_close_r,
|
||||
ntfs_write_r,
|
||||
ntfs_read_r,
|
||||
ntfs_seek_r,
|
||||
ntfs_fstat_r,
|
||||
ntfs_stat_r,
|
||||
ntfs_link_r,
|
||||
ntfs_unlink_r,
|
||||
ntfs_chdir_r,
|
||||
ntfs_rename_r,
|
||||
ntfs_mkdir_r,
|
||||
sizeof (ntfs_dir_state),
|
||||
ntfs_diropen_r,
|
||||
ntfs_dirreset_r,
|
||||
ntfs_dirnext_r,
|
||||
ntfs_dirclose_r,
|
||||
ntfs_statvfs_r,
|
||||
ntfs_ftruncate_r,
|
||||
ntfs_fsync_r,
|
||||
NULL /* Device data */
|
||||
static const devoptab_t devops_ntfs = { NULL, /* Device name */
|
||||
sizeof(ntfs_file_state), ntfs_open_r, ntfs_close_r, ntfs_write_r, ntfs_read_r, ntfs_seek_r, ntfs_fstat_r, ntfs_stat_r,
|
||||
ntfs_link_r, ntfs_unlink_r, ntfs_chdir_r, ntfs_rename_r, ntfs_mkdir_r, sizeof(ntfs_dir_state), ntfs_diropen_r,
|
||||
ntfs_dirreset_r, ntfs_dirnext_r, ntfs_dirclose_r, ntfs_statvfs_r, ntfs_ftruncate_r, ntfs_fsync_r, NULL /* Device data */
|
||||
};
|
||||
|
||||
void ntfsInit(void)
|
||||
@ -72,7 +52,8 @@ void ntfsInit (void)
|
||||
static bool isInit = false;
|
||||
|
||||
// Initialise ntfs-3g (if not already done so)
|
||||
if (!isInit) {
|
||||
if (!isInit)
|
||||
{
|
||||
isInit = true;
|
||||
|
||||
// Set the log handler
|
||||
@ -98,7 +79,8 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
sec_t part_lba = 0;
|
||||
int i;
|
||||
|
||||
union {
|
||||
union
|
||||
{
|
||||
u8 buffer[512];
|
||||
MASTER_BOOT_RECORD mbr;
|
||||
EXTENDED_BOOT_RECORD ebr;
|
||||
@ -106,38 +88,43 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
} sector;
|
||||
|
||||
// Sanity check
|
||||
if (!interface) {
|
||||
if (!interface)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!partitions)
|
||||
return 0;
|
||||
if (!partitions) return 0;
|
||||
|
||||
// Initialise ntfs-3g
|
||||
ntfsInit();
|
||||
|
||||
// Start the device and check that it is inserted
|
||||
if (!interface->startup()) {
|
||||
if (!interface->startup())
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (!interface->isInserted()) {
|
||||
if (!interface->isInserted())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read the first sector on the device
|
||||
if (!interface->readSectors(0, 1, §or.buffer)) {
|
||||
if (!interface->readSectors(0, 1, §or.buffer))
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If this is the devices master boot record
|
||||
if (sector.mbr.signature == MBR_SIGNATURE) {
|
||||
if (sector.mbr.signature == MBR_SIGNATURE)
|
||||
{
|
||||
memcpy(&mbr, §or, sizeof(MASTER_BOOT_RECORD));
|
||||
ntfs_log_debug("Valid Master Boot Record found\n");
|
||||
|
||||
// Search the partition table for all NTFS partitions (max. 4 primary partitions)
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
partition = &mbr.partitions[i];
|
||||
part_lba = le32_to_cpu(mbr.partitions[i].lba_start);
|
||||
|
||||
@ -146,25 +133,32 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
part_lba, partition->type);
|
||||
|
||||
// Figure out what type of partition this is
|
||||
switch (partition->type) {
|
||||
switch (partition->type)
|
||||
{
|
||||
|
||||
// Ignore empty partitions
|
||||
case PARTITION_TYPE_EMPTY:
|
||||
continue;
|
||||
|
||||
// NTFS partition
|
||||
case PARTITION_TYPE_NTFS: {
|
||||
case PARTITION_TYPE_NTFS:
|
||||
{
|
||||
ntfs_log_debug("Partition %i: Claims to be NTFS\n", i + 1);
|
||||
|
||||
// Read and validate the NTFS partition
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
if (interface->readSectors(part_lba, 1, §or))
|
||||
{
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID)
|
||||
{
|
||||
ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if (partition_count < NTFS_MAX_PARTITIONS)
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug("Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1);
|
||||
}
|
||||
}
|
||||
@ -175,17 +169,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
|
||||
// DOS 3.3+ or Windows 95 extended partition
|
||||
case PARTITION_TYPE_DOS33_EXTENDED:
|
||||
case PARTITION_TYPE_WIN95_EXTENDED: {
|
||||
case PARTITION_TYPE_WIN95_EXTENDED:
|
||||
{
|
||||
ntfs_log_debug("Partition %i: Claims to be Extended\n", i + 1);
|
||||
|
||||
// Walk the extended partition chain, finding all NTFS partitions within it
|
||||
sec_t ebr_lba = part_lba;
|
||||
sec_t next_erb_lba = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
|
||||
// Read and validate the extended boot record
|
||||
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or)) {
|
||||
if (sector.ebr.signature == EBR_SIGNATURE) {
|
||||
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or))
|
||||
{
|
||||
if (sector.ebr.signature == EBR_SIGNATURE)
|
||||
{
|
||||
ntfs_log_debug("Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
||||
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||
sector.ebr.partition.type);
|
||||
@ -196,20 +194,26 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
next_erb_lba = le32_to_cpu(sector.ebr.next_ebr.lba_start);
|
||||
|
||||
// Check if this partition has a valid NTFS boot record
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
if (interface->readSectors(part_lba, 1, §or))
|
||||
{
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID)
|
||||
{
|
||||
ntfs_log_debug("Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba);
|
||||
if(sector.ebr.partition.type != PARTITION_TYPE_NTFS) {
|
||||
if (sector.ebr.partition.type != PARTITION_TYPE_NTFS)
|
||||
{
|
||||
ntfs_log_warning("Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS);
|
||||
}
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if (partition_count < NTFS_MAX_PARTITIONS)
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
next_erb_lba = 0;
|
||||
}
|
||||
}
|
||||
@ -221,17 +225,22 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
}
|
||||
|
||||
// Unknown or unsupported partition type
|
||||
default: {
|
||||
default:
|
||||
{
|
||||
|
||||
// Check if this partition has a valid NTFS boot record anyway,
|
||||
// it might be misrepresented due to a lazy partition editor
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
if (interface->readSectors(part_lba, 1, §or))
|
||||
{
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID)
|
||||
{
|
||||
ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
|
||||
if(partition->type != PARTITION_TYPE_NTFS) {
|
||||
if (partition->type != PARTITION_TYPE_NTFS)
|
||||
{
|
||||
ntfs_log_warning("Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS);
|
||||
}
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if (partition_count < NTFS_MAX_PARTITIONS)
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
@ -247,15 +256,21 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
}
|
||||
|
||||
// Else it is assumed this device has no master boot record
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug("No Master Boot Record was found!\n");
|
||||
|
||||
// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (interface->readSectors(i, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
if (interface->readSectors(i, 1, §or))
|
||||
{
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID)
|
||||
{
|
||||
ntfs_log_debug("Valid NTFS boot sector found at sector %d!\n", i);
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
if (partition_count < NTFS_MAX_PARTITIONS)
|
||||
{
|
||||
partition_starts[partition_count] = i;
|
||||
partition_count++;
|
||||
}
|
||||
@ -269,9 +284,11 @@ int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
/*interface->shutdown();*/
|
||||
|
||||
// Return the found partitions (if any)
|
||||
if (partition_count > 0) {
|
||||
if (partition_count > 0)
|
||||
{
|
||||
*partitions = (sec_t*) ntfs_alloc(sizeof(sec_t) * partition_count);
|
||||
if (*partitions) {
|
||||
if (*partitions)
|
||||
{
|
||||
memcpy(*partitions, &partition_starts, sizeof(sec_t) * partition_count);
|
||||
return partition_count;
|
||||
}
|
||||
@ -295,16 +312,21 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
||||
ntfsInit();
|
||||
|
||||
// Find and mount all NTFS partitions on all known devices
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++)
|
||||
{
|
||||
disc = &discs[i];
|
||||
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
||||
if (partition_count > 0 && partitions) {
|
||||
for (j = 0, k = 0; j < partition_count; j++) {
|
||||
if (partition_count > 0 && partitions)
|
||||
{
|
||||
for (j = 0, k = 0; j < partition_count; j++)
|
||||
{
|
||||
|
||||
// Find the next unused mount name
|
||||
do {
|
||||
do
|
||||
{
|
||||
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
||||
if (k >= NTFS_MAX_MOUNTS) {
|
||||
if (k >= NTFS_MAX_MOUNTS)
|
||||
{
|
||||
ntfs_free(partitions);
|
||||
errno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
@ -312,8 +334,11 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
||||
} while (ntfsGetDevice(name, false));
|
||||
|
||||
// Mount the partition
|
||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||
if (mount_count < NTFS_MAX_MOUNTS)
|
||||
{
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE,
|
||||
CACHE_DEFAULT_PAGE_COUNT, flags))
|
||||
{
|
||||
strcpy(mount_points[mount_count].name, name);
|
||||
mount_points[mount_count].interface = disc->interface;
|
||||
mount_points[mount_count].startSector = partitions[j];
|
||||
@ -327,9 +352,11 @@ int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
||||
}
|
||||
|
||||
// Return the mounts (if any)
|
||||
if (mount_count > 0 && mounts) {
|
||||
if (mount_count > 0 && mounts)
|
||||
{
|
||||
*mounts = (ntfs_md*) ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
||||
if (*mounts) {
|
||||
if (*mounts)
|
||||
{
|
||||
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
||||
return mount_count;
|
||||
}
|
||||
@ -350,7 +377,8 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
||||
int i, j, k;
|
||||
|
||||
// Sanity check
|
||||
if (!interface) {
|
||||
if (!interface)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -359,17 +387,23 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
||||
ntfsInit();
|
||||
|
||||
// Find the specified device then find and mount all NTFS partitions on it
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
||||
if (discs[i].interface == interface) {
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++)
|
||||
{
|
||||
if (discs[i].interface == interface)
|
||||
{
|
||||
disc = &discs[i];
|
||||
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
||||
if (partition_count > 0 && partitions) {
|
||||
for (j = 0, k = 0; j < partition_count; j++) {
|
||||
if (partition_count > 0 && partitions)
|
||||
{
|
||||
for (j = 0, k = 0; j < partition_count; j++)
|
||||
{
|
||||
|
||||
// Find the next unused mount name
|
||||
do {
|
||||
do
|
||||
{
|
||||
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
||||
if (k >= NTFS_MAX_MOUNTS) {
|
||||
if (k >= NTFS_MAX_MOUNTS)
|
||||
{
|
||||
ntfs_free(partitions);
|
||||
errno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
@ -377,8 +411,11 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
||||
} while (ntfsGetDevice(name, false));
|
||||
|
||||
// Mount the partition
|
||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||
if (mount_count < NTFS_MAX_MOUNTS)
|
||||
{
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE,
|
||||
CACHE_DEFAULT_PAGE_COUNT, flags))
|
||||
{
|
||||
strcpy(mount_points[mount_count].name, name);
|
||||
mount_points[mount_count].interface = disc->interface;
|
||||
mount_points[mount_count].startSector = partitions[j];
|
||||
@ -394,15 +431,18 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
||||
}
|
||||
|
||||
// If we couldn't find the device then return with error status
|
||||
if (!disc) {
|
||||
if (!disc)
|
||||
{
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return the mounts (if any)
|
||||
if (mount_count > 0 && mounts) {
|
||||
if (mount_count > 0 && mounts)
|
||||
{
|
||||
*mounts = (ntfs_md*) ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
||||
if (*mounts) {
|
||||
if (*mounts)
|
||||
{
|
||||
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
||||
return mount_count;
|
||||
}
|
||||
@ -411,13 +451,15 @@ int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flag
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags)
|
||||
bool ntfsMount(const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount,
|
||||
u32 cachePageSize, u32 flags)
|
||||
{
|
||||
ntfs_vd *vd = NULL;
|
||||
gekko_fd *fd = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!name || !interface) {
|
||||
if (!name || !interface)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
@ -426,20 +468,23 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
ntfsInit();
|
||||
|
||||
// Check that the requested mount name is free
|
||||
if (ntfsGetDevice(name, false)) {
|
||||
if (ntfsGetDevice(name, false))
|
||||
{
|
||||
errno = EADDRINUSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we can at least read from this device
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANREAD)) {
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANREAD))
|
||||
{
|
||||
errno = EPERM;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the volume descriptor
|
||||
vd = (ntfs_vd*) ntfs_alloc(sizeof(ntfs_vd));
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@ -457,7 +502,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
|
||||
// Allocate the device driver descriptor
|
||||
fd = (gekko_fd*) ntfs_alloc(sizeof(gekko_fd));
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
ntfs_free(vd);
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
@ -473,7 +519,8 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
|
||||
// Allocate the device driver
|
||||
vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_gekko_io_ops, fd);
|
||||
if (!vd->dev) {
|
||||
if (!vd->dev)
|
||||
{
|
||||
ntfs_free(fd);
|
||||
ntfs_free(vd);
|
||||
return false;
|
||||
@ -484,46 +531,56 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
vd->flags |= MS_RDONLY;
|
||||
else
|
||||
{
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||
vd->flags |= MS_RDONLY;
|
||||
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||
vd->flags |= MS_EXCLUSIVE;
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANWRITE)) vd->flags |= MS_RDONLY;
|
||||
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE)) vd->flags
|
||||
|= MS_EXCLUSIVE;
|
||||
}
|
||||
if (flags & NTFS_RECOVER)
|
||||
vd->flags |= MS_RECOVER;
|
||||
if (flags & NTFS_IGNORE_HIBERFILE)
|
||||
vd->flags |= MS_IGNORE_HIBERFILE;
|
||||
if (flags & NTFS_RECOVER) vd->flags |= MS_RECOVER;
|
||||
if (flags & NTFS_IGNORE_HIBERFILE) vd->flags |= MS_IGNORE_HIBERFILE;
|
||||
|
||||
if (vd->flags & MS_RDONLY)
|
||||
ntfs_log_debug("Mounting \"%s\" as read-only\n", name);
|
||||
|
||||
// Mount the device
|
||||
vd->vol = ntfs_device_mount(vd->dev, vd->flags);
|
||||
if (!vd->vol) {
|
||||
switch(ntfs_volume_error(errno)) {
|
||||
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
||||
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
||||
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
||||
case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break;
|
||||
default: errno = EINVAL; break;
|
||||
if (!vd->vol)
|
||||
{
|
||||
switch (ntfs_volume_error(errno))
|
||||
{
|
||||
case NTFS_VOLUME_NOT_NTFS:
|
||||
errno = EINVALPART;
|
||||
break;
|
||||
case NTFS_VOLUME_CORRUPT:
|
||||
errno = EINVALPART;
|
||||
break;
|
||||
case NTFS_VOLUME_HIBERNATED:
|
||||
errno = EHIBERNATED;
|
||||
break;
|
||||
case NTFS_VOLUME_UNCLEAN_UNMOUNT:
|
||||
errno = EDIRTY;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
ntfs_device_free(vd->dev);
|
||||
ntfs_free(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flags & NTFS_IGNORE_CASE)
|
||||
ntfs_set_ignore_case(vd->vol);
|
||||
if (flags & NTFS_IGNORE_CASE) ntfs_set_ignore_case(vd->vol);
|
||||
|
||||
// Initialise the volume descriptor
|
||||
if (ntfsInitVolume(vd)) {
|
||||
if (ntfsInitVolume(vd))
|
||||
{
|
||||
ntfs_umount(vd->vol, true);
|
||||
ntfs_free(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the device to the devoptab table
|
||||
if (ntfsAddDevice(name, vd)) {
|
||||
if (ntfsAddDevice(name, vd))
|
||||
{
|
||||
ntfsDeinitVolume(vd);
|
||||
ntfs_umount(vd->vol, true);
|
||||
ntfs_free(vd);
|
||||
@ -539,8 +596,7 @@ void ntfsUnmount (const char *name, bool force)
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd)
|
||||
return;
|
||||
if (!vd) return;
|
||||
|
||||
// Remove the device from the devoptab table
|
||||
ntfsRemoveDevice(name);
|
||||
@ -565,14 +621,16 @@ const char *ntfsGetVolumeName (const char *name)
|
||||
//char *volumeName = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!name) {
|
||||
if (!name)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
@ -645,14 +703,16 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
int ulabel_len;
|
||||
|
||||
// Sanity check
|
||||
if (!name) {
|
||||
if (!name)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
errno = ENODEV;
|
||||
return false;
|
||||
}
|
||||
@ -662,7 +722,8 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// Convert the new volume name to unicode
|
||||
ulabel_len = ntfsLocalToUnicode(volumeName, &ulabel) * sizeof(ntfschar);
|
||||
if (ulabel_len < 0) {
|
||||
if (ulabel_len < 0)
|
||||
{
|
||||
ntfsUnlock(vd);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
@ -670,26 +731,32 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// Check if the volume name attribute exists
|
||||
na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
|
||||
if (na) {
|
||||
if (na)
|
||||
{
|
||||
|
||||
// It does, resize it to match the length of the new volume name
|
||||
if (ntfs_attr_truncate(na, ulabel_len)) {
|
||||
if (ntfs_attr_truncate(na, ulabel_len))
|
||||
{
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the new volume name
|
||||
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
|
||||
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len)
|
||||
{
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// It doesn't, create it now
|
||||
if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) {
|
||||
if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*) ulabel, ulabel_len))
|
||||
{
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
@ -701,11 +768,11 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
vd->name[0] = '\0';
|
||||
|
||||
// Close the volume name attribute
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
if (na) ntfs_attr_close(na);
|
||||
|
||||
// Sync the volume node
|
||||
if (ntfs_inode_sync(vd->vol->vol_ni)) {
|
||||
if (ntfs_inode_sync(vd->vol->vol_ni))
|
||||
{
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
|
@ -23,7 +23,8 @@
|
||||
#define _LIBNTFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <gctypes.h>
|
||||
@ -55,7 +56,8 @@ extern "C" {
|
||||
/**
|
||||
* ntfs_md - NTFS mount descriptor
|
||||
*/
|
||||
typedef struct _ntfs_md {
|
||||
typedef struct _ntfs_md
|
||||
{
|
||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||
sec_t startSector; /* Local block address to first sector of partition */
|
||||
@ -110,7 +112,8 @@ extern int ntfsMountDevice (const DISC_INTERFACE* interface, ntfs_md **mounts, u
|
||||
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
|
||||
* @note ntfsFindPartitions should be used first to locate the partitions start sector
|
||||
*/
|
||||
extern bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags);
|
||||
extern bool ntfsMount(const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount,
|
||||
u32 cachePageSize, u32 flags);
|
||||
|
||||
/**
|
||||
* Unmount a NTFS partition.
|
||||
|
@ -50,11 +50,11 @@
|
||||
void ntfsCloseDir(ntfs_dir_state *dir)
|
||||
{
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd)
|
||||
return;
|
||||
if (!dir || !dir->vd) return;
|
||||
|
||||
// Free the directory entries (if any)
|
||||
while (dir->first) {
|
||||
while (dir->first)
|
||||
{
|
||||
ntfs_dir_entry *next = dir->first->next;
|
||||
ntfs_free(dir->first->name);
|
||||
ntfs_free(dir->first);
|
||||
@ -62,8 +62,7 @@ void ntfsCloseDir (ntfs_dir_state *dir)
|
||||
}
|
||||
|
||||
// Close the directory (if open)
|
||||
if (dir->ni)
|
||||
ntfsCloseEntry(dir->vd, dir->ni);
|
||||
if (dir->ni) ntfsCloseEntry(dir->vd, dir->ni);
|
||||
|
||||
// Reset the directory state
|
||||
dir->ni = NULL;
|
||||
@ -76,8 +75,7 @@ void ntfsCloseDir (ntfs_dir_state *dir)
|
||||
int ntfs_stat_r(struct _reent *r, const char *path, struct stat *st)
|
||||
{
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!st || !path)
|
||||
return 0;
|
||||
if (!st || !path) return 0;
|
||||
|
||||
ntfs_log_trace("path %s, st %p\n", path, st);
|
||||
|
||||
@ -86,7 +84,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -103,7 +102,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry(vd, path);
|
||||
if (!ni) {
|
||||
if (!ni)
|
||||
{
|
||||
r->_errno = errno;
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
@ -111,8 +111,7 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
|
||||
// Get the entry stats
|
||||
int ret = ntfsStat(vd, ni, st);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
if (ret) r->_errno = errno;
|
||||
|
||||
// Close the entry
|
||||
ntfsCloseEntry(vd, ni);
|
||||
@ -131,7 +130,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(existing);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -141,7 +141,8 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
|
||||
// Create a symbolic link between the two paths
|
||||
ni = ntfsCreate(vd, existing, S_IFLNK, newLink);
|
||||
if (!ni) {
|
||||
if (!ni)
|
||||
{
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -162,8 +163,7 @@ int ntfs_unlink_r (struct _reent *r, const char *name)
|
||||
|
||||
// Unlink the entry
|
||||
int ret = ntfsUnlink(ntfsGetVolume(name), name);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
if (ret) r->_errno = errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -177,7 +177,8 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -187,14 +188,16 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
|
||||
// Find the directory
|
||||
ni = ntfsOpenEntry(vd, name);
|
||||
if (!ni) {
|
||||
if (!ni)
|
||||
{
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY))
|
||||
{
|
||||
ntfsCloseEntry(vd, ni);
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = ENOTDIR;
|
||||
@ -202,8 +205,7 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
}
|
||||
|
||||
// Close the old current directory (if any)
|
||||
if (vd->cwd_ni)
|
||||
ntfsCloseEntry(vd, vd->cwd_ni);
|
||||
if (vd->cwd_ni) ntfsCloseEntry(vd, vd->cwd_ni);
|
||||
|
||||
// Set the new current directory
|
||||
vd->cwd_ni = ni;
|
||||
@ -223,7 +225,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(oldName);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -232,7 +235,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
ntfsLock(vd);
|
||||
|
||||
// You cannot rename between devices
|
||||
if(vd != ntfsGetVolume(newName)) {
|
||||
if (vd != ntfsGetVolume(newName))
|
||||
{
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
@ -240,7 +244,8 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
|
||||
// Check that there is no existing entry with the new name
|
||||
ni = ntfsOpenEntry(vd, newName);
|
||||
if (ni) {
|
||||
if (ni)
|
||||
{
|
||||
ntfsCloseEntry(vd, ni);
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = EEXIST;
|
||||
@ -248,14 +253,17 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
}
|
||||
|
||||
// Link the old entry with the new one
|
||||
if (ntfsLink(vd, oldName, newName)) {
|
||||
if (ntfsLink(vd, oldName, newName))
|
||||
{
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unlink the old entry
|
||||
if (ntfsUnlink(vd, oldName)) {
|
||||
if (ntfsUnlink(vd, newName)) {
|
||||
if (ntfsUnlink(vd, oldName))
|
||||
{
|
||||
if (ntfsUnlink(vd, newName))
|
||||
{
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
@ -278,7 +286,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -288,7 +297,8 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
|
||||
// Create the directory
|
||||
ni = ntfsCreate(vd, path, S_IFDIR, NULL);
|
||||
if (!ni) {
|
||||
if (!ni)
|
||||
{
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -313,14 +323,14 @@ int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
if (!vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!buf)
|
||||
return 0;
|
||||
if (!buf) return 0;
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
@ -351,8 +361,7 @@ int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
|
||||
if (delta_bits >= 0)
|
||||
size <<= delta_bits;
|
||||
else
|
||||
size >>= -delta_bits;
|
||||
else size >>= -delta_bits;
|
||||
|
||||
// Number of inodes at this point in time
|
||||
buf->f_files = (vd->vol->mftbmp_na->allocated_size << 3) + size;
|
||||
@ -387,41 +396,45 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
char *entry_name = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd) {
|
||||
if (!dir || !dir->vd)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ignore DOS file names
|
||||
if (name_type == FILE_NAME_DOS) {
|
||||
if (name_type == FILE_NAME_DOS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
|
||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles) {
|
||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles)
|
||||
{
|
||||
|
||||
// Convert the entry name to our current local
|
||||
if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0) {
|
||||
if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(dir->first && dir->first->mref == FILE_root &&
|
||||
MREF(mref) == FILE_root && strcmp(entry_name, "..") == 0)
|
||||
if (dir->first && dir->first->mref == FILE_root && MREF(mref) == FILE_root && strcmp(entry_name, "..") == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If this is not the parent or self directory reference
|
||||
if ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0)) {
|
||||
if ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0))
|
||||
{
|
||||
|
||||
// Open the entry
|
||||
ntfs_inode *ni = ntfs_pathname_to_inode(dir->vd->vol, dir->ni, entry_name);
|
||||
if (!ni)
|
||||
return -1;
|
||||
if (!ni) return -1;
|
||||
|
||||
// Double check that this entry can be emuerated (as described by the volume descriptor)
|
||||
if (((ni->flags & FILE_ATTR_HIDDEN) && !dir->vd->showHiddenFiles) ||
|
||||
((ni->flags & FILE_ATTR_SYSTEM) && !dir->vd->showSystemFiles)) {
|
||||
if (((ni->flags & FILE_ATTR_HIDDEN) && !dir->vd->showHiddenFiles) || ((ni->flags & FILE_ATTR_SYSTEM)
|
||||
&& !dir->vd->showSystemFiles))
|
||||
{
|
||||
ntfs_inode_close(ni);
|
||||
return 0;
|
||||
}
|
||||
@ -433,8 +446,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
|
||||
// Allocate a new directory entry
|
||||
entry = (ntfs_dir_entry *) ntfs_alloc(sizeof(ntfs_dir_entry));
|
||||
if (!entry)
|
||||
return -1;
|
||||
if (!entry) return -1;
|
||||
|
||||
// Setup the entry
|
||||
entry->name = entry_name;
|
||||
@ -442,11 +454,15 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
entry->mref = MREF(mref);
|
||||
|
||||
// Link the entry to the directory
|
||||
if (!dir->first) {
|
||||
if (!dir->first)
|
||||
{
|
||||
dir->first = entry;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_dir_entry *last = dir->first;
|
||||
while (last->next) last = last->next;
|
||||
while (last->next)
|
||||
last = last->next;
|
||||
last->next = entry;
|
||||
}
|
||||
|
||||
@ -464,7 +480,8 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
dir->vd = ntfsGetVolume(path);
|
||||
if (!dir->vd) {
|
||||
if (!dir->vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
@ -474,14 +491,16 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
// Find the directory
|
||||
dir->ni = ntfsOpenEntry(dir->vd, path);
|
||||
if (!dir->ni) {
|
||||
if (!dir->ni)
|
||||
{
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY))
|
||||
{
|
||||
ntfsCloseEntry(dir->vd, dir->ni);
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = ENOTDIR;
|
||||
@ -490,7 +509,8 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
// Read the directory
|
||||
dir->first = dir->current = NULL;
|
||||
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
|
||||
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t) ntfs_readdir_filler))
|
||||
{
|
||||
ntfsCloseDir(dir);
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = errno;
|
||||
@ -504,10 +524,13 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Insert the directory into the double-linked FILO list of open directories
|
||||
if (dir->vd->firstOpenDir) {
|
||||
if (dir->vd->firstOpenDir)
|
||||
{
|
||||
dir->nextOpenDir = dir->vd->firstOpenDir;
|
||||
dir->vd->firstOpenDir->prevOpenDir = dir;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dir->nextOpenDir = NULL;
|
||||
}
|
||||
dir->prevOpenDir = NULL;
|
||||
@ -528,7 +551,8 @@ int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
if (!dir || !dir->vd || !dir->ni)
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -556,7 +580,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
if (!dir || !dir->vd || !dir->ni)
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -565,7 +590,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
// Check that there is a entry waiting to be fetched
|
||||
if (!dir->current) {
|
||||
if (!dir->current)
|
||||
{
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
@ -583,7 +609,8 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
else
|
||||
{
|
||||
ni = ntfsOpenEntry(dir->vd, dir->current->name);
|
||||
if (ni) {
|
||||
if (ni)
|
||||
{
|
||||
ntfsStat(dir->vd, ni, filestat);
|
||||
ntfsCloseEntry(dir->vd, ni);
|
||||
}
|
||||
@ -609,7 +636,8 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd) {
|
||||
if (!dir || !dir->vd)
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -622,12 +650,10 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
|
||||
// Remove the directory from the double-linked FILO list of open directories
|
||||
dir->vd->openDirCount--;
|
||||
if (dir->nextOpenDir)
|
||||
dir->nextOpenDir->prevOpenDir = dir->prevOpenDir;
|
||||
if (dir->nextOpenDir) dir->nextOpenDir->prevOpenDir = dir->prevOpenDir;
|
||||
if (dir->prevOpenDir)
|
||||
dir->prevOpenDir->nextOpenDir = dir->nextOpenDir;
|
||||
else
|
||||
dir->vd->firstOpenDir = dir->nextOpenDir;
|
||||
else dir->vd->firstOpenDir = dir->nextOpenDir;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(dir->vd);
|
||||
|
@ -28,7 +28,8 @@
|
||||
/**
|
||||
* ntfs_dir_entry - Directory entry
|
||||
*/
|
||||
typedef struct _ntfs_dir_entry {
|
||||
typedef struct _ntfs_dir_entry
|
||||
{
|
||||
char *name;
|
||||
u64 mref;
|
||||
struct _ntfs_dir_entry *next;
|
||||
@ -37,7 +38,8 @@ typedef struct _ntfs_dir_entry {
|
||||
/**
|
||||
* ntfs_dir_state - Directory state
|
||||
*/
|
||||
typedef struct _ntfs_dir_state {
|
||||
typedef struct _ntfs_dir_state
|
||||
{
|
||||
ntfs_vd *vd; /* Volume this directory belongs to */
|
||||
ntfs_inode *ni; /* Directory descriptor */
|
||||
ntfs_dir_entry *first; /* The first entry in the directory */
|
||||
|
@ -48,19 +48,16 @@
|
||||
void ntfsCloseFile(ntfs_file_state *file)
|
||||
{
|
||||
// Sanity check
|
||||
if (!file || !file->vd)
|
||||
return;
|
||||
if (!file || !file->vd) return;
|
||||
|
||||
// Special case fix ups for compressed and/or encrypted files
|
||||
if (file->compressed)
|
||||
ntfs_attr_pclose(file->data_na);
|
||||
if (file->compressed) ntfs_attr_pclose(file->data_na);
|
||||
#ifdef HAVE_SETXATTR
|
||||
if (file->encrypted)
|
||||
ntfs_efs_fixup_attribute(NULL, file->data_na);
|
||||
#endif
|
||||
// Close the file data attribute (if open)
|
||||
if (file->data_na)
|
||||
ntfs_attr_close(file->data_na);
|
||||
if (file->data_na) ntfs_attr_close(file->data_na);
|
||||
|
||||
// Sync the file (and its attributes) to disc
|
||||
if (file->write)
|
||||
@ -69,12 +66,10 @@ void ntfsCloseFile (ntfs_file_state *file)
|
||||
ntfsSync(file->vd, file->ni);
|
||||
}
|
||||
|
||||
if (file->read)
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||
if (file->read) ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Close the file (if open)
|
||||
if (file->ni)
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
if (file->ni) ntfsCloseEntry(file->vd, file->ni);
|
||||
|
||||
// Reset the file state
|
||||
file->ni = NULL;
|
||||
@ -97,7 +92,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
file->vd = ntfsGetVolume(path);
|
||||
if (!file->vd) {
|
||||
if (!file->vd)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
@ -107,19 +103,26 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
|
||||
// Determine which mode the file is opened for
|
||||
file->flags = flags;
|
||||
if ((flags & 0x03) == O_RDONLY) {
|
||||
if ((flags & 0x03) == O_RDONLY)
|
||||
{
|
||||
file->read = true;
|
||||
file->write = false;
|
||||
file->append = false;
|
||||
} else if ((flags & 0x03) == O_WRONLY) {
|
||||
}
|
||||
else if ((flags & 0x03) == O_WRONLY)
|
||||
{
|
||||
file->read = false;
|
||||
file->write = true;
|
||||
file->append = (flags & O_APPEND);
|
||||
} else if ((flags & 0x03) == O_RDWR) {
|
||||
}
|
||||
else if ((flags & 0x03) == O_RDWR)
|
||||
{
|
||||
file->read = true;
|
||||
file->write = true;
|
||||
file->append = (flags & O_APPEND);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
r->_errno = EACCES;
|
||||
ntfsUnlock(file->vd);
|
||||
return -1;
|
||||
@ -127,7 +130,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
|
||||
// Try and find the file and (if found) ensure that it is not a directory
|
||||
file->ni = ntfsOpenEntry(file->vd, path);
|
||||
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))
|
||||
{
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EISDIR;
|
||||
@ -135,11 +139,13 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Are we creating this file?
|
||||
if ((flags & O_CREAT) && !file->ni) {
|
||||
if ((flags & O_CREAT) && !file->ni)
|
||||
{
|
||||
|
||||
// Create the file
|
||||
file->ni = ntfsCreate(file->vd, path, S_IFREG, NULL);
|
||||
if (!file->ni) {
|
||||
if (!file->ni)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
return -1;
|
||||
}
|
||||
@ -147,7 +153,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Sanity check, the file should be open by now
|
||||
if (!file->ni) {
|
||||
if (!file->ni)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
@ -155,7 +162,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
|
||||
// Open the files data attribute
|
||||
file->data_na = ntfs_attr_open(file->ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if(!file->data_na) {
|
||||
if (!file->data_na)
|
||||
{
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
return -1;
|
||||
@ -166,7 +174,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
file->encrypted = NAttrEncrypted(file->data_na) || (file->ni->flags & FILE_ATTR_ENCRYPTED);
|
||||
|
||||
// We cannot read/write encrypted files
|
||||
if (file->encrypted) {
|
||||
if (file->encrypted)
|
||||
{
|
||||
ntfs_attr_close(file->data_na);
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
@ -175,7 +184,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Make sure we aren't trying to write to a read-only file
|
||||
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
|
||||
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write)
|
||||
{
|
||||
ntfs_attr_close(file->data_na);
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
@ -184,8 +194,10 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
}
|
||||
|
||||
// Truncate the file if requested
|
||||
if ((flags & O_TRUNC) && file->write) {
|
||||
if (ntfs_attr_truncate(file->data_na, 0)) {
|
||||
if ((flags & O_TRUNC) && file->write)
|
||||
{
|
||||
if (ntfs_attr_truncate(file->data_na, 0))
|
||||
{
|
||||
ntfs_attr_close(file->data_na);
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
@ -204,10 +216,13 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Insert the file into the double-linked FILO list of open files
|
||||
if (file->vd->firstOpenFile) {
|
||||
if (file->vd->firstOpenFile)
|
||||
{
|
||||
file->nextOpenFile = file->vd->firstOpenFile;
|
||||
file->vd->firstOpenFile->prevOpenFile = file;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
file->nextOpenFile = NULL;
|
||||
}
|
||||
file->prevOpenFile = NULL;
|
||||
@ -227,7 +242,8 @@ int ntfs_close_r (struct _reent *r, int fd)
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd) {
|
||||
if (!file || !file->vd)
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
@ -240,12 +256,10 @@ int ntfs_close_r (struct _reent *r, int fd)
|
||||
|
||||
// Remove the file from the double-linked FILO list of open files
|
||||
file->vd->openFileCount--;
|
||||
if (file->nextOpenFile)
|
||||
file->nextOpenFile->prevOpenFile = file->prevOpenFile;
|
||||
if (file->nextOpenFile) file->nextOpenFile->prevOpenFile = file->prevOpenFile;
|
||||
if (file->prevOpenFile)
|
||||
file->prevOpenFile->nextOpenFile = file->nextOpenFile;
|
||||
else
|
||||
file->vd->firstOpenFile = file->nextOpenFile;
|
||||
else file->vd->firstOpenFile = file->nextOpenFile;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(file->vd);
|
||||
@ -262,13 +276,15 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||
off_t old_pos = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if (!file || !file->vd || !file->ni || !file->data_na)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases where we don't actually have to do anything
|
||||
if (!ptr || len <= 0) {
|
||||
if (!ptr || len <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -276,22 +292,26 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if (!file->write) {
|
||||
if (!file->write)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we are in append mode, backup the current position and move to the end of the file
|
||||
if (file->append) {
|
||||
if (file->append)
|
||||
{
|
||||
old_pos = file->pos;
|
||||
file->pos = file->len;
|
||||
}
|
||||
|
||||
// Write to the files data atrribute
|
||||
while (len) {
|
||||
while (len)
|
||||
{
|
||||
ssize_t ret = ntfs_attr_pwrite(file->data_na, file->pos, len, ptr);
|
||||
if (ret <= 0) {
|
||||
if (ret <= 0)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -302,13 +322,13 @@ ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||
}
|
||||
|
||||
// If we are in append mode, restore the current position to were it was prior to this write
|
||||
if (file->append) {
|
||||
if (file->append)
|
||||
{
|
||||
file->pos = old_pos;
|
||||
}
|
||||
|
||||
// Mark the file for archiving (if we actually wrote something)
|
||||
if (written)
|
||||
file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||
if (written) file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||
|
||||
// Update the files data length
|
||||
file->len = file->data_na->data_size;
|
||||
@ -327,13 +347,15 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||
ssize_t read = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if (!file || !file->vd || !file->ni || !file->data_na)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases where we don't actually have to do anything
|
||||
if (!ptr || len <= 0) {
|
||||
if (!ptr || len <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -341,14 +363,16 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Check that we are allowed to read from this file
|
||||
if (!file->read) {
|
||||
if (!file->read)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Don't read past the end of file
|
||||
if (file->pos + len > file->len) {
|
||||
if (file->pos + len > file->len)
|
||||
{
|
||||
r->_errno = EOVERFLOW;
|
||||
len = file->len - file->pos;
|
||||
ntfs_log_trace("EOVERFLOW");
|
||||
@ -357,9 +381,11 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||
ntfs_log_trace("file->pos:%d, len:%d, file->len:%d \n", (u32)file->pos, (u32)len, (u32)file->len);
|
||||
|
||||
// Read from the files data attribute
|
||||
while (len) {
|
||||
while (len)
|
||||
{
|
||||
ssize_t ret = ntfs_attr_pread(file->data_na, file->pos, len, ptr);
|
||||
if (ret <= 0 || ret > len) {
|
||||
if (ret <= 0 || ret > len)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -386,7 +412,8 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||
off_t position = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if (!file || !file->vd || !file->ni || !file->data_na)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -395,10 +422,17 @@ off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Set the files current position
|
||||
switch(dir) {
|
||||
case SEEK_SET: position = file->pos = MIN(MAX(pos, 0), file->len); break;
|
||||
case SEEK_CUR: position = file->pos = MIN(MAX(file->pos + pos, 0), file->len); break;
|
||||
case SEEK_END: position = file->pos = MIN(MAX(file->len + pos, 0), file->len); break;
|
||||
switch (dir)
|
||||
{
|
||||
case SEEK_SET:
|
||||
position = file->pos = MIN(MAX(pos, 0), file->len);
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
position = file->pos = MIN(MAX(file->pos + pos, 0), file->len);
|
||||
break;
|
||||
case SEEK_END:
|
||||
position = file->pos = MIN(MAX(file->len + pos, 0), file->len);
|
||||
break;
|
||||
}
|
||||
|
||||
// Unlock
|
||||
@ -414,19 +448,18 @@ int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if (!file || !file->vd || !file->ni || !file->data_na)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!st)
|
||||
return 0;
|
||||
if (!st) return 0;
|
||||
|
||||
// Get the file stats
|
||||
ret = ntfsStat(file->vd, file->ni, st);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
if (ret) r->_errno = errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -438,7 +471,8 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if (!file || !file->vd || !file->ni || !file->data_na)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -447,31 +481,36 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if (!file->write) {
|
||||
if (!file->write)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// For compressed files, only deleting and expanding contents are implemented
|
||||
if (file->compressed &&
|
||||
len > 0 &&
|
||||
len < file->data_na->initialized_size) {
|
||||
if (file->compressed && len > 0 && len < file->data_na->initialized_size)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Resize the files data attribute, either by expanding or truncating
|
||||
if (file->compressed && len > file->data_na->initialized_size) {
|
||||
if (file->compressed && len > file->data_na->initialized_size)
|
||||
{
|
||||
char zero = 0;
|
||||
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
|
||||
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (ntfs_attr_truncate(file->data_na, len)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ntfs_attr_truncate(file->data_na, len))
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
@ -479,12 +518,10 @@ int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
}
|
||||
|
||||
// Mark the file for archiving (if we actually changed something)
|
||||
if (file->len != file->data_na->data_size)
|
||||
file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||
if (file->len != file->data_na->data_size) file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||
|
||||
// Update file times (if we actually changed something)
|
||||
if (file->len != file->data_na->data_size)
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_AMCTIME);
|
||||
if (file->len != file->data_na->data_size) ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_AMCTIME);
|
||||
|
||||
// Update the files data length
|
||||
file->len = file->data_na->data_size;
|
||||
@ -506,7 +543,8 @@ int ntfs_fsync_r (struct _reent *r, int fd)
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
if (!file || !file->vd || !file->ni || !file->data_na)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -516,8 +554,7 @@ int ntfs_fsync_r (struct _reent *r, int fd)
|
||||
|
||||
// Sync the file (and its attributes) to disc
|
||||
ret = ntfsSync(file->vd, file->ni);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
if (ret) r->_errno = errno;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(file->vd);
|
||||
|
@ -32,7 +32,8 @@
|
||||
/**
|
||||
* ntfs_file_state - File state
|
||||
*/
|
||||
typedef struct _ntfs_file_state {
|
||||
typedef struct _ntfs_file_state
|
||||
{
|
||||
ntfs_vd *vd; /* Volume this file belongs to */
|
||||
ntfs_inode *ni; /* File descriptor */
|
||||
ntfs_attr *data_na; /* File data descriptor */
|
||||
|
@ -363,11 +363,10 @@ ssize_t ntfs_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
|
||||
#endif
|
||||
|
||||
s64 ntfs_attr_getfragments( ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
||||
_ntfs_frag_append_t append_fragment, void *callback_data );
|
||||
s64 ntfs_attr_getfragments(ntfs_attr *na, const s64 pos, s64 count, u64 offset, _ntfs_frag_append_t append_fragment,
|
||||
void *callback_data);
|
||||
|
||||
int _NTFS_get_fragments ( const char *path,
|
||||
_ntfs_frag_append_t append_fragment, void *callback_data )
|
||||
int _NTFS_get_fragments(const char *path, _ntfs_frag_append_t append_fragment, void *callback_data)
|
||||
{
|
||||
struct _reent r;
|
||||
ntfs_file_state file_st, *file = &file_st;
|
||||
@ -379,10 +378,6 @@ int _NTFS_get_fragments ( const char *path,
|
||||
int fd = ntfs_open_r(&r, file, path, O_RDONLY, 0);
|
||||
if (fd != (int) file) return -12;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!file || !file->vd || !file->ni || !file->data_na)
|
||||
{
|
||||
@ -421,8 +416,7 @@ int _NTFS_get_fragments ( const char *path,
|
||||
// Read from the files data attribute
|
||||
while (len)
|
||||
{
|
||||
s64 ret = ntfs_attr_getfragments( file->data_na, file->pos,
|
||||
len, offset, append_fragment, callback_data );
|
||||
s64 ret = ntfs_attr_getfragments(file->data_na, file->pos, len, offset, append_fragment, callback_data);
|
||||
if (ret <= 0 || ret > len)
|
||||
{
|
||||
ntfsUnlock(file->vd);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user